{"openapi":"3.1.0","info":{"title":"ChatsControl API","description":"Turn scans, photos and PDFs into editable Word files with their tables, stamps and signatures, translate them,\nand download Word or InDesign (IDML) files.\n\n## Authentication\nEvery request carries your API key: `Authorization: Bearer cc_live_...`. API access is opened to an account\non request (https://chatscontrol.com/api or the app's Settings, API); with it, you create and revoke your own keys in\nSettings, API. Characters are charged to the account the key belongs to, at its usual rates.\n\n## Flow\n1. `POST /v1/documents` with the file. The answer comes at once, with the document's `id`.\n2. Wait: poll `GET /v1/documents/{id}` until `status` is `completed` or `failed`, or pass a\n   `webhook_url` and we call you.\n3. `GET /v1/documents/{id}/download?file=translation&format=docx` (or `file=copy`, `format=idml`).\n\n## Retrying an upload\nSend an `Idempotency-Key` header (a UUID per upload) with `POST /v1/documents`. If the answer is lost, send\nthe same request with the same key: within a day it answers with the document the first request made, and the file is\nnot read or charged twice. The same key with another file answers 409 `IDEMPOTENCY_KEY_REUSED`.\n\n## Errors\nErrors answer `{\"error\": {\"code\": \"...\", \"message\": \"...\", \"params\": {}}}`; branch on `code`. Malformed fields\nanswer 422 with a `detail` list.\n\n## Limits\n120 requests and 20 uploads a minute per key; past them, 429\nwith `Retry-After`.\n\n## Webhooks\nWe POST a `WebhookPayload` as JSON with the headers `X-ChatsControl-Event` (`document.completed` or `document.failed`),\n`X-ChatsControl-Delivery` (unique per attempt) and `X-ChatsControl-Signature: t=<unix time>,v1=<hex>`, where `v1` is the\nHMAC-SHA256 of `<t>.<raw body>` under the webhook secret issued with your key. Check it and refuse a `t` more than\na few minutes old:\n\n```python\nimport hashlib, hmac, time\n\ndef verified(body: bytes, header: str, secret: str) -> bool:\n    fields = dict(part.split(\"=\", 1) for part in header.split(\",\"))\n    expected = hmac.new(secret.encode(), f\"{fields['t']}.\".encode() + body, hashlib.sha256).hexdigest()\n    return hmac.compare_digest(expected, fields[\"v1\"]) and abs(time.time() - int(fields[\"t\"])) < 300\n```\n\nAnswer 2xx within 10 seconds. Anything else is tried again after 30 s, 2 min, 10 min, 1 h, 6 h, then given up;\n`GET /v1/documents/{id}` still tells the outcome.","version":"v1"},"servers":[{"url":"https://api.translator.chatscontrol.com"}],"paths":{"/v1/documents":{"post":{"summary":"Upload a document or a scan","description":"Starts the work and answers at once with the document in `uploaded` or `processing`. Charged as in the app:\na document by its characters, a scan by its characters with a minimum per page. A scan your balance does not\ncover even at that minimum is refused before it is read.","operationId":"upload","security":[{"ApiKey":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"description":"Optional, any unique string per upload (a UUID). Sending the same key with the same file again within a day answers with the document the first request made instead of reading the file again: retry a timed-out upload safely.","title":"Idempotency-Key"},"description":"Optional, any unique string per upload (a UUID). Sending the same key with the same file again within a day answers with the document the first request made instead of reading the file again: retry a timed-out upload safely."}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiDocument"}}}},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}},"description":"Unauthorized"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}},"description":"Bad Request"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}},"description":"Request Entity Too Large"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"summary":"List your documents","description":"Newest first, uploaded through the API or in the app.","operationId":"list_documents","security":[{"ApiKey":[]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentPage"}}}},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}},"description":"Unauthorized"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/documents/{document_id}":{"get":{"summary":"Get a document's status","description":"Poll it until `status` is `completed` or `failed`; a scan takes a few minutes, a document less.","operationId":"get_document","security":[{"ApiKey":[]}],"parameters":[{"name":"document_id","in":"path","required":true,"schema":{"type":"string","title":"Document Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiDocument"}}}},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}},"description":"Unauthorized"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}},"description":"Bad Request"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}},"description":"Request Entity Too Large"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/documents/{document_id}/download":{"get":{"summary":"Download the copy or the translation","description":"Answers 409 `FILE_NOT_READY` until the file is in the document's `files`.","operationId":"download","security":[{"ApiKey":[]}],"parameters":[{"name":"document_id","in":"path","required":true,"schema":{"type":"string","title":"Document Id"}},{"name":"file","in":"query","required":false,"schema":{"$ref":"#/components/schemas/DocumentFile","description":"`copy`: the editable Word copy of the source; `translation`: the translated one.","default":"translation"},"description":"`copy`: the editable Word copy of the source; `translation`: the translated one."},{"name":"format","in":"query","required":false,"schema":{"$ref":"#/components/schemas/DownloadFormat","description":"`docx` for Word, `idml` for InDesign.","default":"docx"},"description":"`docx` for Word, `idml` for InDesign."},{"name":"notes_language","in":"query","required":false,"schema":{"enum":["uk","ru","en"],"type":"string","description":"Language of the notes a scan's Word file carries on handwriting.","default":"en","title":"Notes Language"},"description":"Language of the notes a scan's Word file carries on handwriting."}],"responses":{"200":{"description":"The file","content":{"application/vnd.openxmlformats-officedocument.wordprocessingml.document":{},"application/vnd.adobe.indesign-idml-package":{}}},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}},"description":"Unauthorized"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}},"description":"Bad Request"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}},"description":"Request Entity Too Large"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/documents/{document_id}/retry":{"post":{"summary":"Try a failed document again","description":"For a failed document whose `retryable` is true; its webhook, if it had one, is called again when it ends.","operationId":"retry","security":[{"ApiKey":[]}],"parameters":[{"name":"document_id","in":"path","required":true,"schema":{"type":"string","title":"Document Id"}}],"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiDocument"}}}},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}},"description":"Unauthorized"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}},"description":"Bad Request"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}},"description":"Not Found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}},"description":"Conflict"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}},"description":"Request Entity Too Large"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}},"description":"Too Many Requests"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/languages":{"get":{"summary":"Languages to translate into","operationId":"languages","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/Language"},"type":"array","title":"Response Languages"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}}},"security":[{"ApiKey":[]}]}},"/v1/balance":{"get":{"summary":"Characters left","operationId":"balance","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Balance"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorBody"}}}}},"security":[{"ApiKey":[]}]}}},"webhooks":{"document-ended":{"post":{"summary":"A document is completed or failed","description":"Sent to the `webhook_url` given at upload. Answer any 2xx within the timeout; anything else is tried again.","operationId":"document_endeddocument_ended_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookPayload"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"ApiDocument":{"properties":{"id":{"type":"string","title":"Id"},"filename":{"type":"string","title":"Filename","description":"The file's name as uploaded."},"kind":{"$ref":"#/components/schemas/DocumentKind"},"service":{"$ref":"#/components/schemas/BilledService","description":"`translation`, or `recognition`: a scan only read into an editable copy."},"status":{"$ref":"#/components/schemas/DocumentStatus","description":"`uploaded` and `processing` go on to `completed` or `failed`."},"source_language":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Language","description":"Detected from the text; null until it is."},"target_language":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target Language","description":"Null for recognition only."},"char_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Char Count","description":"Characters charged for; null until counted."},"page_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Page Count"},"files":{"items":{"$ref":"#/components/schemas/DocumentFile"},"type":"array","title":"Files","description":"Files ready to download: `copy` (the editable source) and, once translated, `translation`."},"error":{"anyOf":[{"$ref":"#/components/schemas/ApiError"},{"type":"null"}],"description":"Why it failed; null unless `status` is `failed`."},"retryable":{"type":"boolean","title":"Retryable","description":"A failed document failed on our side and can be tried again for free."},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"additionalProperties":false,"type":"object","required":["id","filename","kind","service","status","source_language","target_language","char_count","page_count","files","error","retryable","created_at","updated_at"],"title":"ApiDocument","description":"A document and where it stands."},"ApiError":{"properties":{"code":{"type":"string","title":"Code","description":"A stable code to branch on, e.g. `CHAR_LIMIT_REACHED`, `PDF_IS_SCAN`."},"message":{"type":"string","title":"Message","description":"What went wrong, in English."}},"additionalProperties":false,"type":"object","required":["code","message"],"title":"ApiError"},"Balance":{"properties":{"billing":{"type":"string","enum":["prepaid","postpaid","unlimited"],"title":"Billing"},"characters_remaining":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Characters Remaining","description":"Prepaid: free plus purchased characters left. Null for postpaid and unlimited accounts."},"free_characters_remaining":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Free Characters Remaining"},"purchased_characters_remaining":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Purchased Characters Remaining"},"characters_invoiced_this_month":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Characters Invoiced This Month","description":"Postpaid only: characters on this month's invoice."}},"additionalProperties":false,"type":"object","required":["billing","characters_remaining","free_characters_remaining","purchased_characters_remaining","characters_invoiced_this_month"],"title":"Balance","description":"What the account behind the key can still spend, in characters."},"BilledService":{"type":"string","enum":["translation","recognition"],"title":"BilledService","description":"What a document is charged for: read and translated, or only read into an editable copy."},"Body_upload":{"properties":{"file":{"type":"string","format":"binary","title":"File","description":"Up to 100 MB. A document: .docx, .pdf (a PDF holding its text). A scan: .pdf, .png, .jpg, .jpeg, .tif, .tiff, .webp, .docx, up to 50 pages."},"kind":{"$ref":"#/components/schemas/DocumentKind","description":"`scan` reads the pages from their pictures, keeping tables, stamps and signatures.","default":"document"},"target_language":{"type":"string","title":"Target Language","description":"A code from `GET /v1/languages`. Required unless only recognising a scan.","default":""},"language_variant":{"type":"string","title":"Language Variant","description":"One of the language's variants, e.g. `pt-BR`.","default":""},"translate":{"type":"boolean","title":"Translate","description":"Scans only: `false` reads the scan into an editable Word copy without translating it.","default":true},"context":{"type":"string","title":"Context","description":"Optional JSON brief: {\"domain\": \"legal\", \"audience\": \"business\", \"tone\": \"formal\", \"additional_context\": \"...\", \"terminology\": \"...\"}.","default":""},"webhook_url":{"type":"string","title":"Webhook Url","description":"Optional https URL we POST to once the document is completed or failed. Without it, poll `GET /v1/documents/{id}`.","default":""}},"type":"object","required":["file"],"title":"Body_upload"},"DocumentFile":{"type":"string","enum":["copy","translation"],"title":"DocumentFile"},"DocumentKind":{"type":"string","enum":["document","scan"],"title":"DocumentKind"},"DocumentPage":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ApiDocument"},"type":"array","title":"Items"},"has_more":{"type":"boolean","title":"Has More"}},"additionalProperties":false,"type":"object","required":["items","has_more"],"title":"DocumentPage"},"DocumentStatus":{"type":"string","enum":["uploaded","processing","completed","failed"],"title":"DocumentStatus"},"DownloadFormat":{"type":"string","enum":["docx","idml"],"title":"DownloadFormat","description":"What a document's stored Word file is handed out as; the value is the file's extension before fonts are\nzipped beside it."},"ErrorBody":{"properties":{"error":{"$ref":"#/components/schemas/ErrorDetail"}},"additionalProperties":false,"type":"object","required":["error"],"title":"ErrorBody","description":"Every error the API answers, but a request's malformed fields (422 with FastAPI's `detail` list)."},"ErrorDetail":{"properties":{"code":{"type":"string","title":"Code"},"message":{"type":"string","title":"Message"},"params":{"additionalProperties":true,"type":"object","title":"Params"}},"additionalProperties":false,"type":"object","required":["code","message","params"],"title":"ErrorDetail"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"Language":{"properties":{"code":{"type":"string","title":"Code","description":"Pass it as `target_language`."},"name":{"type":"string","title":"Name"},"variants":{"items":{"$ref":"#/components/schemas/LanguageVariant"},"type":"array","title":"Variants","description":"Pass one as `language_variant`."}},"additionalProperties":false,"type":"object","required":["code","name","variants"],"title":"Language"},"LanguageVariant":{"properties":{"code":{"type":"string","title":"Code"},"name":{"type":"string","title":"Name"}},"additionalProperties":false,"type":"object","required":["code","name"],"title":"LanguageVariant"},"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"},"WebhookEvent":{"type":"string","enum":["document.completed","document.failed"],"title":"WebhookEvent"},"WebhookPayload":{"properties":{"event":{"$ref":"#/components/schemas/WebhookEvent"},"document":{"$ref":"#/components/schemas/ApiDocument"}},"additionalProperties":false,"type":"object","required":["event","document"],"title":"WebhookPayload","description":"The body POSTed to your `webhook_url` once a document is completed or failed."}},"securitySchemes":{"ApiKey":{"type":"http","description":"Your API key, sent as `Authorization: Bearer cc_live_...`.","scheme":"bearer"}}}}