{"openapi":"3.0.3","info":{"title":"Kuro API","version":"1.0.0","description":"Make images, clips, voice-overs and music, and run recipes, from your own code. The same API serves Kuro Cloud and every studio you run yourself.\n\nAuthenticate with a personal token from Settings → Connections: `Authorization: Bearer KR_…`. A token minted with permissions works only here and at `/mcp`, and each operation names the permission it needs.\n\nGenerations run on your own provider keys at no credits when you hold one that can run them, exactly as in the app; otherwise they spend credits.\n\nWebhooks: pass `webhook_url` (HTTPS) when you make a generation or run a recipe, and the server POSTs a `WebhookEvent` there when it settles: `generation.ready` or `generation.failed`, `run.done` or `run.failed`, and `run.asks_you` when a run waits on you. Each POST carries `webhook-id`, `webhook-timestamp` and `webhook-signature` (Standard Webhooks, HMAC-SHA256 with the signing secret from Settings → Connections); verify it, answer 2xx within ten seconds, and treat a repeated `webhook-id` as the same event. A refused or unanswered event is retried for a day.\n\nInside v1 changes are additive only: new fields, new operations, and new values in enums whose description says so. Ignore what you do not recognise.","license":{"name":"AGPL-3.0-only","url":"https://www.gnu.org/licenses/agpl-3.0.html"}},"servers":[{"url":"https://api.meetkuro.com"}],"security":[{"token":[]}],"tags":[{"name":"Account"},{"name":"Models"},{"name":"Generations"},{"name":"Uploads"},{"name":"Recipes"},{"name":"Runs"},{"name":"Subjects"}],"paths":{"/v1/me":{"get":{"operationId":"getAccount","summary":"Read the account","description":"Who the key belongs to, its credits and plan, and what the key may do.\n\nAny key.","tags":["Account"],"parameters":[],"responses":{"200":{"description":"Read the account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Account"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"402":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/models":{"get":{"operationId":"listModels","summary":"List models","description":"Every model this server can run, with its price, shapes, lengths, reference capacity and voices. Pass `type` for one medium.\n\nPermission: `media.read`.","tags":["Models"],"parameters":[{"name":"type","in":"query","required":false,"schema":{"type":"string","enum":["image","clip","voiceover","music"]}}],"responses":{"200":{"description":"List models","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","enum":["list"]},"data":{"type":"array","items":{"$ref":"#/components/schemas/Model"}},"next_cursor":{"type":"string","nullable":true,"description":"Pass as `cursor` for the next page; null on the last one."}},"required":["object","data","next_cursor"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"402":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/models/{id}":{"get":{"operationId":"getModel","summary":"Read a model","description":"One model, with its guide: how to prompt it well and what it cannot do.\n\nPermission: `media.read`.","tags":["Models"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Read a model","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Model"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"402":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/quotes":{"post":{"operationId":"createQuote","summary":"Price a request","description":"What a generation or a recipe run would cost and who would pay, compared with the balance. Creates nothing.\n\nPermission: `generation.write`.","tags":["Generations"],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","enum":["image"]},"prompt":{"type":"string","maxLength":2000,"default":""},"model":{"type":"string","maxLength":80,"description":"Defaults to the server's default image model."},"aspect_ratio":{"type":"string","maxLength":12,"description":"Such as \"9:16\", \"1:1\" or \"16:9\". Defaults to 9:16, snapped to what the model offers."},"setting":{"type":"string","maxLength":40,"description":"The model's one extra setting (`setting` on `GET /v1/models/{id}`), such as its quality."},"references":{"type":"array","items":{"$ref":"#/components/schemas/MediaReference"},"maxItems":16,"description":"Pictures the model can see. The model's `max_reference_images` applies."},"subjects":{"type":"array","items":{"type":"string","minLength":1,"maxLength":120},"maxItems":4,"description":"Names or ids of your Subjects. Kuro brings each one's face and description, so do not also attach pictures of them."},"runs_on":{"type":"string","maxLength":40,"description":"Who pays: \"credits\", or the vendor of one of your own keys (\"replicate\", \"fal\", …). Leave out to follow the payer order set in Settings → Agents."}},"required":["type"]},{"type":"object","properties":{"type":{"type":"string","enum":["clip"]},"prompt":{"type":"string","maxLength":4000,"default":""},"model":{"type":"string","maxLength":80,"description":"Defaults to the server's default clip model."},"duration_seconds":{"type":"integer","minimum":-1,"maximum":60,"description":"One of the model's `duration.values`; -1 lets a model that supports it choose."},"resolution":{"type":"string","maxLength":12},"aspect_ratio":{"type":"string","maxLength":12,"description":"Defaults to 9:16. Leave out with a `first_frame`: the clip takes the frame's shape."},"generate_audio":{"type":"boolean"},"first_frame":{"$ref":"#/components/schemas/MediaReference","description":"A picture, clip or sound you already have in Kuro."},"last_frame":{"$ref":"#/components/schemas/MediaReference","description":"A picture, clip or sound you already have in Kuro."},"reference_images":{"type":"array","items":{"$ref":"#/components/schemas/MediaReference"},"maxItems":9},"reference_videos":{"type":"array","items":{"$ref":"#/components/schemas/MediaReference"},"maxItems":3,"description":"A take to copy motion from, or to re-sync a mouth in."},"reference_audios":{"type":"array","items":{"$ref":"#/components/schemas/MediaReference"},"maxItems":3},"subjects":{"type":"array","items":{"type":"string","minLength":1,"maxLength":120},"maxItems":4,"description":"Names or ids of your Subjects. Kuro brings each one's face and description, so do not also attach pictures of them."},"runs_on":{"type":"string","maxLength":40,"description":"Who pays: \"credits\", or the vendor of one of your own keys (\"replicate\", \"fal\", …). Leave out to follow the payer order set in Settings → Agents."}},"required":["type"]},{"type":"object","properties":{"type":{"type":"string","enum":["voiceover"]},"text":{"type":"string","minLength":1,"maxLength":4000,"description":"The words to speak."},"subject":{"type":"string","minLength":1,"maxLength":120,"description":"A Subject whose bound voice reads it. Then leave out model, voice, style_prompt and language_code."},"model":{"type":"string","maxLength":80},"voice":{"type":"string","minLength":1,"maxLength":120,"description":"A voice id from the model's `voices`."},"style_prompt":{"type":"string","maxLength":4000,"description":"How to say it, on models that take one."},"language_code":{"type":"string","minLength":2,"maxLength":35},"speed":{"type":"number","minimum":0.1,"maximum":5},"emotion":{"type":"string","maxLength":40},"runs_on":{"type":"string","maxLength":40,"description":"Who pays: \"credits\", or the vendor of one of your own keys (\"replicate\", \"fal\", …). Leave out to follow the payer order set in Settings → Agents."}},"required":["type","text"]},{"type":"object","properties":{"type":{"type":"string","enum":["music"]},"prompt":{"type":"string","minLength":1,"maxLength":4000,"description":"The brief: genre, mood, instruments, tempo."},"model":{"type":"string","maxLength":80},"lyrics":{"type":"string","minLength":1,"maxLength":3500},"instrumental":{"type":"boolean","description":"Defaults to true when there are no lyrics."},"runs_on":{"type":"string","maxLength":40,"description":"Who pays: \"credits\", or the vendor of one of your own keys (\"replicate\", \"fal\", …). Leave out to follow the payer order set in Settings → Agents."}},"required":["type","prompt"]},{"type":"object","properties":{"prompt":{"type":"string","maxLength":4000,"default":"","description":"The idea, in the words the recipe's `prompt` asks for."},"inputs":{"type":"object","additionalProperties":{},"default":{},"description":"By key. On an `arm` or `reprompt` recipe, each of its `inputs` takes a list of media (`{ \"type\": \"upload\", \"upload_id\" }`, `{ \"type\": \"generation\", \"generation_id\" }`) or one Subject (`{ \"type\": \"subject\", \"subject_id\" }`). On a `run` recipe, each of its `run_inputs` takes the value its type asks for."},"choices":{"type":"object","additionalProperties":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"default":{},"description":"One option `value` per choice, by key; a list where `max_picks` is above one."},"model":{"type":"string","maxLength":80,"description":"Another model of the recipe's medium. Not for `run` recipes."},"runs_on":{"type":"string","maxLength":40,"description":"Who pays: \"credits\", or the vendor of one of your own keys (\"replicate\", \"fal\", …). Leave out to follow the payer order set in Settings → Agents."},"type":{"type":"string","enum":["recipe"]},"recipe_id":{"type":"string","format":"uuid"}},"required":["type","recipe_id"]}],"description":"The body `POST /v1/generations` takes, or a recipe run as `{ \"type\": \"recipe\", \"recipe_id\", … }` with the body `POST /v1/recipes/{id}/runs` takes."}}}},"responses":{"200":{"description":"Price a request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Quote"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"402":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/generations":{"post":{"operationId":"createGeneration","summary":"Make an image, clip, voice-over or music","description":"Starts one generation. It spends credits, or runs on your own provider key: your provider bills you, and Kuro charges no credits. Pass `wait` to hold the response until it is ready (images usually are within a minute); otherwise read it with `GET /v1/generations/{id}`.\n\nPermission: `generation.write`.","tags":["Generations"],"parameters":[{"name":"wait","in":"query","required":false,"description":"Hold the response up to this many seconds until the work settles. 0 answers at once.","schema":{"type":"integer","minimum":0,"maximum":60,"default":0}},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ImageRequest"},{"$ref":"#/components/schemas/ClipRequest"},{"$ref":"#/components/schemas/VoiceoverRequest"},{"$ref":"#/components/schemas/MusicRequest"}],"description":"What to make. `type` decides which fields apply."}}}},"responses":{"201":{"description":"Make an image, clip, voice-over or music","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Generation"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"402":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"get":{"operationId":"listGenerations","summary":"List generations","description":"Your generations, newest first.\n\nPermission: `media.read`.","tags":["Generations"],"parameters":[{"name":"type","in":"query","required":false,"schema":{"type":"string","enum":["image","clip","voiceover","music"]}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["queued","generating","ready","failed"]}},{"name":"q","in":"query","required":false,"description":"Search titles, prompts and tags.","schema":{"type":"string","maxLength":200}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"cursor","in":"query","required":false,"description":"The `next_cursor` of the page before.","schema":{"type":"string","maxLength":500}}],"responses":{"200":{"description":"List generations","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","enum":["list"]},"data":{"type":"array","items":{"$ref":"#/components/schemas/Generation"}},"next_cursor":{"type":"string","nullable":true,"description":"Pass as `cursor` for the next page; null on the last one."}},"required":["object","data","next_cursor"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"402":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/generations/{id}":{"get":{"operationId":"getGeneration","summary":"Read a generation","description":"One generation. Pass `wait` to hold the response until it is `ready` or `failed`.\n\nPermission: `media.read`.","tags":["Generations"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"wait","in":"query","required":false,"description":"Hold the response up to this many seconds until the work settles. 0 answers at once.","schema":{"type":"integer","minimum":0,"maximum":60,"default":0}}],"responses":{"200":{"description":"Read a generation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Generation"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"402":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}},"delete":{"operationId":"deleteGeneration","summary":"Delete a generation","description":"Deletes it and its files. One still working is cancelled first.\n\nPermission: `generation.write`.","tags":["Generations"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Delete a generation","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","enum":["generation"]},"id":{"type":"string","format":"uuid"},"deleted":{"type":"boolean","enum":[true]}},"required":["object","id","deleted"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"402":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/uploads":{"post":{"operationId":"createUpload","summary":"Start an upload","description":"Reserves an upload and answers with where to PUT the bytes. PUT them with every `upload_headers` entry, then call `POST /v1/uploads/{id}/complete`.\n\nPermission: `generation.write`.","tags":["Uploads"],"parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"filename":{"type":"string","minLength":1,"maxLength":220},"mime_type":{"type":"string","minLength":1,"maxLength":120,"description":"Such as \"image/png\" or \"video/mp4\"."},"bytes":{"type":"integer","exclusiveMinimum":true,"minimum":0},"checksum_sha256":{"type":"string","pattern":"^[0-9a-f]{64}$","description":"Hex SHA-256 of the bytes, checked when the upload completes."}},"required":["filename","mime_type","bytes"]}}}},"responses":{"201":{"description":"Start an upload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadTicket"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"402":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/uploads/{id}/complete":{"post":{"operationId":"completeUpload","summary":"Finish an upload","description":"Checks the bytes against what was declared and answers with the upload, ready to use as a reference.\n\nPermission: `generation.write`.","tags":["Uploads"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"checksum_sha256":{"type":"string","pattern":"^[0-9a-f]{64}$"},"width":{"type":"integer","exclusiveMinimum":true,"minimum":0},"height":{"type":"integer","exclusiveMinimum":true,"minimum":0}}}}}},"responses":{"200":{"description":"Finish an upload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Upload"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"402":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/uploads/import":{"post":{"operationId":"importUpload","summary":"Import a file from a URL","description":"Fetches a file and stores it as a verified upload. Only hosts the server allows are fetched; otherwise use `POST /v1/uploads`.\n\nPermission: `generation.write`.","tags":["Uploads"],"parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri","description":"A file on a host this server is allowed to fetch from (`MEDIA_IMPORT_ALLOWED_HOSTS`)."},"filename":{"type":"string","minLength":1,"maxLength":220},"mime_type":{"type":"string","minLength":1,"maxLength":120}},"required":["url"]}}}},"responses":{"201":{"description":"Import a file from a URL","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Upload"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"402":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/uploads/{id}":{"get":{"operationId":"getUpload","summary":"Read an upload","description":"One upload.\n\nPermission: `media.read`.","tags":["Uploads"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Read an upload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Upload"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"402":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/recipes":{"get":{"operationId":"listRecipes","summary":"List recipes","description":"The recipes you can run: the catalog and your own. Each says what it asks for.\n\nPermission: `recipes.read`.","tags":["Recipes"],"parameters":[{"name":"type","in":"query","required":false,"schema":{"type":"string","enum":["image","clip","voiceover","music"]}},{"name":"q","in":"query","required":false,"schema":{"type":"string","maxLength":100}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"cursor","in":"query","required":false,"description":"The `next_cursor` of the page before.","schema":{"type":"string","maxLength":500}}],"responses":{"200":{"description":"List recipes","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","enum":["list"]},"data":{"type":"array","items":{"$ref":"#/components/schemas/Recipe"}},"next_cursor":{"type":"string","nullable":true,"description":"Pass as `cursor` for the next page; null on the last one."}},"required":["object","data","next_cursor"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"402":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/recipes/{id}":{"get":{"operationId":"getRecipe","summary":"Read a recipe","description":"One recipe and every question it asks.\n\nPermission: `recipes.read`.","tags":["Recipes"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Read a recipe","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Recipe"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"402":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/recipes/{id}/runs":{"post":{"operationId":"runRecipe","summary":"Run a recipe","description":"Answers the recipe's questions and starts it. An `arm` or `reprompt` recipe makes one generation; a `run` recipe starts a run you can read and cancel at `/v1/runs/{id}`. Pass `wait` to hold the response until it settles.\n\nPermission: `generation.write`.","tags":["Recipes"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"wait","in":"query","required":false,"description":"Hold the response up to this many seconds until the work settles. 0 answers at once.","schema":{"type":"integer","minimum":0,"maximum":60,"default":0}},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"prompt":{"type":"string","maxLength":4000,"default":"","description":"The idea, in the words the recipe's `prompt` asks for."},"inputs":{"type":"object","additionalProperties":{},"default":{},"description":"By key. On an `arm` or `reprompt` recipe, each of its `inputs` takes a list of media (`{ \"type\": \"upload\", \"upload_id\" }`, `{ \"type\": \"generation\", \"generation_id\" }`) or one Subject (`{ \"type\": \"subject\", \"subject_id\" }`). On a `run` recipe, each of its `run_inputs` takes the value its type asks for."},"choices":{"type":"object","additionalProperties":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"default":{},"description":"One option `value` per choice, by key; a list where `max_picks` is above one."},"model":{"type":"string","maxLength":80,"description":"Another model of the recipe's medium. Not for `run` recipes."},"runs_on":{"type":"string","maxLength":40,"description":"Who pays: \"credits\", or the vendor of one of your own keys (\"replicate\", \"fal\", …). Leave out to follow the payer order set in Settings → Agents."},"webhook_url":{"type":"string","maxLength":2048,"format":"uri","description":"Where to POST a signed event when this settles. HTTPS on the default port; see Webhooks in the API description."}}}}}},"responses":{"201":{"description":"Run a recipe","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecipeRun"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"402":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/runs":{"get":{"operationId":"listRuns","summary":"List runs","description":"Your runs of `run` recipes, newest first. Read one whole with `GET /v1/runs/{id}`.\n\nPermission: `media.read`.","tags":["Runs"],"parameters":[{"name":"cursor","in":"query","required":false,"description":"The `next_cursor` of the page before.","schema":{"type":"string","maxLength":500}}],"responses":{"200":{"description":"List runs","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","enum":["list"]},"data":{"type":"array","items":{"type":"object","properties":{"object":{"type":"string","enum":["run"]},"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["queued","running","awaiting_approval","paused","succeeded","failed","canceled"],"description":"`succeeded`, `failed` and `canceled` are final. `awaiting_approval` and `paused` wait on you in the app (`app_url`). New values may be added."},"created_at":{"type":"string","format":"date-time"},"completed_at":{"type":"string","format":"date-time","nullable":true}},"required":["object","id","status","created_at","completed_at"]}},"next_cursor":{"type":"string","nullable":true,"description":"Pass as `cursor` for the next page; null on the last one."}},"required":["object","data","next_cursor"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"402":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/runs/{id}":{"get":{"operationId":"getRun","summary":"Read a run","description":"One run and what it has made. Pass `wait` to hold the response until it finishes or waits on you.\n\nPermission: `media.read`.","tags":["Runs"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"wait","in":"query","required":false,"description":"Hold the response up to this many seconds until the work settles. 0 answers at once.","schema":{"type":"integer","minimum":0,"maximum":60,"default":0}}],"responses":{"200":{"description":"Read a run","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Run"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"402":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/runs/{id}/cancel":{"post":{"operationId":"cancelRun","summary":"Cancel a run","description":"Stops a run. What it already made stays; credits held for the rest are released.\n\nPermission: `generation.write`.","tags":["Runs"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Cancel a run","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Run"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"402":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/subjects":{"get":{"operationId":"listSubjects","summary":"List subjects","description":"The people, places and products you make again and again. Name one in a request's `subjects`.\n\nPermission: `media.read`.","tags":["Subjects"],"parameters":[{"name":"q","in":"query","required":false,"schema":{"type":"string","maxLength":120}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"cursor","in":"query","required":false,"description":"The `next_cursor` of the page before.","schema":{"type":"string","maxLength":500}}],"responses":{"200":{"description":"List subjects","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","enum":["list"]},"data":{"type":"array","items":{"$ref":"#/components/schemas/Subject"}},"next_cursor":{"type":"string","nullable":true,"description":"Pass as `cursor` for the next page; null on the last one."}},"required":["object","data","next_cursor"]}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"402":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/subjects/{id}":{"get":{"operationId":"getSubject","summary":"Read a subject","description":"One subject.\n\nPermission: `media.read`.","tags":["Subjects"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Read a subject","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Subject"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"402":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}}},"components":{"securitySchemes":{"token":{"type":"http","scheme":"bearer","description":"A personal token (`KR_…`) from Settings → Connections."}},"parameters":{"IdempotencyKey":{"name":"Idempotency-Key","in":"header","required":false,"description":"Any string up to 255 characters. Send the same value to retry a request without spending twice; a different body under a used key is refused with 409.","schema":{"type":"string","minLength":1,"maxLength":255}}},"responses":{"Error":{"description":"The request was refused. `error.code` is stable; on 429, wait `Retry-After` seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"Account":{"type":"object","properties":{"object":{"type":"string","enum":["account"]},"id":{"type":"string","format":"uuid"},"plan":{"type":"string"},"credits":{"type":"number","description":"Credits available now."},"charges_credits":{"type":"boolean","description":"False on a server that sells nothing: everything runs on its keys or yours."},"ai_requests_per_minute":{"type":"integer","description":"How many generations a minute the account may start, shared with the app and agents."},"permissions":{"type":"array","items":{"type":"string"},"nullable":true,"description":"What this key may do; null when it holds the whole account."}},"required":["object","id","plan","credits","charges_credits","ai_requests_per_minute","permissions"],"description":"Who the key belongs to and what it may spend."},"Model":{"type":"object","properties":{"object":{"type":"string","enum":["model"]},"id":{"type":"string"},"type":{"type":"string","enum":["image","clip","voiceover","music"]},"label":{"type":"string"},"maker":{"type":"string"},"credits":{"type":"number","description":"Credits for the request `credits_basis` names."},"credits_basis":{"type":"string"},"cost_rank":{"type":"integer","description":"1 is the cheapest of its type."},"paid_by":{"type":"string","description":"Who pays when a request names no payer: the vendor of your own key, \"house\" or \"credits\"."},"default":{"type":"boolean","description":"Used when a request names no model."},"aspect_ratios":{"type":"array","items":{"type":"string"}},"resolutions":{"type":"array","items":{"type":"string"}},"duration":{"type":"object","properties":{"min":{"type":"number"},"max":{"type":"number"},"values":{"type":"array","items":{"type":"number"}}},"required":["min","max","values"],"nullable":true,"description":"Clip lengths in seconds; null for other types."},"setting":{"type":"object","properties":{"key":{"type":"string"},"default":{"type":"string"},"options":{"type":"array","items":{"type":"string"}}},"required":["key","default","options"],"nullable":true,"description":"The one model-specific image setting (`setting` on an image request)."},"max_reference_images":{"type":"integer"},"max_reference_videos":{"type":"integer"},"max_reference_audios":{"type":"integer"},"supports_first_frame":{"type":"boolean"},"supports_last_frame":{"type":"boolean"},"required_inputs":{"type":"object","properties":{"image":{"type":"boolean"},"video":{"type":"boolean"},"audio":{"type":"boolean"}},"required":["image","video","audio"]},"voices":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"}},"required":["id","label"]},"description":"For a voice-over model, the voices it speaks with."},"languages":{"type":"array","items":{"type":"string"}},"guide":{"type":"object","properties":{"prompting":{"type":"string"},"constraints":{"type":"array","items":{"type":"string"}},"pitfalls":{"type":"array","items":{"type":"string"}}},"required":["prompting","constraints","pitfalls"],"nullable":true,"description":"How to prompt it well. Only on `GET /v1/models/{id}`."}},"required":["object","id","type","label","maker","credits","credits_basis","cost_rank","paid_by","default","aspect_ratios","resolutions","duration","setting","max_reference_images","max_reference_videos","max_reference_audios","supports_first_frame","supports_last_frame","required_inputs","voices","languages","guide"],"description":"A model this server can run."},"Quote":{"type":"object","properties":{"object":{"type":"string","enum":["quote"]},"credits":{"type":"number","description":"What it would cost, in credits."},"paid_by":{"type":"string","nullable":true,"description":"Who would pay: \"credits\", \"house\", \"server\", or the vendor of your own key."},"estimated_cost_usd":{"type":"number","nullable":true,"description":"What your own provider account would be charged, when your key pays."},"available_credits":{"type":"number"},"affordable":{"type":"boolean","description":"Whether it can run now."},"aspect_ratio":{"type":"string","nullable":true},"blocked":{"type":"object","properties":{"vendor":{"type":"string"},"reason":{"type":"string"}},"required":["vendor","reason"],"nullable":true,"description":"Why the payer named in `runs_on` cannot take it."}},"required":["object","credits","paid_by","estimated_cost_usd","available_credits","affordable","aspect_ratio","blocked"],"description":"A price, before anything is spent."},"Generation":{"type":"object","properties":{"object":{"type":"string","enum":["generation"]},"id":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["image","clip","voiceover","music","tool"],"description":"What was made. New values may be added; treat an unknown one as opaque."},"status":{"type":"string","enum":["queued","generating","ready","failed"],"description":"`ready` and `failed` are final."},"model":{"type":"string","description":"The model id it was made with (`GET /v1/models`)."},"prompt":{"type":"string"},"aspect_ratio":{"type":"string","nullable":true,"description":"Null for audio."},"output_url":{"type":"string","format":"uri","nullable":true,"description":"The finished file, once `ready`. A signed link that works for about an hour; read the generation again for a fresh one."},"thumbnail_url":{"type":"string","format":"uri","nullable":true,"description":"A small still of the result, for a grid. Null for audio and while it works."},"credits":{"type":"number","nullable":true,"description":"Credits charged. Zero when your own provider key or the free allowance paid."},"paid_by":{"type":"string","nullable":true,"description":"Who paid: \"credits\", \"house\" (the free allowance), \"server\" (a server that charges nothing), or the vendor of your own key (\"replicate\", \"fal\", …)."},"error":{"type":"string","nullable":true,"description":"Why it failed. Null otherwise."},"ready_in_seconds":{"type":"number","nullable":true,"description":"Roughly how long an unfinished generation has left; 0 means past its usual time."},"recipe_id":{"type":"string","format":"uuid","nullable":true,"description":"The recipe it was made with, if any."},"created_at":{"type":"string","format":"date-time"},"app_url":{"type":"string","format":"uri","description":"Opens it in the app."}},"required":["object","id","type","status","model","prompt","aspect_ratio","output_url","thumbnail_url","credits","paid_by","error","ready_in_seconds","recipe_id","created_at","app_url"],"description":"One image, clip, voice-over or piece of music."},"ImageRequest":{"type":"object","properties":{"type":{"type":"string","enum":["image"]},"prompt":{"type":"string","maxLength":2000,"default":""},"model":{"type":"string","maxLength":80,"description":"Defaults to the server's default image model."},"aspect_ratio":{"type":"string","maxLength":12,"description":"Such as \"9:16\", \"1:1\" or \"16:9\". Defaults to 9:16, snapped to what the model offers."},"setting":{"type":"string","maxLength":40,"description":"The model's one extra setting (`setting` on `GET /v1/models/{id}`), such as its quality."},"references":{"type":"array","items":{"$ref":"#/components/schemas/MediaReference"},"maxItems":16,"description":"Pictures the model can see. The model's `max_reference_images` applies."},"subjects":{"type":"array","items":{"type":"string","minLength":1,"maxLength":120},"maxItems":4,"description":"Names or ids of your Subjects. Kuro brings each one's face and description, so do not also attach pictures of them."},"runs_on":{"type":"string","maxLength":40,"description":"Who pays: \"credits\", or the vendor of one of your own keys (\"replicate\", \"fal\", …). Leave out to follow the payer order set in Settings → Agents."},"webhook_url":{"type":"string","maxLength":2048,"format":"uri","description":"Where to POST a signed event when this settles. HTTPS on the default port; see Webhooks in the API description."}},"required":["type"]},"ClipRequest":{"type":"object","properties":{"type":{"type":"string","enum":["clip"]},"prompt":{"type":"string","maxLength":4000,"default":""},"model":{"type":"string","maxLength":80,"description":"Defaults to the server's default clip model."},"duration_seconds":{"type":"integer","minimum":-1,"maximum":60,"description":"One of the model's `duration.values`; -1 lets a model that supports it choose."},"resolution":{"type":"string","maxLength":12},"aspect_ratio":{"type":"string","maxLength":12,"description":"Defaults to 9:16. Leave out with a `first_frame`: the clip takes the frame's shape."},"generate_audio":{"type":"boolean"},"first_frame":{"$ref":"#/components/schemas/MediaReference","description":"A picture, clip or sound you already have in Kuro."},"last_frame":{"$ref":"#/components/schemas/MediaReference","description":"A picture, clip or sound you already have in Kuro."},"reference_images":{"type":"array","items":{"$ref":"#/components/schemas/MediaReference"},"maxItems":9},"reference_videos":{"type":"array","items":{"$ref":"#/components/schemas/MediaReference"},"maxItems":3,"description":"A take to copy motion from, or to re-sync a mouth in."},"reference_audios":{"type":"array","items":{"$ref":"#/components/schemas/MediaReference"},"maxItems":3},"subjects":{"type":"array","items":{"type":"string","minLength":1,"maxLength":120},"maxItems":4,"description":"Names or ids of your Subjects. Kuro brings each one's face and description, so do not also attach pictures of them."},"runs_on":{"type":"string","maxLength":40,"description":"Who pays: \"credits\", or the vendor of one of your own keys (\"replicate\", \"fal\", …). Leave out to follow the payer order set in Settings → Agents."},"webhook_url":{"type":"string","maxLength":2048,"format":"uri","description":"Where to POST a signed event when this settles. HTTPS on the default port; see Webhooks in the API description."}},"required":["type"]},"VoiceoverRequest":{"type":"object","properties":{"type":{"type":"string","enum":["voiceover"]},"text":{"type":"string","minLength":1,"maxLength":4000,"description":"The words to speak."},"subject":{"type":"string","minLength":1,"maxLength":120,"description":"A Subject whose bound voice reads it. Then leave out model, voice, style_prompt and language_code."},"model":{"type":"string","maxLength":80},"voice":{"type":"string","minLength":1,"maxLength":120,"description":"A voice id from the model's `voices`."},"style_prompt":{"type":"string","maxLength":4000,"description":"How to say it, on models that take one."},"language_code":{"type":"string","minLength":2,"maxLength":35},"speed":{"type":"number","minimum":0.1,"maximum":5},"emotion":{"type":"string","maxLength":40},"runs_on":{"type":"string","maxLength":40,"description":"Who pays: \"credits\", or the vendor of one of your own keys (\"replicate\", \"fal\", …). Leave out to follow the payer order set in Settings → Agents."},"webhook_url":{"type":"string","maxLength":2048,"format":"uri","description":"Where to POST a signed event when this settles. HTTPS on the default port; see Webhooks in the API description."}},"required":["type","text"]},"MusicRequest":{"type":"object","properties":{"type":{"type":"string","enum":["music"]},"prompt":{"type":"string","minLength":1,"maxLength":4000,"description":"The brief: genre, mood, instruments, tempo."},"model":{"type":"string","maxLength":80},"lyrics":{"type":"string","minLength":1,"maxLength":3500},"instrumental":{"type":"boolean","description":"Defaults to true when there are no lyrics."},"runs_on":{"type":"string","maxLength":40,"description":"Who pays: \"credits\", or the vendor of one of your own keys (\"replicate\", \"fal\", …). Leave out to follow the payer order set in Settings → Agents."},"webhook_url":{"type":"string","maxLength":2048,"format":"uri","description":"Where to POST a signed event when this settles. HTTPS on the default port; see Webhooks in the API description."}},"required":["type","prompt"]},"MediaReference":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","enum":["upload"]},"upload_id":{"type":"string","format":"uuid"}},"required":["type","upload_id"]},{"type":"object","properties":{"type":{"type":"string","enum":["generation"]},"generation_id":{"type":"string","format":"uuid"}},"required":["type","generation_id"]}],"description":"A picture, clip or sound you already have in Kuro."},"UploadTicket":{"type":"object","properties":{"object":{"type":"string","enum":["upload_ticket"]},"upload_id":{"type":"string","format":"uuid"},"upload_url":{"type":"string","format":"uri","description":"PUT the file's bytes here."},"upload_headers":{"type":"object","additionalProperties":{"type":"string"},"description":"Send every one of these on the PUT, exactly as given: they are signed into the URL."},"expires_at":{"type":"string","format":"date-time"}},"required":["object","upload_id","upload_url","upload_headers","expires_at"],"description":"Where to send a file's bytes. Then call `POST /v1/uploads/{id}/complete`."},"Upload":{"type":"object","properties":{"object":{"type":"string","enum":["upload"]},"id":{"type":"string","format":"uuid"},"filename":{"type":"string"},"type":{"type":"string","enum":["image","video","audio"]},"mime_type":{"type":"string"},"bytes":{"type":"integer"},"status":{"type":"string","enum":["pending","verified","rejected","expired"],"description":"Only a `verified` upload can be used in a generation."},"url":{"type":"string","format":"uri","description":"A signed link to the file, for about an hour."},"thumbnail_url":{"type":"string","format":"uri","nullable":true},"reference":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","enum":["upload"]},"upload_id":{"type":"string","format":"uuid"}},"required":["type","upload_id"]},{"type":"object","properties":{"type":{"type":"string","enum":["generation"]},"generation_id":{"type":"string","format":"uuid"}},"required":["type","generation_id"]}],"description":"Pass this where a request takes media."},"created_at":{"type":"string","format":"date-time"}},"required":["object","id","filename","type","mime_type","bytes","status","url","thumbnail_url","reference","created_at"],"description":"A file you brought into Kuro."},"Recipe":{"type":"object","properties":{"object":{"type":"string","enum":["recipe"]},"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string"},"action":{"type":"string","enum":["arm","reprompt","run"],"description":"`arm` makes one generation from your answers; `reprompt` does too, with a model writing the prompt from them; `run` starts a multi-step run (`GET /v1/runs/{id}`). New values may be added."},"type":{"type":"string","enum":["image","clip","voiceover","music"],"description":"What it makes. New values may be added."},"model":{"type":"string","nullable":true,"description":"The default model; null on a `run` recipe, whose steps choose their own."},"recommended_models":{"type":"array","items":{"type":"string"},"description":"Models its author tested. Any model of its medium that can take its inputs runs it too."},"prompt":{"type":"object","properties":{"label":{"type":"string"},"placeholder":{"type":"string"},"required":{"type":"boolean"},"max_length":{"type":"integer"}},"required":["label","placeholder","required","max_length"],"nullable":true,"description":"What `prompt` asks for when you run it; null when it asks for none."},"inputs":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"label":{"type":"string"},"help":{"type":"string","nullable":true},"media":{"type":"string","description":"\"image\", \"video\" or \"audio\"."},"required":{"type":"boolean"},"max_items":{"type":"integer"},"takes_subject":{"type":"boolean","description":"Whether this input takes one of your Subjects as `{ \"type\": \"subject\", \"subject_id\" }`."}},"required":["key","label","help","media","required","max_items","takes_subject"]},"description":"The media an `arm` or `reprompt` recipe takes, by key."},"choices":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"label":{"type":"string"},"help":{"type":"string","nullable":true},"options":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"}},"required":["value","label"]}},"max_picks":{"type":"integer"},"shown_when":{"type":"object","properties":{"choice":{"type":"string"},"values":{"type":"array","items":{"type":"string"}}},"required":["choice","values"],"nullable":true,"description":"Asked only when that earlier choice holds one of these values."}},"required":["key","label","help","options","max_picks","shown_when"]}},"run_inputs":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"key":{"type":"string"},"label":{"type":"string"}},"required":["type","key","label"]},"description":"What a `run` recipe takes, by key; empty on the others."},"tags":{"type":"array","items":{"type":"string"}},"uses":{"type":"integer"},"cover_url":{"type":"string","format":"uri","nullable":true},"app_url":{"type":"string","format":"uri"}},"required":["object","id","name","description","action","type","model","recommended_models","prompt","inputs","choices","run_inputs","tags","uses","cover_url","app_url"],"description":"A template that asks a few questions and makes something."},"RecipeRun":{"type":"object","properties":{"object":{"type":"string","enum":["recipe_run"]},"recipe_id":{"type":"string","format":"uuid"},"run":{"allOf":[{"$ref":"#/components/schemas/Run"}],"nullable":true,"description":"The run a `run` recipe started; null for `arm` and `reprompt`, which make one generation."},"generations":{"type":"array","items":{"$ref":"#/components/schemas/Generation"},"description":"What it made: the one generation, or what the run has made so far."}},"required":["object","recipe_id","run","generations"],"description":"What running a recipe started."},"Run":{"type":"object","properties":{"object":{"type":"string","enum":["run"]},"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["queued","running","awaiting_approval","paused","succeeded","failed","canceled"],"description":"`succeeded`, `failed` and `canceled` are final. `awaiting_approval` and `paused` wait on you in the app (`app_url`). New values may be added."},"error":{"type":"object","properties":{"code":{"type":"string","nullable":true},"message":{"type":"string"}},"required":["code","message"],"nullable":true},"generations":{"type":"array","items":{"$ref":"#/components/schemas/Generation"},"description":"Everything the run has made so far, in order."},"created_at":{"type":"string","format":"date-time"},"completed_at":{"type":"string","format":"date-time","nullable":true},"app_url":{"type":"string","format":"uri"}},"required":["object","id","status","error","generations","created_at","completed_at","app_url"],"description":"One run of a `run` recipe: several steps, several generations."},"Subject":{"type":"object","properties":{"object":{"type":"string","enum":["subject"]},"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"kind":{"type":"string","description":"\"character\", \"location\", \"product\", \"prop\" or \"wardrobe\". New values may be added."},"description":{"type":"string","nullable":true},"identity_images":{"type":"integer","description":"How many reference pictures travel with it. Zero: it travels as words alone."},"has_voice":{"type":"boolean","description":"Whether a voice is bound to it, for voice-overs."},"tags":{"type":"array","items":{"type":"string"}},"preview_url":{"type":"string","format":"uri","nullable":true},"created_at":{"type":"string","format":"date-time"},"app_url":{"type":"string","format":"uri"}},"required":["object","id","name","kind","description","identity_images","has_voice","tags","preview_url","created_at","app_url"],"description":"Someone or something you make again and again. Name it in `subjects` and Kuro brings its face and description."},"WebhookEvent":{"type":"object","properties":{"type":{"type":"string","enum":["generation.ready","generation.failed","run.asks_you","run.done","run.failed"],"description":"What happened. `run.asks_you` may arrive more than once; the others once per webhook_url. New types may be added inside v1."},"timestamp":{"type":"string","format":"date-time","description":"When it happened."},"data":{"type":"object","properties":{"object":{"type":"string","enum":["generation","run"]},"id":{"type":"string","format":"uuid"},"status":{"type":"string","description":"The object's status when it happened."},"error":{"anyOf":[{"type":"string"},{"type":"object","properties":{"code":{"type":"string","nullable":true},"message":{"type":"string"}},"required":["code","message"]}],"nullable":true}},"required":["object","id","status","error"],"description":"The object, thin: read it whole with your key (`GET /v1/generations/{id}` or `GET /v1/runs/{id}`), which also mints fresh media URLs."}},"required":["type","timestamp","data"],"description":"The body of a webhook POST. Verify `webhook-signature` (Standard Webhooks, with the signing secret from Settings → Connections) before trusting it, and answer 2xx within ten seconds."},"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","description":"A stable machine-readable code, such as `INSUFFICIENT_CREDITS` or `RATE_LIMITED`."},"message":{"type":"string"},"details":{}},"required":["code","message"]}},"required":["error"],"description":"Every error has this shape."}}}}