{"openapi":"3.1.0","info":{"title":"Inkaai Avatar API","version":"1.2.0","description":"Create a talking avatar from **one photo**. Everything else is optional.\n\n### Quickstart — the only call most people need\n\n```bash\ncurl -X POST https://inkaai.com/v1/avatar \\\n  -H \"Authorization: Bearer inkaa_sk_...\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n        \"image_url\": \"https://your-cdn.com/face.jpg\",\n        \"text\": \"Hi! This is my avatar speaking.\"\n      }'\n```\nReturns `{\"job_id\": \"...\", \"status\": \"queued\", \"credits_deducted\": N}`.\nThen poll `GET /v1/avatar/{job_id}` until `status` is `done`,\nand download `GET /v1/avatar/{job_id}/result` (mp4).\n\n### Which endpoint do I want?\n\n| I want to… | Use |\n|---|---|\n| Make a photo talk — I have the script | `POST /v1/avatar` with `image_url` + `text` |\n| …in a specific person's voice | add `voice_sample_url` (5-30s of them talking) |\n| …and I already have the speech audio | send `audio_url` instead of `text` |\n| Two people talking to each other | `person1_audio_url` + `person2_audio_url` |\n| Re-voice a video I already have | `POST /v1/lipsync` |\n| Reuse one avatar many times, cheaply | `POST /v1/library`, then `/v1/library/{id}/dub` |\n| Just synthesize speech, no video | `POST /v1/voice/clone-and-speak` |\n\n### Notes\n\n* **URLs, not uploads.** We fetch `image_url` / `audio_url`, so they must be publicly reachable. Image ≤20 MB, audio ≤100 MB. We fetch them synchronously during your submit call, so they only need to stay reachable for that request.\n* **Auth:** `Authorization: Bearer inkaa_sk_...` on every request. Create keys at https://inkaai.com/avatar-api-keys.html\n* **Billing:** by audio duration; credits are deducted on submit and **refunded automatically if the job fails or you cancel it**.\n* **Jobs are private to your key** — polling another key's `job_id` returns 403.\n\n### Job lifecycle\n\n`status` is one of **`queued`**, **`running`**, **`done`**, **`failed`**, **`cancelled`**.\n`done`, `failed` and `cancelled` are **terminal** — the `terminal` boolean says so\ndirectly, so a poll loop never has to hardcode the set. Anything else means keep polling.\n\nOn `failed` the payload carries a machine-readable **`error_code`** plus a\n**`permanent`** boolean: `permanent: true` means retrying the identical request\ncannot succeed (bad input), `false` means it was transient and a retry may work.\n\n`DELETE /v1/avatar/{job_id}` cancels a queued or running job and refunds its\ncredits. Cancelling an already-terminal job is a harmless no-op.\n\n### Limits\n\n| | |\n|---|---|\n| Max audio per job | **180 s** at `480p`, **120 s** at `720p` — split longer speech across jobs |\n| Concurrent jobs per key | **2** queued or running; further submits return `429` with `Retry-After` |\n| Image / audio size | 20 MB / 100 MB |\n\n**Typical completion times** (generation runs well above realtime — a job is not\na request/response operation):\n\n| audio | typical | p95 |\n|---|---|---|\n| 15 s | ~9 min | ~26 min |\n| 30 s | ~14 min | ~31 min |\n| 60 s | ~25 min | ~42 min |\n| 90 s | ~36 min | ~53 min |\n| 180 s | ~69 min | ~86 min |\n\nPoll every **15–30 seconds**; polling faster does not make a job finish sooner.\n\n### Retries and duplicates\n\nSend an **`Idempotency-Key`** header on `POST /v1/avatar`. Repeating a request\nwith the same key within 24 hours replays the original response instead of\ncreating a second job, so a lost response never means paying twice.\n\n### Output format\n\nMP4 (H.264) with AAC audio. `resolution` and `prompt` are advisory hints.\nAudio you supply is re-encoded — if your audio is quality-critical, keep your own\nmaster and re-mux it over our video."},"servers":[{"url":"https://inkaai.com","description":"production"}],"paths":{"/v1/avatar":{"post":{"summary":"V1 Avatar Submit","description":"Submit an avatar generation job. Returns {job_id, status, credits_deducted}.","operationId":"v1_avatar_submit_v1_avatar_post","parameters":[{"name":"authorization","in":"header","required":true,"schema":{"type":"string","default":"","title":"Authorization"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","default":"","title":"Idempotency-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/V1AvatarReq"},{"oneOf":[{"title":"Synthesize from text","required":["text"],"not":{"anyOf":[{"required":["audio_url"]},{"required":["person1_audio_url"]}]}},{"title":"Bring your own audio","required":["audio_url"],"not":{"anyOf":[{"required":["text"]},{"required":["person1_audio_url"]}]}},{"title":"Two speakers","required":["person1_audio_url","person2_audio_url"],"not":{"anyOf":[{"required":["text"]},{"required":["audio_url"]}]}}]}]}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","required":["job_id","status","credits_deducted","status_url","result_url"],"properties":{"job_id":{"type":"string","description":"Opaque job identifier.","examples":["9f2c1ab34de0"]},"status":{"type":"string","enum":["queued"],"description":"Always `queued` on acceptance."},"audio_duration_s":{"type":"number","description":"Probed duration of the speech audio."},"credits_deducted":{"type":"number","description":"Credits taken at submission. Refunded automatically if the job fails or is cancelled."},"remaining_balance":{"type":"number"},"mode":{"type":"string","enum":["single","multi"]},"status_url":{"type":"string"},"result_url":{"type":"string"},"idempotent_replay":{"type":"boolean","description":"true when this body was replayed from a previous request with the same Idempotency-Key. No new job was created and no credits were charged."}}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"type":"object","required":["detail"],"properties":{"detail":{"type":"string"}}}}}},"403":{"description":"This job belongs to a different API key.","content":{"application/json":{"schema":{"type":"object","required":["detail"],"properties":{"detail":{"type":"string"}}}}}},"404":{"description":"No such job.","content":{"application/json":{"schema":{"type":"object","required":["detail"],"properties":{"detail":{"type":"string"}}}}}},"429":{"description":"Too many concurrent jobs for this API key (limit 2 in flight). Retry after the interval in the Retry-After header.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","examples":[60]}}},"content":{"application/json":{"schema":{"type":"object","required":["detail"],"properties":{"detail":{"type":"string"}}}}}},"413":{"description":"Audio longer than the limit for the chosen resolution (180s at 480p, 120s at 720p), or an asset over its size cap.","content":{"application/json":{"schema":{"type":"object","required":["detail"],"properties":{"detail":{"type":"string"}}}}}},"402":{"description":"Insufficient credits for the submitted audio duration.","content":{"application/json":{"schema":{"type":"object","required":["detail"],"properties":{"detail":{"type":"string"}}}}}}}}},"/v1/avatar/{job_id}":{"get":{"summary":"V1 Avatar Status","description":"Get job status. Returns {status, message, pct, ...}.","operationId":"v1_avatar_status_v1_avatar__job_id__get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"authorization","in":"header","required":true,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","required":["job_id","status","terminal","pct"],"properties":{"job_id":{"type":"string"},"status":{"type":"string","enum":["queued","running","done","failed","cancelled"],"description":"Complete enumeration. Terminal: `done`, `failed`, `cancelled`. Keep polling on `queued` and `running`."},"terminal":{"type":"boolean","description":"True when no further transition will occur. Stop polling."},"message":{"type":["string","null"],"description":"Human-readable progress note. Do not branch on this."},"pct":{"type":"integer","minimum":0,"maximum":100,"description":"Integer percent. 0 while queued, 100 when done. Never null."},"audio_duration_s":{"type":["number","null"]},"wall_time_s":{"type":["number","null"],"description":"Generation wall time, present once terminal."},"error":{"type":["string","null"],"description":"Human-readable failure detail. Null unless status is `failed`."},"error_code":{"type":["string","null"],"description":"Machine-readable failure reason. Null unless status is `failed`.","enum":[null,"image_too_large","audio_too_large","asset_too_large","unreadable_audio","unreadable_asset","asset_unreachable","insufficient_credits","backend_timeout","backend_unavailable","backend_capacity","generation_failed"]},"permanent":{"type":["boolean","null"],"description":"True if retrying the identical request cannot succeed (bad input). False if transient — a retry may work. Null unless status is `failed`."},"result_url":{"type":["string","null"],"description":"Populated only when status is `done`."}}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"type":"object","required":["detail"],"properties":{"detail":{"type":"string"}}}}}},"403":{"description":"This job belongs to a different API key.","content":{"application/json":{"schema":{"type":"object","required":["detail"],"properties":{"detail":{"type":"string"}}}}}},"404":{"description":"No such job.","content":{"application/json":{"schema":{"type":"object","required":["detail"],"properties":{"detail":{"type":"string"}}}}}}}},"delete":{"summary":"V1 Avatar Cancel","description":"Cancel a queued or running avatar job and refund its credits.\n\nBest-effort: work already dispatched to the generation backend may still\nfinish, but the job is marked cancelled, the result is not delivered, and\nthe credits taken at submission are returned. Cancelling an already-terminal\njob is a no-op and returns its current state (idempotent).","operationId":"v1_avatar_cancel_v1_avatar__job_id__delete","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"authorization","in":"header","required":true,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","required":["job_id","status","cancelled","credits_refunded"],"properties":{"job_id":{"type":"string"},"status":{"type":"string","enum":["queued","running","done","failed","cancelled"]},"terminal":{"type":"boolean"},"cancelled":{"type":"boolean","description":"False when the job was already terminal (no-op, not an error)."},"credits_refunded":{"type":"number"},"message":{"type":"string"}}}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"type":"object","required":["detail"],"properties":{"detail":{"type":"string"}}}}}},"403":{"description":"This job belongs to a different API key.","content":{"application/json":{"schema":{"type":"object","required":["detail"],"properties":{"detail":{"type":"string"}}}}}},"404":{"description":"No such job.","content":{"application/json":{"schema":{"type":"object","required":["detail"],"properties":{"detail":{"type":"string"}}}}}}}}},"/v1/avatar/{job_id}/result":{"get":{"summary":"V1 Avatar Result","description":"Get the resulting mp4 (auth-gated).","operationId":"v1_avatar_result_v1_avatar__job_id__result_get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"authorization","in":"header","required":true,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"video/mp4":{"schema":{"type":"string","format":"binary","description":"The generated MP4, streamed directly. Not a redirect."}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"type":"object","required":["detail"],"properties":{"detail":{"type":"string"}}}}}},"403":{"description":"This job belongs to a different API key.","content":{"application/json":{"schema":{"type":"object","required":["detail"],"properties":{"detail":{"type":"string"}}}}}},"404":{"description":"No such job.","content":{"application/json":{"schema":{"type":"object","required":["detail"],"properties":{"detail":{"type":"string"}}}}}}}}},"/v1/library":{"post":{"summary":"V1 Library Upload","description":"Store a photo and return an id usable as `library_id` on POST /v1/avatar.\n\nFree and instant — nothing is generated or charged here; this only stores\nthe image. It exists because `image_url` requires a publicly reachable URL,\nwhich a caller handling personal or clinical photos often cannot provide.\nUpload once, then reference the id on every generation.","operationId":"v1_library_upload_v1_library_post","parameters":[{"name":"authorization","in":"header","required":true,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_v1_library_upload_v1_library_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"type":"object","required":["detail"],"properties":{"detail":{"type":"string"}}}}}},"403":{"description":"This job belongs to a different API key.","content":{"application/json":{"schema":{"type":"object","required":["detail"],"properties":{"detail":{"type":"string"}}}}}},"404":{"description":"No such job.","content":{"application/json":{"schema":{"type":"object","required":["detail"],"properties":{"detail":{"type":"string"}}}}}}}},"get":{"summary":"V1 Library List","description":"List photos stored under this API key's account.","operationId":"v1_library_list_v1_library_get","parameters":[{"name":"authorization","in":"header","required":true,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"type":"object","required":["detail"],"properties":{"detail":{"type":"string"}}}}}},"403":{"description":"This job belongs to a different API key.","content":{"application/json":{"schema":{"type":"object","required":["detail"],"properties":{"detail":{"type":"string"}}}}}},"404":{"description":"No such job.","content":{"application/json":{"schema":{"type":"object","required":["detail"],"properties":{"detail":{"type":"string"}}}}}}}}},"/v1/library/{library_id}":{"get":{"summary":"V1 Library Get","description":"Fetch one stored photo's metadata.","operationId":"v1_library_get_v1_library__library_id__get","parameters":[{"name":"library_id","in":"path","required":true,"schema":{"type":"string","title":"Library Id"}},{"name":"authorization","in":"header","required":true,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"type":"object","required":["detail"],"properties":{"detail":{"type":"string"}}}}}},"403":{"description":"This job belongs to a different API key.","content":{"application/json":{"schema":{"type":"object","required":["detail"],"properties":{"detail":{"type":"string"}}}}}},"404":{"description":"No such job.","content":{"application/json":{"schema":{"type":"object","required":["detail"],"properties":{"detail":{"type":"string"}}}}}}}},"delete":{"summary":"V1 Library Delete","description":"Delete a stored photo and its S3 objects.","operationId":"v1_library_delete_v1_library__library_id__delete","parameters":[{"name":"library_id","in":"path","required":true,"schema":{"type":"string","title":"Library Id"}},{"name":"authorization","in":"header","required":true,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"type":"object","required":["detail"],"properties":{"detail":{"type":"string"}}}}}},"403":{"description":"This job belongs to a different API key.","content":{"application/json":{"schema":{"type":"object","required":["detail"],"properties":{"detail":{"type":"string"}}}}}},"404":{"description":"No such job.","content":{"application/json":{"schema":{"type":"object","required":["detail"],"properties":{"detail":{"type":"string"}}}}}}}}},"/v1/usage":{"get":{"summary":"V1 Usage","description":"Balance, spend and job counts for this account — with a per-key breakdown.\n\nCredits are pooled per ACCOUNT: one email can hold many keys and they all draw\non the same balance. `GET /v1/avatar/{job_id}` answers \"what did this job cost\"\nand the dashboard answers \"what is my balance\", but nothing answered \"which key\nis spending my money\", which is the question a customer running separate keys\nfor staging and production actually has.\n\nReads the billing ledger rather than keeping a second counter, so it cannot\ndrift from what was actually charged.","operationId":"v1_usage_v1_usage_get","parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","default":30,"title":"Days"}},{"name":"authorization","in":"header","required":true,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"type":"object","required":["detail"],"properties":{"detail":{"type":"string"}}}}}},"403":{"description":"This job belongs to a different API key.","content":{"application/json":{"schema":{"type":"object","required":["detail"],"properties":{"detail":{"type":"string"}}}}}},"404":{"description":"No such job.","content":{"application/json":{"schema":{"type":"object","required":["detail"],"properties":{"detail":{"type":"string"}}}}}}}}}},"components":{"schemas":{"Body_v1_library_upload_v1_library_post":{"properties":{"image":{"type":"string","format":"binary","title":"Image","description":"Reference photo (jpg/png, ≤20 MB)"},"name":{"type":"string","title":"Name","description":"Label for this photo, ≤80 chars","default":""}},"type":"object","required":["image"],"title":"Body_v1_library_upload_v1_library_post"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"V1AvatarReq":{"properties":{"image_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Image Url","description":"HTTPS URL of reference photo (jpg/png, ≤20 MB). Provide this OR library_id.","examples":["https://example.com/face.jpg"]},"library_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Library Id","description":"Id of a photo already stored via POST /v1/library. Use instead of image_url when the photo cannot be exposed on a public URL.","examples":["a1b2c3d4e5f6"]},"text":{"anyOf":[{"type":"string","maxLength":5000},{"type":"null"}],"title":"Text","description":"What the avatar should say. We synthesize it — no need to make audio yourself. Mutually exclusive with audio_url.","examples":["Hey there, welcome to the show."]},"voice_sample_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Voice Sample Url","description":"Optional 5-30s HTTPS audio of a voice to clone for `text`. Omit to use a default voice.","examples":["https://example.com/my_voice.wav"]},"language":{"type":"string","maxLength":2,"minLength":2,"title":"Language","description":"2-letter ISO code for `text` (en, hi, ta, te, es, fr, ...)","default":"en"},"voice_gender":{"type":"string","pattern":"^(male|female|neutral)$","title":"Voice Gender","description":"Default-voice gender. Ignored when voice_sample_url is given.","default":"neutral"},"emotion":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Emotion","description":"Delivery hint for `text` (neutral, happy, sad, angry)","default":"neutral"},"audio_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Audio Url","description":"HTTPS URL of ready-made speech audio (wav/mp3/m4a, ≤100 MB). Mutually exclusive with text.","examples":["https://example.com/voice.mp3"]},"person1_audio_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Person1 Audio Url","description":"HTTPS URL of left speaker's audio (two-speaker mode)"},"person2_audio_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Person2 Audio Url","description":"HTTPS URL of right speaker's audio (two-speaker mode)"},"prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Prompt","description":"Optional scene/character prompt to bias the look","default":"","examples":["A woman in a kitchen, warm lighting"]},"resolution":{"type":"string","pattern":"^(480p|720p)$","title":"Resolution","description":"Output quality. `720p` renders 2.25x the pixels of `480p` and takes about 2.2x as long. Orientation is chosen separately -- see `aspect_ratio` -- so either quality is available for both vertical and horizontal photos. Exact frames: 480p is 832x480 or 480x832; 720p is 1280x704 or 704x1280.","default":"480p"},"aspect_ratio":{"anyOf":[{"type":"string","pattern":"^(16:9|9:16)$"},{"type":"null"}],"title":"Aspect Ratio","description":"Optional. `16:9` horizontal or `9:16` vertical. **Leave it unset and we match your photo's own orientation**, which is almost always what you want: the frame is centre-cropped to fill, so a vertical photo forced to `16:9` keeps only about 41% of its height and the face is cropped to a horizontal band."},"project_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Name","description":"Optional human-friendly label that appears in your dashboard","default":""},"seed":{"anyOf":[{"type":"integer","maximum":2147483647.0,"minimum":0.0},{"type":"null"}],"title":"Seed","description":"Optional. Fixes the random seed so the same request reproduces the same take. Omit for a new variation each time."},"callback_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Callback Url","description":"Optional public https URL. We POST the final job status here once the job reaches a terminal state, so you do not have to poll. The body is identical to GET /v1/avatar/{job_id}.","examples":["https://your.app/hooks/inkaai"]}},"type":"object","title":"V1AvatarReq","description":"Body for POST /v1/avatar.\n\nSingle speaker — pick ONE way to supply the speech:\n  1. text                          -> we synthesize it in a default voice\n  2. text + voice_sample_url       -> we clone that voice, then synthesize\n  3. audio_url                     -> you supply the speech yourself\n\nTwo-speaker: person1_audio_url + person2_audio_url instead.","examples":[{"description":"Smallest valid request: just an image and a single audio file.","summary":"Single speaker (minimal)","value":{"audio_url":"https://example.com/voice.mp3","image_url":"https://example.com/face.jpg"}},{"description":"All optional fields populated.","summary":"Single speaker (full)","value":{"audio_url":"https://example.com/voice.mp3","image_url":"https://example.com/face.jpg","project_name":"Recipe intro v1","prompt":"A woman in a kitchen, warm lighting","resolution":"720p"}},{"description":"Pass two audio URLs instead of one. The two speakers in the photo are taken to be left and right by face bounding box.","summary":"Two speakers (conversation)","value":{"image_url":"https://example.com/two_people.jpg","person1_audio_url":"https://example.com/alice.mp3","person2_audio_url":"https://example.com/bob.mp3","resolution":"720p"}}]},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}},"securitySchemes":{"ApiKeyAuth":{"type":"http","scheme":"bearer","description":"Your key from https://inkaai.com/avatar-api-keys.html — send as `Authorization: Bearer inkaa_sk_...`"}}},"security":[{"ApiKeyAuth":[]}]}