{"components":{"headers":{"XRateLimitLimit":{"description":"Requests allowed per minute for this key.","schema":{"type":"integer"}},"XRateLimitRemaining":{"description":"Requests left in the current minute.","schema":{"type":"integer"}},"XRateLimitReset":{"description":"When the current minute ends, in seconds since the epoch.","schema":{"type":"integer"}}},"responses":{"BadRequest":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The request is not valid (`invalid_input`)."},"Unauthorized":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The API key is missing, malformed, unknown, revoked or expired (`invalid_api_key`)."},"InsufficientLuvs":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsufficientLuvs"}}},"description":"The balance does not cover the shots."},"Forbidden":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The key lacks the scope (`insufficient_scope`), the account is banned (`account_banned`), or the order is above the account's content level (`adult-content-level-required`)."},"NotFound":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"No such object for this member."},"Conflict":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The request conflicts with the current state (a limit, a persona that is not ready, a draft that is not finished)."},"TooLarge":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The request body is too large."},"Unprocessable":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The words were refused (`unsafe_prompt`), or the Idempotency-Key was used for another request."},"RateLimited":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"Too many requests (`rate_limited`), or the daily ceiling of shots (`daily_limit`).","headers":{"Retry-After":{"schema":{"type":"integer"}}}},"Unavailable":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"description":"The engine or the Luv economy is unavailable right now, or the API could not check the key in time (`service_unavailable`, `engine_unavailable`, `economy_unavailable`)."}},"schemas":{"AspectRatio":{"enum":["9:16","3:4","1:1","16:9"],"type":"string"},"Error":{"additionalProperties":false,"properties":{"code":{"description":"A stable, machine-readable reason.","type":"string"},"error":{"description":"A plain-language message.","type":"string"},"field":{"type":"string"},"issues":{"items":{"additionalProperties":false,"properties":{"message":{"type":"string"},"path":{"type":"string"}},"required":["message","path"],"type":"object"},"type":"array"},"limit":{"type":"integer"}},"required":["code","error"],"type":"object"},"FeedPage":{"additionalProperties":false,"properties":{"nextCursor":{"type":["string","null"]},"shots":{"items":{"$ref":"#/components/schemas/FeedShot"},"type":"array"}},"required":["nextCursor","shots"],"type":"object"},"FeedShot":{"additionalProperties":false,"properties":{"author":{"additionalProperties":false,"properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"],"type":"object"},"caption":{"type":["string","null"]},"height":{"type":"integer"},"id":{"type":"string"},"imageUrl":{"type":"string"},"level":{"$ref":"#/components/schemas/Level"},"likeCount":{"type":"integer"},"likedByMe":{"type":"boolean"},"lookName":{"type":["string","null"]},"persona":{"additionalProperties":false,"properties":{"avatarUrl":{"type":["string","null"]},"id":{"type":"string"},"name":{"type":"string"}},"required":["avatarUrl","id","name"],"type":"object"},"publishedAt":{"format":"date-time","type":"string"},"remixCount":{"type":"integer"},"sceneTitle":{"type":["string","null"]},"width":{"type":"integer"}},"required":["author","caption","height","id","imageUrl","level","likeCount","likedByMe","lookName","persona","publishedAt","remixCount","sceneTitle","width"],"type":"object"},"InsufficientLuvs":{"additionalProperties":false,"properties":{"action":{"type":"string"},"balance":{"type":"number"},"code":{"const":"INSUFFICIENT_LUVS","type":"string"},"error":{"type":"string"},"errorCode":{"const":"insufficient-credits","type":"string"},"requiredLuvs":{"type":"number"}},"required":["action","balance","code","error","errorCode","requiredLuvs"],"type":"object"},"Level":{"description":"1 Romance, 2 Spicy, 3 Explicit.","enum":[1,2,3],"type":"integer"},"Look":{"additionalProperties":false,"properties":{"coverUrl":{"type":["string","null"]},"createdAt":{"format":"date-time","type":"string"},"id":{"type":"string"},"level":{"$ref":"#/components/schemas/Level"},"name":{"type":"string"},"outfit":{"type":"string"},"personaId":{"description":"Null: usable on any persona.","type":["string","null"]}},"required":["coverUrl","createdAt","id","level","name","outfit","personaId"],"type":"object"},"LookList":{"additionalProperties":false,"properties":{"looks":{"items":{"$ref":"#/components/schemas/Look"},"type":"array"}},"required":["looks"],"type":"object"},"LookResult":{"additionalProperties":false,"properties":{"look":{"$ref":"#/components/schemas/Look"}},"required":["look"],"type":"object"},"Me":{"additionalProperties":false,"properties":{"engine":{"additionalProperties":false,"properties":{"available":{"type":"boolean"},"paused":{"type":"boolean"},"reason":{"type":["string","null"]}},"required":["available","paused","reason"],"type":"object"},"level":{"$ref":"#/components/schemas/Level"},"limits":{"additionalProperties":false,"properties":{"inProgress":{"type":"integer"},"perDay":{"type":"integer"},"perOrder":{"items":{"type":"integer"},"type":"array"},"personas":{"type":"integer"}},"required":["inProgress","perDay","perOrder","personas"],"type":"object"},"luvs":{"additionalProperties":false,"properties":{"balance":{"description":"Null where nothing is charged.","type":["number","null"]}},"required":["balance"],"type":"object"},"member":{"additionalProperties":false,"properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"],"type":"object"},"prices":{"additionalProperties":false,"properties":{"photo":{"type":"number"}},"required":["photo"],"type":"object"},"usage":{"additionalProperties":false,"properties":{"inProgress":{"type":"integer"},"orderedToday":{"type":"integer"},"personas":{"type":"integer"}},"required":["inProgress","orderedToday","personas"],"type":"object"}},"required":["engine","level","limits","luvs","member","prices","usage"],"type":"object"},"Ok":{"additionalProperties":false,"properties":{"ok":{"const":true,"type":"boolean"}},"required":["ok"],"type":"object"},"OpenApiDocument":{"type":"object"},"Persona":{"additionalProperties":false,"properties":{"age":{"type":["integer","null"]},"avatarUrl":{"type":["string","null"]},"createdAt":{"format":"date-time","type":"string"},"description":{"type":["string","null"]},"id":{"type":"string"},"lookCount":{"type":"integer"},"name":{"type":"string"},"personality":{"type":["string","null"]},"ready":{"type":"boolean"},"shotCount":{"type":"integer"},"tagline":{"type":["string","null"]}},"required":["age","avatarUrl","createdAt","description","id","lookCount","name","personality","ready","shotCount","tagline"],"type":"object"},"PersonaDraft":{"additionalProperties":false,"properties":{"candidates":{"items":{"additionalProperties":false,"properties":{"id":{"type":"string"},"imageUrl":{"type":"string"}},"required":["id","imageUrl"],"type":"object"},"type":"array"},"error":{"type":["string","null"]},"id":{"type":"string"},"state":{"enum":["drawing","ready","failed"],"type":"string"}},"required":["candidates","error","id","state"],"type":"object"},"PersonaDraftResult":{"additionalProperties":false,"properties":{"draft":{"$ref":"#/components/schemas/PersonaDraft"}},"required":["draft"],"type":"object"},"PersonaList":{"additionalProperties":false,"properties":{"canCreate":{"type":"boolean"},"limit":{"type":"integer"},"personas":{"items":{"$ref":"#/components/schemas/Persona"},"type":"array"}},"required":["canCreate","limit","personas"],"type":"object"},"PersonaResult":{"additionalProperties":false,"properties":{"persona":{"$ref":"#/components/schemas/Persona"}},"required":["persona"],"type":"object"},"PickShelves":{"additionalProperties":false,"properties":{"shelves":{"items":{"additionalProperties":false,"properties":{"id":{"type":"string"},"shots":{"items":{"$ref":"#/components/schemas/FeedShot"},"type":"array"},"title":{"type":"string"}},"required":["id","shots","title"],"type":"object"},"type":"array"}},"required":["shelves"],"type":"object"},"Recipe":{"additionalProperties":false,"properties":{"aspectRatio":{"$ref":"#/components/schemas/AspectRatio"},"level":{"$ref":"#/components/schemas/Level"},"lookId":{"type":["string","null"]},"lookName":{"type":["string","null"]},"outfit":{"type":["string","null"]},"prompt":{"type":["string","null"]},"remixOf":{"type":["string","null"]},"sceneId":{"type":["string","null"]},"sceneTitle":{"type":["string","null"]},"seed":{"type":["number","null"]}},"required":["aspectRatio","level","lookId","lookName","outfit","prompt","remixOf","sceneId","sceneTitle","seed"],"type":"object"},"Scene":{"additionalProperties":false,"properties":{"aspectRatio":{"$ref":"#/components/schemas/AspectRatio"},"id":{"type":"string"},"level":{"$ref":"#/components/schemas/Level"},"summary":{"type":"string"},"tags":{"items":{"type":"string"},"type":"array"},"title":{"type":"string"}},"required":["aspectRatio","id","level","summary","tags","title"],"type":"object"},"SceneList":{"additionalProperties":false,"properties":{"scenes":{"items":{"$ref":"#/components/schemas/Scene"},"type":"array"}},"required":["scenes"],"type":"object"},"Shot":{"additionalProperties":false,"properties":{"caption":{"type":["string","null"]},"createdAt":{"format":"date-time","type":"string"},"deliveredAt":{"format":"date-time","type":["string","null"]},"failure":{"description":"Why a failed or refused shot did not come out; null for every other status.","enum":["face_drift","engine_failed","expired","insufficient_luvs","unsafe_prompt",null],"type":["string","null"]},"height":{"type":["integer","null"]},"id":{"type":"string"},"imageUrl":{"description":"The public, unlisted URL of the picture; set once the shot is `done`.","type":["string","null"]},"level":{"$ref":"#/components/schemas/Level"},"likeCount":{"type":"integer"},"likedByMe":{"type":"boolean"},"luvs":{"description":"Charged; 0 until delivered.","type":"integer"},"personaId":{"type":"string"},"personaName":{"type":"string"},"publishable":{"description":"Whether the shot is of one of the member's own personas, which is the only kind the app sends for review. False for a photo of a house character asked for in chat (the member's private picture); `POST /studio/shots/:id/publish` refuses it with `409 conflict`. Publishing is not part of this API.","type":"boolean"},"recipe":{"$ref":"#/components/schemas/Recipe"},"rejectReason":{"type":["string","null"]},"remixCount":{"type":"integer"},"status":{"enum":["queued","running","done","failed","refused","cancelled"],"type":"string"},"visibility":{"enum":["private","pending","public","rejected"],"type":"string"},"width":{"type":["integer","null"]}},"required":["caption","createdAt","deliveredAt","failure","height","id","imageUrl","level","likeCount","likedByMe","luvs","personaId","personaName","publishable","recipe","rejectReason","remixCount","status","visibility","width"],"type":"object"},"ShotList":{"additionalProperties":false,"properties":{"shots":{"items":{"$ref":"#/components/schemas/Shot"},"type":"array"}},"required":["shots"],"type":"object"},"ShotPage":{"additionalProperties":false,"properties":{"nextCursor":{"type":["string","null"]},"shots":{"items":{"$ref":"#/components/schemas/Shot"},"type":"array"}},"required":["nextCursor","shots"],"type":"object"},"ShotResult":{"additionalProperties":false,"properties":{"shot":{"$ref":"#/components/schemas/Shot"}},"required":["shot"],"type":"object"},"Webhook":{"additionalProperties":false,"properties":{"createdAt":{"format":"date-time","type":"string"},"disabledAt":{"format":"date-time","type":["string","null"]},"disabledReason":{"enum":["failures",null],"type":["string","null"]},"events":{"items":{"enum":["shot.delivered","shot.failed","persona.draft.ready","persona.draft.failed","persona.created"],"type":"string"},"type":"array"},"id":{"type":"string"},"lastDeliveryAt":{"format":"date-time","type":["string","null"]},"lastStatus":{"type":["integer","null"]},"url":{"type":"string"}},"required":["createdAt","disabledAt","disabledReason","events","id","lastDeliveryAt","lastStatus","url"],"type":"object"},"WebhookCreated":{"additionalProperties":false,"properties":{"secret":{"description":"Signs every delivery (see Webhooks). Shown once: only this response has it.","type":"string"},"webhook":{"$ref":"#/components/schemas/Webhook"}},"required":["secret","webhook"],"type":"object"},"WebhookList":{"additionalProperties":false,"properties":{"webhooks":{"items":{"$ref":"#/components/schemas/Webhook"},"type":"array"}},"required":["webhooks"],"type":"object"},"Event_persona_created":{"additionalProperties":false,"properties":{"createdAt":{"format":"date-time","type":"string"},"data":{"additionalProperties":false,"properties":{"persona":{"$ref":"#/components/schemas/Persona"}},"required":["persona"],"type":"object"},"id":{"description":"The event id; also the `Luv-Event-Id` header.","type":"string"},"type":{"const":"persona.created","type":"string"}},"required":["createdAt","data","id","type"],"type":"object"},"Event_persona_draft_failed":{"additionalProperties":false,"properties":{"createdAt":{"format":"date-time","type":"string"},"data":{"additionalProperties":false,"properties":{"draft":{"$ref":"#/components/schemas/PersonaDraft"}},"required":["draft"],"type":"object"},"id":{"description":"The event id; also the `Luv-Event-Id` header.","type":"string"},"type":{"const":"persona.draft.failed","type":"string"}},"required":["createdAt","data","id","type"],"type":"object"},"Event_persona_draft_ready":{"additionalProperties":false,"properties":{"createdAt":{"format":"date-time","type":"string"},"data":{"additionalProperties":false,"properties":{"draft":{"$ref":"#/components/schemas/PersonaDraft"}},"required":["draft"],"type":"object"},"id":{"description":"The event id; also the `Luv-Event-Id` header.","type":"string"},"type":{"const":"persona.draft.ready","type":"string"}},"required":["createdAt","data","id","type"],"type":"object"},"Event_shot_delivered":{"additionalProperties":false,"properties":{"createdAt":{"format":"date-time","type":"string"},"data":{"additionalProperties":false,"properties":{"shot":{"$ref":"#/components/schemas/Shot"}},"required":["shot"],"type":"object"},"id":{"description":"The event id; also the `Luv-Event-Id` header.","type":"string"},"type":{"const":"shot.delivered","type":"string"}},"required":["createdAt","data","id","type"],"type":"object"},"Event_shot_failed":{"additionalProperties":false,"properties":{"createdAt":{"format":"date-time","type":"string"},"data":{"additionalProperties":false,"properties":{"shot":{"$ref":"#/components/schemas/Shot"}},"required":["shot"],"type":"object"},"id":{"description":"The event id; also the `Luv-Event-Id` header.","type":"string"},"type":{"const":"shot.failed","type":"string"}},"required":["createdAt","data","id","type"],"type":"object"},"CreatePersonaDraftRequest":{"type":"object","properties":{"age":{"type":"integer","minimum":18,"maximum":45},"description":{"type":"string","minLength":10,"maxLength":600},"name":{"maxLength":40,"minLength":1,"type":"string"}},"required":["age","description","name"],"additionalProperties":false},"ChoosePersonaFaceRequest":{"type":"object","properties":{"candidateId":{"type":"string","minLength":1,"maxLength":120},"personality":{"anyOf":[{"type":"string","maxLength":600},{"type":"null"}]}},"required":["candidateId"],"additionalProperties":false},"UpdatePersonaRequest":{"type":"object","properties":{"name":{"maxLength":40,"minLength":1,"type":"string"},"personality":{"anyOf":[{"type":"string","maxLength":600},{"type":"null"}]},"tagline":{"anyOf":[{"type":"string","maxLength":80},{"type":"null"}]}},"additionalProperties":false},"CreateLookRequest":{"type":"object","properties":{"coverShotId":{"anyOf":[{"type":"string","minLength":1,"maxLength":120},{"type":"null"}]},"level":{"enum":[1,2,3],"type":"integer"},"name":{"type":"string","minLength":1,"maxLength":60},"outfit":{"type":"string","minLength":1,"maxLength":300},"personaId":{"anyOf":[{"type":"string","minLength":1,"maxLength":120},{"type":"null"}]}},"required":["level","name","outfit"],"additionalProperties":false},"UpdateLookRequest":{"type":"object","properties":{"coverShotId":{"anyOf":[{"type":"string","minLength":1,"maxLength":120},{"type":"null"}]},"level":{"enum":[1,2,3],"type":"integer"},"name":{"type":"string","minLength":1,"maxLength":60},"outfit":{"type":"string","minLength":1,"maxLength":300},"personaId":{"anyOf":[{"type":"string","minLength":1,"maxLength":120},{"type":"null"}]}},"additionalProperties":false},"OrderShotsRequest":{"type":"object","properties":{"aspectRatio":{"description":"The photo's format. Optional: the chosen scene's own format when there is a scene, else 9:16. Ignored by a remix.","anyOf":[{"type":"string","enum":["9:16","3:4","1:1","16:9"]},{"type":"null"}]},"count":{"default":1,"description":"Photos in this order: 1, 2 or 4. Optional, 1 by default.","enum":[1,2,4],"type":"integer"},"level":{"description":"The content level, 1 Romance, 2 Spicy, 3 Explicit. Optional: the lowest level the order needs, which is the highest of the scene's level, the look's level and what the words ask for. Never above the account's level: an order that needs more is refused with 403 adult-content-level-required, whether the level was given or worked out. Ignored by a remix.","anyOf":[{"enum":[1,2,3],"type":"integer"},{"type":"null"}]},"lookId":{"anyOf":[{"type":"string","minLength":1,"maxLength":120},{"type":"null"}]},"prompt":{"anyOf":[{"type":"string","maxLength":600},{"type":"null"}]},"remixOf":{"anyOf":[{"type":"string","minLength":1,"maxLength":120},{"type":"null"}]},"sceneId":{"anyOf":[{"type":"string","minLength":1,"maxLength":120},{"type":"null"}]},"personaId":{"type":"string","minLength":1,"maxLength":120}},"required":["personaId"],"additionalProperties":false},"CreateWebhookRequest":{"type":"object","properties":{"events":{"minItems":1,"type":"array","items":{"type":"string","enum":["shot.delivered","shot.failed","persona.draft.ready","persona.draft.failed","persona.created"]}},"url":{"type":"string","minLength":1,"maxLength":2048}},"required":["events","url"],"additionalProperties":false}},"securitySchemes":{"ApiKey":{"bearerFormat":"luv_live_<id>_<secret>","description":"An API key. The scopes a route needs are listed in its security requirement.","scheme":"bearer","type":"http"}}},"info":{"description":"Luv's API for integrations: the same studio the app uses, for your own software. Create personas, give them looks, order\nshots, read the results, and receive webhooks. Everything a call does is done as the member who owns the key: their\ncontent level, the safety floor, the limits and the Luv prices all apply, and shots are charged to their balance.\n\n**Authentication.** `Authorization: Bearer luv_live_<id>_<secret>`. A member creates keys in their settings; the secret\nis shown once. Each route needs the scope named in its security requirement. A missing, malformed, unknown, revoked or\nexpired key is `401 invalid_api_key`; a key without the scope is `403 insufficient_scope`.\n\n**Limits.** 120 requests per minute per key (`X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`;\n`429 rate_limited` with `Retry-After`).\n\n**Errors** are `{ \"code\": string, \"error\": string }`, with more fields where the studio returns them.\n\n**Idempotency.** `Idempotency-Key` (8 to 100 characters from A-Z a-z 0-9 _ . : -) makes a creating request safe to repeat:\nthe same key returns the first answer. It is required to order shots.\n\n**Webhooks.** Register an HTTPS endpoint and choose events. Every delivery is `POST` JSON with `Luv-Event-Id`,\n`Luv-Event-Type`, `Luv-Timestamp` (seconds since the epoch) and `Luv-Signature: v1=<hex HMAC-SHA256 of\n\"<timestamp>.<raw body>\" keyed with the endpoint secret>`. Answer 2xx within 10 seconds. Failed deliveries are retried\nafter about 1 minute, 5 minutes, 30 minutes, 2 hours and 12 hours; delivery is at least once and may be out of order, so\nuse `Luv-Event-Id` as the idempotency key.","title":"Luv API","version":"1.0.0"},"openapi":"3.1.0","paths":{"/me":{"get":{"operationId":"getMe","parameters":[],"responses":{"200":{"content":{"application/json":{"example":{"engine":{"available":true,"paused":false,"reason":null},"level":2,"limits":{"inProgress":4,"perDay":200,"perOrder":[1,2,4],"personas":12},"luvs":{"balance":120},"member":{"id":"u1","name":"Alex"},"prices":{"photo":5},"usage":{"inProgress":1,"orderedToday":6,"personas":3}},"schema":{"$ref":"#/components/schemas/Me"}}},"description":"Who the key acts for, the limits, the usage and the balance.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/Unavailable"}},"security":[{"ApiKey":[]}],"summary":"The member behind the key","tags":["Me"]}},"/scenes":{"get":{"operationId":"listScenes","parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SceneList"}}},"description":"The scenes at or below the account's content level.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/Unavailable"}},"security":[{"ApiKey":[]}],"summary":"List scenes","tags":["Catalog"]}},"/personas":{"get":{"operationId":"listPersonas","parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PersonaList"}}},"description":"The member's personas, newest first.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/Unavailable"}},"security":[{"ApiKey":["personas:read"]}],"summary":"List personas","tags":["Personas"]}},"/personas/{id}":{"get":{"operationId":"getPersona","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PersonaResult"}}},"description":"The persona.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/Unavailable"}},"security":[{"ApiKey":["personas:read"]}],"summary":"Get a persona","tags":["Personas"]},"patch":{"operationId":"updatePersona","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"tagline":"Always one more chapter"},"schema":{"$ref":"#/components/schemas/UpdatePersonaRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PersonaResult"}}},"description":"The persona.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"413":{"$ref":"#/components/responses/TooLarge"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/Unavailable"}},"security":[{"ApiKey":["personas:write"]}],"summary":"Change a persona","tags":["Personas"]},"delete":{"operationId":"deletePersona","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ok"}}},"description":"The persona, her looks and her shots are gone.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/Unavailable"}},"security":[{"ApiKey":["personas:write"]}],"summary":"Delete a persona","tags":["Personas"]}},"/personas/drafts":{"post":{"operationId":"createPersonaDraft","parameters":[{"description":"Optional. Repeating the request with the same key returns the first answer.","in":"header","name":"Idempotency-Key","required":false,"schema":{"pattern":"^[A-Za-z0-9_.:-]{8,100}$","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"age":27,"description":"Warm brown eyes, freckles, a quiet confidence","name":"Mira"},"schema":{"$ref":"#/components/schemas/CreatePersonaDraftRequest"}}},"required":true},"responses":{"202":{"content":{"application/json":{"example":{"draft":{"candidates":[],"error":null,"id":"2d0b0f64-51a8-4f55-9c1e-7a2d35e0b9c4","state":"drawing"}},"schema":{"$ref":"#/components/schemas/PersonaDraftResult"}}},"description":"The draft; her faces are being drawn.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/TooLarge"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/Unavailable"}},"security":[{"ApiKey":["personas:write"]}],"summary":"Start a persona","tags":["Personas"]}},"/personas/drafts/{id}":{"get":{"operationId":"getPersonaDraft","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PersonaDraftResult"}}},"description":"The draft; poll every 3 seconds while it is `drawing`.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/Unavailable"}},"security":[{"ApiKey":["personas:read"]}],"summary":"Get a persona draft","tags":["Personas"]},"delete":{"operationId":"deletePersonaDraft","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ok"}}},"description":"The draft is gone.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/Unavailable"}},"security":[{"ApiKey":["personas:write"]}],"summary":"Discard a persona draft","tags":["Personas"]}},"/personas/drafts/{id}/choose":{"post":{"operationId":"choosePersonaFace","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"candidateId":"ast_0a1","personality":"Dry humour, curious"},"schema":{"$ref":"#/components/schemas/ChoosePersonaFaceRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PersonaResult"}}},"description":"The persona, made from the chosen face.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/TooLarge"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/Unavailable"}},"security":[{"ApiKey":["personas:write"]}],"summary":"Choose a face","tags":["Personas"]}},"/looks":{"get":{"operationId":"listLooks","parameters":[{"description":"Only this persona's looks, plus those that fit any persona.","in":"query","name":"personaId","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LookList"}}},"description":"The looks.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/Unavailable"}},"security":[{"ApiKey":["looks:read"]}],"summary":"List looks","tags":["Looks"]},"post":{"operationId":"createLook","parameters":[{"description":"Optional. Repeating the request with the same key returns the first answer.","in":"header","name":"Idempotency-Key","required":false,"schema":{"pattern":"^[A-Za-z0-9_.:-]{8,100}$","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"level":1,"name":"Linen summer dress","outfit":"a cream linen dress, gold hoop earrings, loose hair","personaId":"kLq3x9Vt0a2B"},"schema":{"$ref":"#/components/schemas/CreateLookRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LookResult"}}},"description":"The look.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/TooLarge"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/Unavailable"}},"security":[{"ApiKey":["looks:write"]}],"summary":"Create a look","tags":["Looks"]}},"/looks/{id}":{"patch":{"operationId":"updateLook","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateLookRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LookResult"}}},"description":"The look.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"413":{"$ref":"#/components/responses/TooLarge"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/Unavailable"}},"security":[{"ApiKey":["looks:write"]}],"summary":"Change a look","tags":["Looks"]},"delete":{"operationId":"deleteLook","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ok"}}},"description":"The look is gone.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/Unavailable"}},"security":[{"ApiKey":["looks:write"]}],"summary":"Delete a look","tags":["Looks"]}},"/shots":{"post":{"operationId":"orderShots","parameters":[{"description":"Required. Repeating the request with the same key returns the first answer and orders nothing more.","in":"header","name":"Idempotency-Key","required":true,"schema":{"pattern":"^[A-Za-z0-9_.:-]{8,100}$","type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"aspectRatio":"3:4","count":2,"level":1,"personaId":"kLq3x9Vt0a2B","prompt":"reading by the window","sceneId":"golden-hour-rooftop"},"schema":{"$ref":"#/components/schemas/OrderShotsRequest"}}},"required":true},"responses":{"202":{"content":{"application/json":{"example":{"shots":[{"caption":null,"createdAt":"2026-10-12T09:30:00.000Z","deliveredAt":null,"failure":null,"height":null,"id":"6f1d3a34-52f6-4c0e-9f6f-5d0c3b5a6a11","imageUrl":null,"level":1,"likeCount":0,"likedByMe":false,"luvs":0,"personaId":"kLq3x9Vt0a2B","personaName":"Mira","publishable":true,"recipe":{"aspectRatio":"3:4","level":1,"lookId":null,"lookName":null,"outfit":null,"prompt":"reading by the window","remixOf":null,"sceneId":"golden-hour-rooftop","sceneTitle":"Golden hour rooftop","seed":1894522201},"rejectReason":null,"remixCount":0,"status":"queued","visibility":"private","width":null},{"caption":null,"createdAt":"2026-10-12T09:30:00.000Z","deliveredAt":null,"failure":null,"height":null,"id":"0c5d9f3e-1a07-4a8e-8b0e-4f7a2c6d9e22","imageUrl":null,"level":1,"likeCount":0,"likedByMe":false,"luvs":0,"personaId":"kLq3x9Vt0a2B","personaName":"Mira","publishable":true,"recipe":{"aspectRatio":"3:4","level":1,"lookId":null,"lookName":null,"outfit":null,"prompt":"reading by the window","remixOf":null,"sceneId":"golden-hour-rooftop","sceneTitle":"Golden hour rooftop","seed":1894522201},"rejectReason":null,"remixCount":0,"status":"queued","visibility":"private","width":null}]},"schema":{"$ref":"#/components/schemas/ShotList"}}},"description":"The shots, queued. The same Idempotency-Key returns the same shots.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/InsufficientLuvs"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/TooLarge"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/Unavailable"}},"security":[{"ApiKey":["shots:write"]}],"summary":"Order shots","tags":["Shots"]},"get":{"operationId":"listShots","parameters":[{"description":"Only this persona's shots.","in":"query","name":"personaId","schema":{"type":"string"}},{"description":"Only shots in this state.","in":"query","name":"status","schema":{"enum":["queued","running","done","failed","refused","cancelled"],"type":"string"}},{"description":"The `nextCursor` of the previous page.","in":"query","name":"cursor","schema":{"type":"string"}},{"description":"Page size: 24 by default, at most 48.","in":"query","name":"limit","schema":{"default":24,"maximum":48,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShotPage"}}},"description":"The member's shots, newest first.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/Unavailable"}},"security":[{"ApiKey":["shots:read"]}],"summary":"List shots","tags":["Shots"]}},"/shots/{id}":{"get":{"operationId":"getShot","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"example":{"shot":{"caption":null,"createdAt":"2026-10-12T09:30:00.000Z","deliveredAt":"2026-10-12T09:34:12.000Z","failure":null,"height":1344,"id":"6f1d3a34-52f6-4c0e-9f6f-5d0c3b5a6a11","imageUrl":"https://cdn.luv.club/studio/u1/6f1d3a34-52f6-4c0e-9f6f-5d0c3b5a6a11.png","level":1,"likeCount":0,"likedByMe":false,"luvs":5,"personaId":"kLq3x9Vt0a2B","personaName":"Mira","publishable":true,"recipe":{"aspectRatio":"3:4","level":1,"lookId":null,"lookName":null,"outfit":null,"prompt":"reading by the window","remixOf":null,"sceneId":"golden-hour-rooftop","sceneTitle":"Golden hour rooftop","seed":1894522201},"rejectReason":null,"remixCount":0,"status":"done","visibility":"private","width":1024}},"schema":{"$ref":"#/components/schemas/ShotResult"}}},"description":"The shot; poll every 4 seconds while it is `queued` or `running`.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/Unavailable"}},"security":[{"ApiKey":["shots:read"]}],"summary":"Get a shot","tags":["Shots"]},"delete":{"operationId":"deleteShot","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ok"}}},"description":"A shot being drawn is cancelled; a finished one is deleted.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/Unavailable"}},"security":[{"ApiKey":["shots:write"]}],"summary":"Cancel or delete a shot","tags":["Shots"]}},"/feed":{"get":{"operationId":"listFeed","parameters":[{"description":"`new` (default) or `top`.","in":"query","name":"sort","schema":{"default":"new","enum":["new","top"],"type":"string"}},{"description":"Only this persona's shots: the `persona.id` of a feed shot. A persona that does not exist, or has no public shot at the account's level, gives an empty page. The `nextCursor` of a filtered page works only with the same `persona`.","in":"query","name":"persona","schema":{"maxLength":120,"minLength":1,"type":"string"}},{"description":"The `nextCursor` of the previous page.","in":"query","name":"cursor","schema":{"type":"string"}},{"description":"Page size: 24 by default, at most 48.","in":"query","name":"limit","schema":{"default":24,"maximum":48,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedPage"}}},"description":"Public shots at or below the account's content level.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/Unavailable"}},"security":[{"ApiKey":["feed:read"]}],"summary":"Read the community feed","tags":["Feed"]}},"/picks":{"get":{"operationId":"listPicks","parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PickShelves"}}},"description":"Editor's picks shelves.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/Unavailable"}},"security":[{"ApiKey":["feed:read"]}],"summary":"Read Editor's picks","tags":["Feed"]}},"/webhooks":{"get":{"operationId":"listWebhooks","parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookList"}}},"description":"The member's webhook endpoints.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/Unavailable"}},"security":[{"ApiKey":["webhooks:write"]}],"summary":"List webhook endpoints","tags":["Webhooks"]},"post":{"operationId":"createWebhook","parameters":[],"requestBody":{"content":{"application/json":{"example":{"events":["shot.delivered","shot.failed"],"url":"https://example.com/hooks/luv"},"schema":{"$ref":"#/components/schemas/CreateWebhookRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"example":{"secret":"whsec_0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f","webhook":{"createdAt":"2026-10-12T09:00:00.000Z","disabledAt":null,"disabledReason":null,"events":["shot.delivered","shot.failed"],"id":"b4a1c1de-7b0c-45f3-9e5a-4a3f1e8c2d10","lastDeliveryAt":null,"lastStatus":null,"url":"https://example.com/hooks/luv"}},"schema":{"$ref":"#/components/schemas/WebhookCreated"}}},"description":"The endpoint and its signing secret, shown once.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"413":{"$ref":"#/components/responses/TooLarge"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/Unavailable"}},"security":[{"ApiKey":["webhooks:write"]}],"summary":"Add a webhook endpoint","tags":["Webhooks"]}},"/webhooks/{id}":{"delete":{"operationId":"deleteWebhook","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ok"}}},"description":"The endpoint is gone.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/Unavailable"}},"security":[{"ApiKey":["webhooks:write"]}],"summary":"Delete a webhook endpoint","tags":["Webhooks"]}},"/openapi.json":{"get":{"operationId":"getOpenApiDocument","parameters":[],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenApiDocument"}}},"description":"This document."}},"security":[],"summary":"The OpenAPI document of this API","tags":["Me"]}}},"security":[{"ApiKey":[]}],"servers":[{"description":"This server","url":"/api/v1"}],"tags":[{"description":"Who the key acts for","name":"Me"},{"description":"Scenes","name":"Catalog"},{"description":"Personas and the drafts they are made from","name":"Personas"},{"description":"Reusable outfits","name":"Looks"},{"description":"Orders and results","name":"Shots"},{"description":"The community feed and Editor's picks","name":"Feed"},{"description":"Endpoints that receive events","name":"Webhooks"}],"x-scopes":["personas:read","personas:write","looks:read","looks:write","shots:read","shots:write","feed:read","webhooks:write"],"webhooks":{"shot.delivered":{"post":{"description":"A shot was drawn and charged; its picture is ready.","operationId":"webhook_shot_delivered","parameters":[{"in":"header","name":"Luv-Event-Id","required":true,"schema":{"type":"string"}},{"in":"header","name":"Luv-Event-Type","required":true,"schema":{"const":"shot.delivered","type":"string"}},{"in":"header","name":"Luv-Timestamp","required":true,"schema":{"type":"string"}},{"description":"v1=<hex HMAC-SHA256 of \"<timestamp>.<raw body>\" with the endpoint secret>","in":"header","name":"Luv-Signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"createdAt":"2026-10-12T09:34:12.000Z","data":{"shot":{"caption":null,"createdAt":"2026-10-12T09:30:00.000Z","deliveredAt":"2026-10-12T09:34:12.000Z","failure":null,"height":1344,"id":"6f1d3a34-52f6-4c0e-9f6f-5d0c3b5a6a11","imageUrl":"https://cdn.luv.club/studio/u1/6f1d3a34-52f6-4c0e-9f6f-5d0c3b5a6a11.png","level":1,"likeCount":0,"likedByMe":false,"luvs":5,"personaId":"kLq3x9Vt0a2B","personaName":"Mira","publishable":true,"recipe":{"aspectRatio":"3:4","level":1,"lookId":null,"lookName":null,"outfit":null,"prompt":"reading by the window","remixOf":null,"sceneId":"golden-hour-rooftop","sceneTitle":"Golden hour rooftop","seed":1894522201},"rejectReason":null,"remixCount":0,"status":"done","visibility":"private","width":1024}},"id":"evt_4b83f7d2-0c4a-4a2d-9d7c-5b2b5e6f7088","type":"shot.delivered"},"schema":{"$ref":"#/components/schemas/Event_shot_delivered"}}},"required":true},"responses":{"200":{"description":"Received. Any 2xx within 10 seconds is a success."}},"summary":"shot.delivered","tags":["Webhooks"]}},"shot.failed":{"post":{"description":"A shot did not come out (failed, refused) or was cancelled.","operationId":"webhook_shot_failed","parameters":[{"in":"header","name":"Luv-Event-Id","required":true,"schema":{"type":"string"}},{"in":"header","name":"Luv-Event-Type","required":true,"schema":{"const":"shot.failed","type":"string"}},{"in":"header","name":"Luv-Timestamp","required":true,"schema":{"type":"string"}},{"description":"v1=<hex HMAC-SHA256 of \"<timestamp>.<raw body>\" with the endpoint secret>","in":"header","name":"Luv-Signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"createdAt":"2026-10-12T09:34:12.000Z","data":{"shot":{"caption":null,"createdAt":"2026-10-12T09:30:00.000Z","deliveredAt":null,"failure":"face_drift","height":null,"id":"6f1d3a34-52f6-4c0e-9f6f-5d0c3b5a6a11","imageUrl":null,"level":1,"likeCount":0,"likedByMe":false,"luvs":0,"personaId":"kLq3x9Vt0a2B","personaName":"Mira","publishable":true,"recipe":{"aspectRatio":"3:4","level":1,"lookId":null,"lookName":null,"outfit":null,"prompt":"reading by the window","remixOf":null,"sceneId":"golden-hour-rooftop","sceneTitle":"Golden hour rooftop","seed":1894522201},"rejectReason":null,"remixCount":0,"status":"failed","visibility":"private","width":null}},"id":"evt_5c94a8e3-1d5b-4b3e-8e8d-6c3c6f708199","type":"shot.failed"},"schema":{"$ref":"#/components/schemas/Event_shot_failed"}}},"required":true},"responses":{"200":{"description":"Received. Any 2xx within 10 seconds is a success."}},"summary":"shot.failed","tags":["Webhooks"]}},"persona.draft.ready":{"post":{"description":"The faces of a persona draft are drawn and can be chosen from.","operationId":"webhook_persona_draft_ready","parameters":[{"in":"header","name":"Luv-Event-Id","required":true,"schema":{"type":"string"}},{"in":"header","name":"Luv-Event-Type","required":true,"schema":{"const":"persona.draft.ready","type":"string"}},{"in":"header","name":"Luv-Timestamp","required":true,"schema":{"type":"string"}},{"description":"v1=<hex HMAC-SHA256 of \"<timestamp>.<raw body>\" with the endpoint secret>","in":"header","name":"Luv-Signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"createdAt":"2026-10-12T09:03:00.000Z","data":{"draft":{"candidates":[{"id":"ast_0a1","imageUrl":"https://cdn.luv.club/drafts/ast_0a1.png"},{"id":"ast_0a2","imageUrl":"https://cdn.luv.club/drafts/ast_0a2.png"}],"error":null,"id":"2d0b0f64-51a8-4f55-9c1e-7a2d35e0b9c4","state":"ready"}},"id":"evt_1b50e4af-7a1d-4d9a-a894-2e9e2b3c4d55","type":"persona.draft.ready"},"schema":{"$ref":"#/components/schemas/Event_persona_draft_ready"}}},"required":true},"responses":{"200":{"description":"Received. Any 2xx within 10 seconds is a success."}},"summary":"persona.draft.ready","tags":["Webhooks"]}},"persona.draft.failed":{"post":{"description":"The faces of a persona draft could not be drawn.","operationId":"webhook_persona_draft_failed","parameters":[{"in":"header","name":"Luv-Event-Id","required":true,"schema":{"type":"string"}},{"in":"header","name":"Luv-Event-Type","required":true,"schema":{"const":"persona.draft.failed","type":"string"}},{"in":"header","name":"Luv-Timestamp","required":true,"schema":{"type":"string"}},{"description":"v1=<hex HMAC-SHA256 of \"<timestamp>.<raw body>\" with the endpoint secret>","in":"header","name":"Luv-Signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"createdAt":"2026-10-12T09:05:00.000Z","data":{"draft":{"candidates":[],"error":"None of the faces came out clearly. Try a different description.","id":"2d0b0f64-51a8-4f55-9c1e-7a2d35e0b9c4","state":"failed"}},"id":"evt_3a72e6c1-9b3f-4f1c-8c6b-4a1a4d5e6f77","type":"persona.draft.failed"},"schema":{"$ref":"#/components/schemas/Event_persona_draft_failed"}}},"required":true},"responses":{"200":{"description":"Received. Any 2xx within 10 seconds is a success."}},"summary":"persona.draft.failed","tags":["Webhooks"]}},"persona.created":{"post":{"description":"A persona was made from a draft.","operationId":"webhook_persona_created","parameters":[{"in":"header","name":"Luv-Event-Id","required":true,"schema":{"type":"string"}},{"in":"header","name":"Luv-Event-Type","required":true,"schema":{"const":"persona.created","type":"string"}},{"in":"header","name":"Luv-Timestamp","required":true,"schema":{"type":"string"}},{"description":"v1=<hex HMAC-SHA256 of \"<timestamp>.<raw body>\" with the endpoint secret>","in":"header","name":"Luv-Signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"createdAt":"2026-10-12T09:05:00.000Z","data":{"persona":{"age":27,"avatarUrl":"https://cdn.luv.club/personas/kLq3x9Vt0a2B/avatar.png","createdAt":"2026-10-11T18:02:11.000Z","description":"Warm brown eyes, freckles, a quiet confidence","id":"kLq3x9Vt0a2B","lookCount":2,"name":"Mira","personality":"Dry humour, curious, never in a hurry","ready":true,"shotCount":14,"tagline":null}},"id":"evt_2c61f5b0-8a2e-4e0b-b9a5-3f0f3c4d5e66","type":"persona.created"},"schema":{"$ref":"#/components/schemas/Event_persona_created"}}},"required":true},"responses":{"200":{"description":"Received. Any 2xx within 10 seconds is a success."}},"summary":"persona.created","tags":["Webhooks"]}}}}