{"openapi":"3.0.3","info":{"title":"Čtení Faktur API","version":"1.0.0","description":"Veřejné REST API pro nahrávání dokladů a stahování exportů.\n\n**Rychlý start.** Od souboru k importu do účetnictví to jsou čtyři volání, z toho tři na naše API:\n\n```bash\nAPI=\"https://ctenifaktur.cz/api/v1\"\nAUTH=\"Authorization: Bearer cf_live_…\"\n\n# 1. Řekněte si o adresu. Vrátí batchId a uploadUrl.\ncurl -X POST $API/documents \\\n  -H \"$AUTH\" -H \"Content-Type: application/json\" \\\n  -d '{\"files\":[{\"fileName\":\"faktura.pdf\",\n        \"contentType\":\"application/pdf\",\"sizeBytes\":184320}]}'\n\n# 2. Pošlete bajty. Bez hlaviček, na adresu z kroku 1.\ncurl -X PUT --data-binary @faktura.pdf \"UPLOAD_URL\"\n\n# 3. Stav. Opakujte, dokud je status pending nebo processing.\ncurl $API/batches/BATCH_ID -H \"$AUTH\"\n\n# 4. Export. Id jsou v uploads[].documentIds.\ncurl -X POST $API/documents/export \\\n  -H \"$AUTH\" -H \"Content-Type: application/json\" \\\n  -d '{\"documentIds\":[\"DOC_ID\"],\"format\":\"pohoda\"}' \\\n  -o faktura.xml\n```\n\n**Autentizace.** Klíč `cf_live_…` vydáte v aplikaci na stránce Tým a nastavení v sekci API klíče a posíláte ho v hlavičce `Authorization: Bearer <klíč>`. Klíč je vázaný na jednu kancelář a nikdy neumí více než člen, který ho vydal: oprávnění se dopočítávají z aktuálního členství při každém požadavku, takže odebrání práv nebo vyřazení z kanceláře platí okamžitě. API je dostupné v placených tarifech.\n\n**Nahrání je jeden endpoint pro všechno.** `POST /documents` se chová stejně pro jeden soubor i pro dávku až 300 souborů a pro jakoukoli velikost do 25 MB, takže se velikostí nemusíte zabývat. Bajty jdou přímo do úložiště, ne přes naše API, takže neplatí strop 4,5 MB na tělo požadavku a samotné `PUT` se do limitu požadavků nepočítají. Že dorazily, si všimneme sami; potvrzovat nahrání se nemusí.\n\n**Jeden soubor může dát více dokladů.** PDF s několika fakturami se rozpozná a rozdělí, takže `uploadId` označuje nahrání, ne doklad. Které doklady z něj vznikly, řekne `GET /batches/{id}` v poli `documentIds`.\n\n**Vytěžená data se přes API nedají přečíst, jen vyexportovat.** `GET /documents/{id}` vrací jen metadata (stav, název souboru, jednotka). Dodavatel, částky ani položky se přes API nečtou; data odcházejí výhradně přes `POST /documents/export`, a to rovnou jako soubor v účetním formátu.\n\n**Limity.** 300 souborů na dávku, 25 MB na soubor, 500 dokladů na jeden export. Limit požadavků se počítá na klíč a minutu; platný strop i zbytek rozpočtu si čtěte z hlaviček `X-RateLimit-*`, ne z pevného čísla v dokumentaci. Hlavičky nese každá odpověď, kterou limit započítal, včetně chybových. Chybí u 401 a 403, které se odmítají dřív, než se na limit sáhne, a u 500 a 503.\n\n**Chyby.** Vždy `{ \"error\": { \"code\", \"message\", \"details\"? } }`. Větvete na `code`, ne na `message` ani na stavový kód: `message` je český text pro člověka a mění se, `code` je součást kontraktu.","contact":{"name":"Podpora Čtení Faktur","url":"https://ctenifaktur.cz/kontakt"},"termsOfService":"https://ctenifaktur.cz/obchodni-podminky"},"servers":[{"url":"https://ctenifaktur.cz/api/v1"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"Nahrávání","description":"Nahrání dokladů a spuštění zpracování."},{"name":"Stav","description":"Průběh dávky a metadata dokladu."},{"name":"Export","description":"Stažení dokladů v účetním formátu."},{"name":"Účetní jednotky","description":"Jednotky, na které klíč dosáhne."}],"paths":{"/documents":{"post":{"tags":["Nahrávání"],"summary":"Nahrání dokladů","description":"Jediná cesta k nahrání a funguje stejně pro jeden soubor i pro dávku, pro 200 kB i pro 25 MB. Rezervuje kredit a vrátí jednu předpodepsanou adresu na soubor.\n\nBajty pak pošlete prostým `PUT <uploadUrl>` bez jakýchkoli hlaviček (Content-Type se nepodepisuje), takže je to jeden HTTP uzel v n8n i v Make. Tyhle `PUT` jdou mimo naše API, takže se do limitu požadavků nepočítají.\n\n**Potom už nic volat nemusíte.** Že bajty dorazily, si všimneme sami a zpracování se rozjede do minuty. Když vám program spadne hned po `PUT`, o doklad ani o kredit nepřijdete.\n\nAdresa platí 15 minut. Když `PUT` selže, zopakujte ho na tutéž adresu; opakování je pro nás k nerozeznání od pomalého prvního pokusu. Soubor, který se nenahraje vůbec, se po vypršení lhůty zahodí a kredit se vrátí.","operationId":"createUploads","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Libovolný neprázdný řetězec do 255 znaků. Opakovaný požadavek se stejným klíčem vrátí původní odpověď (včetně původního stavového kódu) a neúčtuje se znovu. Platnost 24 hodin. Poslat stejný klíč s jiným tělem skončí chybou `idempotency_conflict`.\n\nOpakování vrací původní odpověď doslova, tedy i původní adresy pro nahrání, a ty platí 15 minut. Na opakování během několika minut, kvůli kterému klíč existuje, to nemá vliv; po vypršení lhůty ale adresy z odpovědi už nikam nenahrajete a je potřeba založit nahrání znovu s novým klíčem. Kredit z prvního pokusu se vrátí sám, jakmile se soubor nenahraje.","schema":{"type":"string","maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUploadRequest"},"example":{"accountingUnitId":"665f1f77bcf86cd799439011","files":[{"fileName":"faktura-2026-001.pdf","contentType":"application/pdf","sizeBytes":184320}]}}}},"responses":{"200":{"description":"Dávka založena, kredit rezervován.","headers":{"X-RateLimit-Limit":{"description":"Strop požadavků na klíč a minutu.","schema":{"type":"integer","example":60}},"X-RateLimit-Remaining":{"description":"Kolik požadavků v aktuálním okně zbývá.","schema":{"type":"integer","example":59}},"X-RateLimit-Reset":{"description":"Unixový čas (v sekundách), kdy se okno resetuje.","schema":{"type":"integer","example":1785312000}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUploadResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/InsufficientCredits"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/IdempotencyConflict"},"413":{"$ref":"#/components/responses/FileTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedFileType"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/batches/{id}":{"get":{"tags":["Stav"],"summary":"Průběh dávky","description":"Další volání po nahrání a jediné, na které se při čekání ptáte. Ptejte se, dokud je `status` na `pending` nebo `processing`. Konečné stavy jsou tři: `completed`, `completed_with_failures` a `failed`; kterýkoli z nich znamená konec čekání. U prvních dvou jsou id hotových dokladů v `uploads[].documentIds` a jdou rovnou do exportu. Pořadí v `uploads` odpovídá pořadí souborů v požadavku, takže se odpověď dá spárovat proti vstupnímu poli.\n\nČástečný neúspěch se řeší po souborech, ne po dávce: dávka, kde selhal jeden soubor z deseti, hlásí `completed_with_failures` a devět položek `completed`, ne plošné `failed`. Který soubor selhal a proč, řekne `uploads[].status` a `uploads[].errorCode`; zbylé doklady se exportují normálně.\n\nHotové nahrání ještě nemusí znamenat, že z něj vzniklo všechno. Když soubor obsahoval více dokladů, než se stihlo zpracovat nebo vytěžit, přibude `uploads[].incomplete` s počty. `status` zůstává `completed`, protože co vzniklo, je v pořádku, takže kdo se dívá jen na něj, o zbytek přijde, aniž by se to dozvěděl.","operationId":"getBatch","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"`batchId` z nahrávacího volání."}],"responses":{"200":{"description":"Stav dávky a jednotlivých nahrání.","headers":{"X-RateLimit-Limit":{"description":"Strop požadavků na klíč a minutu.","schema":{"type":"integer","example":60}},"X-RateLimit-Remaining":{"description":"Kolik požadavků v aktuálním okně zbývá.","schema":{"type":"integer","example":59}},"X-RateLimit-Reset":{"description":"Unixový čas (v sekundách), kdy se okno resetuje.","schema":{"type":"integer","example":1785312000}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchStatus"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/documents/{id}":{"get":{"tags":["Stav"],"summary":"Metadata dokladu","description":"Doplněk k průběhu dávky, pro integraci ho většinou nepotřebujete. Vrací pouze metadata. Vytěžená data (dodavatel, částky, položky) API nevrací, ta odcházejí výhradně přes export.","operationId":"getDocument","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Id dokladu z `GET /batches/{id}`."}],"responses":{"200":{"description":"Metadata dokladu.","headers":{"X-RateLimit-Limit":{"description":"Strop požadavků na klíč a minutu.","schema":{"type":"integer","example":60}},"X-RateLimit-Remaining":{"description":"Kolik požadavků v aktuálním okně zbývá.","schema":{"type":"integer","example":59}},"X-RateLimit-Reset":{"description":"Unixový čas (v sekundách), kdy se okno resetuje.","schema":{"type":"integer","example":1785312000}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DocumentMetadata"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/documents/export":{"post":{"tags":["Export"],"summary":"Export dokladů do účetního formátu","description":"Vrací rovnou bajty souboru, ne odkaz ani base64 v JSONu. Název je v `Content-Disposition`.\n\nISDOC dá u jednoho dokladu soubor `.isdoc`, u více dokladů ZIP. Pohoda i Money S3 vracejí vždy jedno XML.\n\nDoklady musí patřit jedné účetní jednotce: jeden soubor nese jedno IČO a jedno nastavení, takže smíchaná dávka by se do účetního programu naimportovala špatně. Když o dávce nerozhoduje žádná jednotka, protože ji doklady nemají nebo byla smazaná, musí se místo toho shodnout IČO odběratele na dokladech; jinak by soubor dostal IČO prvního dokladu a zbytek by se naimportoval pod cizí firmu.\n\nDávku nerozdělujeme automaticky. Obě odmítnutí vrátí v `details.documents[]` u každého dokladu jeho jednotku i IČO, takže se dávka dá rozdělit na volání po jednotkách (u nezařazených dokladů po firmách) a poslat znovu. Bez IČO by u dvou nezařazených dokladů nebylo podle čeho dělit.\n\nPořadí dokladů ve výstupu odpovídá pořadí `documentIds`.","operationId":"exportDocuments","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExportRequest"},"example":{"documentIds":["665f1f77bcf86cd799439033"],"format":"pohoda"}}}},"responses":{"200":{"description":"Bajty exportního souboru.","headers":{"X-RateLimit-Limit":{"description":"Strop požadavků na klíč a minutu.","schema":{"type":"integer","example":60}},"X-RateLimit-Remaining":{"description":"Kolik požadavků v aktuálním okně zbývá.","schema":{"type":"integer","example":59}},"X-RateLimit-Reset":{"description":"Unixový čas (v sekundách), kdy se okno resetuje.","schema":{"type":"integer","example":1785312000}},"Content-Disposition":{"description":"Navržený název souboru.","schema":{"type":"string","example":"attachment; filename=\"ctenifaktur_12345678_2026-07-29.pohoda.xml\""}}},"content":{"application/xml":{"schema":{"type":"string","format":"binary"}},"application/zip":{"schema":{"type":"string","format":"binary"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/MixedAccountingUnits"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/accounting-units":{"get":{"tags":["Účetní jednotky"],"summary":"Seznam účetních jednotek","description":"Volitelné. Nahrát jde i bez jednotky, doklad pak zůstane nezařazený a přiřadíte ho v aplikaci. Když ho chcete zařadit rovnou, id jednotky zjistíte jenom tady. Vrací jen jednotky, na které dosáhne tvůrce klíče.","operationId":"listAccountingUnits","responses":{"200":{"description":"Seznam jednotek.","headers":{"X-RateLimit-Limit":{"description":"Strop požadavků na klíč a minutu.","schema":{"type":"integer","example":60}},"X-RateLimit-Remaining":{"description":"Kolik požadavků v aktuálním okně zbývá.","schema":{"type":"integer","example":59}},"X-RateLimit-Reset":{"description":"Unixový čas (v sekundách), kdy se okno resetuje.","schema":{"type":"integer","example":1785312000}}},"content":{"application/json":{"schema":{"type":"object","required":["accountingUnits"],"properties":{"accountingUnits":{"type":"array","items":{"$ref":"#/components/schemas/AccountingUnit"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/openapi.json":{"get":{"summary":"Tento dokument","description":"Bez autentizace: specifikaci potřebujete dřív, než máte klíč. `?lang=en` vrátí anglickou verzi.","operationId":"getOpenApiDocument","security":[],"parameters":[{"name":"lang","in":"query","required":false,"schema":{"type":"string","enum":["cs","en"]},"description":"Jazyk popisků. Výchozí je čeština."}],"responses":{"200":{"description":"OpenAPI dokument.","content":{"application/json":{"schema":{"type":"object"}}}}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"API klíč `cf_live_…` ze sekce API klíče na stránce Tým a nastavení."}},"responses":{"BadRequest":{"description":"Neplatný požadavek.","headers":{"X-RateLimit-Limit":{"description":"Strop požadavků na klíč a minutu.","schema":{"type":"integer","example":60}},"X-RateLimit-Remaining":{"description":"Kolik požadavků v aktuálním okně zbývá.","schema":{"type":"integer","example":59}},"X-RateLimit-Reset":{"description":"Unixový čas (v sekundách), kdy se okno resetuje.","schema":{"type":"integer","example":1785312000}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"invalid_request","message":"Popis chyby v češtině."}}}}},"Unauthorized":{"description":"Chybějící nebo neplatný klíč.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"missing_credentials","message":"Popis chyby v češtině."}}}}},"InsufficientCredits":{"description":"Nedostatek kreditů ani volných dokumentů v tarifu.","headers":{"X-RateLimit-Limit":{"description":"Strop požadavků na klíč a minutu.","schema":{"type":"integer","example":60}},"X-RateLimit-Remaining":{"description":"Kolik požadavků v aktuálním okně zbývá.","schema":{"type":"integer","example":59}},"X-RateLimit-Reset":{"description":"Unixový čas (v sekundách), kdy se okno resetuje.","schema":{"type":"integer","example":1785312000}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"insufficient_credits","message":"Popis chyby v češtině."}}}}},"Forbidden":{"description":"Klíč nemá potřebné oprávnění nebo přístup k jednotce, případně je kancelář na tarifu zdarma.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"plan_required","message":"Popis chyby v češtině."}}}}},"NotFound":{"description":"Nenalezeno. Odpověď je stejná i pro cizí záznam, aby neprozradila, že existuje.","headers":{"X-RateLimit-Limit":{"description":"Strop požadavků na klíč a minutu.","schema":{"type":"integer","example":60}},"X-RateLimit-Remaining":{"description":"Kolik požadavků v aktuálním okně zbývá.","schema":{"type":"integer","example":59}},"X-RateLimit-Reset":{"description":"Unixový čas (v sekundách), kdy se okno resetuje.","schema":{"type":"integer","example":1785312000}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"not_found","message":"Popis chyby v češtině."}}}}},"IdempotencyConflict":{"description":"Dva různé důvody, které jde odlišit podle `code`. `idempotency_conflict`: klíč už byl použit pro JINÝ požadavek, opakovat nemá smysl, použijte nový klíč. `idempotency_in_progress`: stejný požadavek právě probíhá, zkuste to za okamžik znovu.","headers":{"X-RateLimit-Limit":{"description":"Strop požadavků na klíč a minutu.","schema":{"type":"integer","example":60}},"X-RateLimit-Remaining":{"description":"Kolik požadavků v aktuálním okně zbývá.","schema":{"type":"integer","example":59}},"X-RateLimit-Reset":{"description":"Unixový čas (v sekundách), kdy se okno resetuje.","schema":{"type":"integer","example":1785312000}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"idempotency_conflict","message":"Popis chyby v češtině."}}}}},"FileTooLarge":{"description":"Soubor přesahuje limit.","headers":{"X-RateLimit-Limit":{"description":"Strop požadavků na klíč a minutu.","schema":{"type":"integer","example":60}},"X-RateLimit-Remaining":{"description":"Kolik požadavků v aktuálním okně zbývá.","schema":{"type":"integer","example":59}},"X-RateLimit-Reset":{"description":"Unixový čas (v sekundách), kdy se okno resetuje.","schema":{"type":"integer","example":1785312000}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"file_too_large","message":"Popis chyby v češtině."}}}}},"UnsupportedFileType":{"description":"Nepodporovaný formát souboru.","headers":{"X-RateLimit-Limit":{"description":"Strop požadavků na klíč a minutu.","schema":{"type":"integer","example":60}},"X-RateLimit-Remaining":{"description":"Kolik požadavků v aktuálním okně zbývá.","schema":{"type":"integer","example":59}},"X-RateLimit-Reset":{"description":"Unixový čas (v sekundách), kdy se okno resetuje.","schema":{"type":"integer","example":1785312000}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"unsupported_file_type","message":"Popis chyby v češtině."}}}}},"MixedAccountingUnits":{"description":"Doklady patří k různým účetním jednotkám, nebo jsou bez jednotky a patří různým firmám. Rozdělte je podle `accountingUnitId` a `ico` z `details.documents[]` a exportujte po skupinách.","headers":{"X-RateLimit-Limit":{"description":"Strop požadavků na klíč a minutu.","schema":{"type":"integer","example":60}},"X-RateLimit-Remaining":{"description":"Kolik požadavků v aktuálním okně zbývá.","schema":{"type":"integer","example":59}},"X-RateLimit-Reset":{"description":"Unixový čas (v sekundách), kdy se okno resetuje.","schema":{"type":"integer","example":1785312000}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"mixed_accounting_units","message":"Popis chyby v češtině."}}}}},"RateLimited":{"description":"Překročen limit požadavků.","headers":{"X-RateLimit-Limit":{"description":"Strop požadavků na klíč a minutu.","schema":{"type":"integer","example":60}},"X-RateLimit-Remaining":{"description":"Kolik požadavků v aktuálním okně zbývá.","schema":{"type":"integer","example":59}},"X-RateLimit-Reset":{"description":"Unixový čas (v sekundách), kdy se okno resetuje.","schema":{"type":"integer","example":1785312000}},"Retry-After":{"description":"Sekundy do konce okna.","schema":{"type":"integer","example":42}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"rate_limited","message":"Překročen limit 60 požadavků za minutu. Zkuste to znovu za 42 s."}}}}},"InternalError":{"description":"Chyba na naší straně.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"ServiceUnavailable":{"description":"Dočasná nedostupnost databáze. S hlavičkou `Retry-After` je požadavek bezpečné zopakovat; bez ní mohl proběhnout, takže opakování u nahrávání může znamenat druhý doklad.","headers":{"Retry-After":{"description":"Sekundy do dalšího pokusu. Přítomna jen tehdy, když je opakování bezpečné.","schema":{"type":"integer","example":15}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","enum":["missing_credentials","invalid_key","plan_required","insufficient_scope","forbidden","not_found","invalid_request","mixed_accounting_units","insufficient_credits","file_too_large","unsupported_file_type","too_many_files","rate_limited","idempotency_conflict","idempotency_in_progress","service_unavailable","internal_error"],"description":"Stabilní strojový kód. Větvete na něj, ne na `message`."},"message":{"type":"string","description":"Český text pro člověka. Může se změnit, nevětvete na něj."},"details":{"description":"Volitelný rozpad podle druhu chyby, například seznam nenalezených id nebo souborů s nepodporovaným formátem."}}}}},"AccountingUnit":{"type":"object","required":["id","name","ico","dic","vatPayer","accountingSystem"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"ico":{"type":"string","description":"IČO."},"dic":{"type":"string","nullable":true,"description":"DIČ."},"vatPayer":{"type":"string","enum":["yes","no","unknown","identified"]},"accountingSystem":{"type":"string","nullable":true,"enum":["pohoda","money-s3","money-s4-s5","abra-gen","abra-flexi","mrp-ks","mrp-vs","kastner-stereo","ucto-tichy","duel","premier","aconto","other",null]}}},"CreateUploadRequest":{"type":"object","required":["files"],"properties":{"accountingUnitId":{"type":"string","description":"Volitelné. Klíč omezený na podmnožinu jednotek musí jednotku uvést a musí na ni dosáhnout."},"files":{"type":"array","minItems":1,"maxItems":300,"items":{"type":"object","required":["fileName","contentType","sizeBytes"],"properties":{"fileName":{"type":"string","minLength":1,"maxLength":255},"contentType":{"type":"string","description":"PDF, obrázek (PNG, JPEG, WEBP, HEIC, TIFF) nebo strukturovaná faktura ISDOC / XML. U strukturované faktury musí mít `fileName` příponu `.isdoc` nebo `.xml`; podle ní se pozná a zpracuje se rovnou, bez AI. U ostatních typů může být název i bez přípony, ale když ji má, musí sedět s `contentType`: `scan.png` ohlášený jako `application/pdf` odmítneme, protože zpracování se řídí ohlášeným typem."},"sizeBytes":{"type":"integer","minimum":1,"maximum":26214400},"sha256":{"type":"string","pattern":"^[0-9a-fA-F]{64}$","description":"Volitelné. Slouží jen ke kontrole integrity po stažení; bez něj se tahle kontrola vynechá a nic dalšího se nemění."}}}}}},"CreateUploadResponse":{"type":"object","required":["batchId","uploads"],"properties":{"batchId":{"type":"string"},"uploads":{"type":"array","items":{"type":"object","required":["uploadId","fileName","uploadUrl","expiresAt"],"properties":{"uploadId":{"type":"string","description":"Označuje **nahrání**, ne doklad. Jedno nahrání může dát více dokladů; jejich id vrátí `GET /batches/{id}`."},"fileName":{"type":"string"},"uploadUrl":{"type":"string","format":"uri","description":"Pošlete sem bajty prostým `PUT`, bez hlaviček."},"expiresAt":{"type":"string","format":"date-time"}}}}}},"DocumentStatus":{"type":"string","enum":["pending","processing","completed","failed"]},"DocumentMetadata":{"type":"object","required":["id","fileName","status","accountingUnitId","createdAt","availableFormats"],"properties":{"id":{"type":"string"},"fileName":{"type":"string"},"status":{"$ref":"#/components/schemas/DocumentStatus"},"accountingUnitId":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"},"availableFormats":{"type":"array","items":{"type":"string","enum":["isdoc","pohoda","money-s3"]},"description":"Formáty, které má u tohoto dokladu smysl zkusit. Prázdné pole znamená, že neprojde žádný, takže doklad můžete rovnou přeskočit. Je to předběžná kontrola, ne záruka: export si doklad prověřuje sám a může ho odmítnout i tak, vždy s vysvětlením, co mu chybí."}}},"BatchStatus":{"type":"object","required":["id","status","accountingUnitId","createdAt","updatedAt","completedAt","counts","uploads"],"properties":{"id":{"type":"string"},"status":{"type":"string","enum":["pending","processing","completed","completed_with_failures","failed"]},"accountingUnitId":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"completedAt":{"type":"string","format":"date-time","nullable":true},"counts":{"type":"object","required":["total","pending","processing","completed","failed"],"properties":{"total":{"type":"integer"},"pending":{"type":"integer"},"processing":{"type":"integer"},"completed":{"type":"integer"},"failed":{"type":"integer"}}},"uploads":{"type":"array","description":"V pořadí, ve kterém byly soubory poslány.","items":{"type":"object","required":["uploadId","fileName","status","documentIds"],"properties":{"uploadId":{"type":"string"},"fileName":{"type":"string"},"status":{"$ref":"#/components/schemas/DocumentStatus"},"documentIds":{"type":"array","items":{"type":"string"},"description":"Použitelné doklady, které z tohoto nahrání vznikly. Prázdné, dokud nahrání neskončí; více než jedno id znamená rozpoznané rozdělení vícedokladového souboru. Doklad, ze kterého se nepodařilo nic vytěžit, tady není, protože by ho export odmítl."},"incomplete":{"type":"object","required":["discarded","unparsed"],"description":"Jen když nahrání skončilo a vzniklo z něj méně, než soubor obsahoval. Když pole chybí, nic se neztratilo. `discarded`: doklady, které se v souboru rozpoznaly, ale nezpracovaly, protože došly kredity nebo soubor přesáhl limit na jedno nahrání. Nejsou zaplacené ani uložené, získáte je opětovným nahráním souboru. `unparsed`: doklady, které vznikly, ale nepodařilo se z nich nic vytěžit. V `documentIds` nejsou a export je odmítne, doplnit je jde v aplikaci.","properties":{"discarded":{"type":"integer"},"unparsed":{"type":"integer"}}},"errorCode":{"type":"string","enum":["source_missing","source_rejected","processing_failed","upload_not_received"],"description":"Jen u `failed`. `upload_not_received`: bajty nikdy nedorazily do S3. `source_missing`: nahraný soubor se nepodařilo stáhnout. `source_rejected`: soubor je nepoužitelný (nad limit, nesedí otisk). Opakovat stejný soubor nemá smysl. `processing_failed`: vytěžení selhalo."}}}}}},"ExportRequest":{"type":"object","required":["documentIds","format"],"properties":{"documentIds":{"type":"array","minItems":1,"maxItems":500,"items":{"type":"string"},"description":"Doklady jedné účetní jednotky, u nezařazených dokladů jedné firmy. Duplicity se ignorují."},"format":{"type":"string","enum":["isdoc","pohoda","money-s3"]}}}}}}