# API Vsechny cesty jsou uvedene relativne. Verejne se volaji s prefixem `/apps/html-to-pdf`, ktery Caddy pred predanim do containeru odstranuje. Odpovedi jsou JSON, vyjimkou je stazeni hotoveho PDF. ## POST /convert Synchronni prevod. Vraci primo `application/pdf`. Urceno pro mensi dokumenty. Pokud konverze presahne `SYNC_TIMEOUT_SECONDS` (vychozi 60 s), job se zrusi a sluzba vrati HTTP 413 s odkazem na asynchronni endpoint. Zruseni se loguje, nikdy nezmizi potichu. Hlavicky odpovedi: | Hlavicka | Vyznam | |---|---| | `X-Page-Count` | pocet stranek vysledku | | `X-Engine-Used` | engine, ktery dokument vyrenderoval | | `X-Missing-Assets` | pocet assetu, ktere se nepodarilo nacist | | `X-Warnings` | pocet varovani | Pokud je `X-Missing-Assets` nenulovy, v PDF neco chybi. Detaily jsou dostupne jen u asynchronni cesty, kde se vraci cely seznam. ## POST /jobs Zaradi konverzi do fronty. Vraci HTTP 202. ```json { "job_id": "1f0e...", "status": "queued", "created_at": "2026-08-27T10:00:00Z", "result_url": "/apps/html-to-pdf/jobs/1f0e.../result" } ``` ## GET /jobs/{job_id} Stav jobu. ```json { "job_id": "1f0e...", "status": "running", "created_at": "2026-08-27T10:00:00Z", "started_at": "2026-08-27T10:00:01Z", "finished_at": null, "expires_at": null, "progress": { "pages_rendered": 420, "chunks_done": 9, "chunks_total": 21, "pass_number": 1 }, "engine_used": null, "page_count": null, "missing_assets": [], "warnings": [], "error": null, "result_url": null } ``` Stavy: `queued`, `running`, `done`, `failed`, `cancelled`, `expired`. Pole `pass_number` rozlisuje prvni a druhy pruchod. Druhy pruchod nastava jen tehdy, kdyz se generuje obsah se skutecnymi cisly stranek, takze u takoveho dokumentu ukazatel postupu probehne dvakrat. ## GET /jobs/{job_id}/result Stahne hotove PDF. Soubor se streamuje, nenacita se cely do pameti. - 404 job neexistuje nebo uz expiroval - 409 job jeste nedobehl nebo skoncil chybou ## DELETE /jobs/{job_id} Zrusi bezici job nebo smaze hotovy vysledek. ## GET /health Stav sluzby, verze, dostupnost enginu a stav fronty. U Chromia se dostupnost overuje skutecnym nastartovanim prohlizece. `status` je `ok`, pokud je k dispozici alespon jeden engine, jinak `degraded`. ## GET /version Nazev aplikace, verze a aktualni `root_path`. ## GET /docs Swagger UI. OpenAPI dokument obsahuje `servers` s prefixem `/apps/html-to-pdf`, takze tlacitko Try it out vola spravnou verejnou cestu. ## Telo requestu Stejne pro `/convert` i `/jobs`. Povinne je pouze `source`, vsechno ostatni ma pouzitelnou vychozi hodnotu. ```json { "source": { "url": "https://example.com/dokument.html", "html": null, "base_url": null }, "engine": "auto", "page": { "format": "A4", "orientation": "portrait", "margin": { "top": "20mm", "right": "15mm", "bottom": "20mm", "left": "15mm" } }, "page_numbers": { "enabled": false, "format": "{page} / {pages}", "position": "bottom-center", "mode": "auto", "start_at": 1 }, "toc": { "enabled": false, "depth": 3, "title": "Obsah" }, "outline": true, "pdf_profile": null, "assets": { "allow_remote": true, "timeout_seconds": 10 }, "chunking": { "enabled": true, "pages_per_chunk": 50 }, "wait_for": { "state": "load", "selector": null, "timeout_seconds": 30 }, "filename": null, "callback_url": null } ``` ### source Vyplnene musi byt prave jedno z poli `url` a `html`, jinak sluzba vraci 422. `base_url` slouzi k rozpadu relativnich cest a pouziva se hlavne spolu s `html`. Pri pouziti `url` se `base_url` odvodi z finalni adresy po presmerovanich. ### engine - `weasyprint` spravne strankovani, nizka pametova narocnost, nespousti JavaScript - `chromium` zvladne i dokumenty dokreslovane JavaScriptem - `auto` zvoli chromium, pokud dokument obsahuje aktivni skripty, jinak weasyprint. Pokud render pres weasyprint selze, sluzba to zaloguje a zopakuje ho pres chromium, coz se objevi ve `warnings`. ### page.format Nazev formatu (`A4`, `A5`, `Letter`) nebo explicitni rozmer (`210mm 297mm`). U nazvu se uplatni i `orientation`, u explicitniho rozmeru je orientace dana poradim hodnot. ### page_numbers.mode - `css` cislovani resi CSS countery pri renderu. Nejhezci vysledek, ale funguje jen kdyz se cely dokument renderuje najednou, protoze v kazde casti se citac stranek restartuje. Vyzaduje `engine: weasyprint` a `chunking.enabled: false`, jinak sluzba vraci 400 s kodem `unsupported_combination`. - `overlay` cisla se dopisi do hotoveho PDF jako pruhledna vrstva. Jedina moznost u clenenych dokumentu a u Chromia. - `auto` zvoli `css` u necleneneho dokumentu renderovaneho WeasyPrintem, jinak `overlay`. Cislovaci vrstvu kresli WeasyPrint i tehdy, kdyz dokument vyrenderovalo Chromium. Bez nainstalovaneho WeasyPrintu proto cislovani stranek nefunguje. ### toc Generuje obsah s odkazy a skutecnymi cisly stranek. Vyzaduje `engine: weasyprint`, protoze Chromium neumi rict, na ktere strance nadpis skoncil. Pri jine kombinaci sluzba vraci 400. Nadpisy bez atributu `id` ho dostanou automaticky. Pokud je dokument rozdelen na casti, odkazy v obsahu nejsou klikatelne, protoze cil lezi v jine casti. Cisla stranek jsou spravna. Sluzba na to upozorni ve `warnings`. ### outline Zalozky PDF generovane z nadpisu h1 az h6. Vypnuti se resi CSS pravidlem `bookmark-level: none`, takze funguje i uvnitr jednotlivych casti. ### pdf_profile Predava se WeasyPrintu jako `pdf_variant`. Povolene hodnoty: `pdf/a-1b`, `pdf/a-2b`, `pdf/a-3b`, `pdf/a-4b`, `pdf/ua-1`. ### assets `allow_remote: false` zakaze stahovani externich assetu. Nedostupne assety render nezastavi, ale objevi se v `missing_assets` a v logu. ### chunking `pages_per_chunk` je cilova velikost casti. Skutecny pocet stranek je znamy az po renderu, deleni proto vychazi z odhadu podle mnozstvi textu, obrazku a radku tabulek. Rez vznika vzdy jen mezi primymi potomky kontejneru, takze tabulka ani odstavec se nikdy nerozdeli. Delici body jsou elementy `section`, `article`, `h1`, elementy s atributem `data-chunk` a elementy se stylem obsahujicim `page-break-before` nebo `break-before`. Pokud dokument zadny takovy nema, renderuje se vcelku a sluzba to zaloguje. ### wait_for Pouziva jen Chromium. `state` je `load`, `domcontentloaded` nebo `networkidle`, `selector` navic ceka na konkretni element. ### callback_url Po dokonceni nebo selhani jobu na nej sluzba posle POST se stejnym telem, jake vraci `GET /jobs/{job_id}`. Neuspech se loguje a nekolikrat zopakuje, job se kvuli nemu neoznaci jako failed. ## Chyby ```json { "error_code": "blocked_target", "message": "Cilova adresa smeruje do privatniho nebo vyhrazeneho rozsahu a je zablokovana.", "detail": { "url": "http://127.0.0.1/a.html", "host": "127.0.0.1" } } ``` | error_code | HTTP | Kdy nastane | |---|---|---| | `invalid_request` | 400 | chybny vstup | | `blocked_target` | 400 | adresa smeruje do zakazaneho rozsahu nebo ma nepovolene schema | | `unsupported_combination` | 400 | nepodporovana kombinace parametru, napriklad obsah s Chromiem | | `limit_exceeded` | 400 | prekrocen nakonfigurovany limit | | `source_unavailable` | 502 | zdrojovy dokument se nepodarilo stahnout | | `render_timeout` | 504 | render presahl casovy limit | | `sync_too_long` | 413 | synchronni konverze presahla limit, pouzijte POST /jobs | | `engine_unavailable` | 503 | pozadovany engine neni k dispozici | | `queue_full` | 503 | fronta je plna | | `job_not_found` | 404 | job neexistuje nebo expiroval | | `result_not_ready` | 409 | job jeste nedobehl | | `service_restarted` | v tele jobu | sluzba se restartovala drive, nez job dobehl | | `internal_error` | 500 | neocekavana chyba |