Robustní KSeF integrace: proč většina napojení selže a jak to udělat pořádně
KSeF není jen HTTP volání. Je to asynchronní, rate-limited státní systém, který občas spadne. Jak postavit integraci, která neztratí ani jednu fakturu.
Od 1. února 2026 je KSeF (Krajowy System e-Faktur) v Polsku povinný pro velké plátce, od 1. dubna 2026 pro ostatní plátce DPH. Rok 2026 je sice grace period bez pokut, ale od 1. ledna 2027 přichází tvrdé vynucování. A právě tady se ukáže rozdíl mezi integrací, která „nějak funguje", a integrací, která vydrží.
Většina napojení na KSeF, která vidíme, má stejnou vadu: jsou fire-and-forget. Aplikace pošle fakturu v HTTP requestu a doufá, že to vyšlo. Dokud je státní systém dostupný a rychlý, vypadá to perfektně. Problém přijde první den, kdy KSeF odpoví chybou, timeoutem nebo rate limitem — a faktura tiše zmizí. Nikdo se to nedozví, dokud nepřijde kontrola.
Proč je KSeF těžší, než vypadá
KSeF není běžné REST API. Má čtyři vlastnosti, které dohromady tvoří past:
- Je asynchronní. Odeslání faktury a její potvrzení (UPO) jsou dva různé okamžiky. Mezi nimi musíte stav někde držet.
- Je rate-limited. Při dávkovém odesílání narazíte na limity. Bez fronty a řízení tempa se vám zastaví celá fakturace.
- Občas je nedostupný. Státní systém má výpadky a údržby. Vaše fakturace kvůli tomu nesmí spadnout.
- Má vlastní stav a session. Session má omezenou platnost, tokeny expirují, a cizí SDK do toho přidává své zvláštnosti.
Když systém má dvě nebo více těchto vlastností, nejde o jednoduché volání. Jde o dlouhoběžící stavový workflow — a ten potřebuje úplně jinou architekturu než „zavolej API v controlleru".
Jak to stavíme: durable, ne fire-and-forget
Klíčový princip: každé volání KSeF je durable, idempotentní, perzistovaná jednotka práce. Nikdy ne fire-and-forget, nikdy ne v HTTP requestu. Tady jsou pilíře, na kterých to stojí.
1. Idempotentní odeslání
Každá faktura dostane deterministický idempotency key. Když se odeslání zopakuje (a ono se zopakuje — kvůli retry, restartu, race condition), systém pozná, že tohle už řešil, a nevytvoří duplicitní fakturu. Bez idempotence se z každého retry stane riziko duplicity ve státním systému.
2. Retry s exponenciálním backoffem
Přechodné chyby a timeouty jsou normální, ne výjimka. Místo ručně psané smyčky (kterou vždycky někdo napíše špatně) použijeme retry s exponenciálním backoffem — battle-tested mechanismus, který opakuje s rostoucími rozestupy a nezahltí API, když má problém.
3. Rate limiting jako sdílený stav
Limity KSeF musíte respektovat i ve chvíli, kdy běžíte na více instancích. In-memory počítadlo v jednom procesu nestačí — potřebujete sdílený token-bucket (typicky přes Redis), aby si instance navzájem nepřebíraly kvótu.
4. Reconciliation job
Tohle je díl, který skoro každý vynechá — a je nejdůležitější. Periodický job se ptá: „sedí realita?" Má každá faktura potvrzení? Neuvízla některá ve stavu „pending"? Nevznikl orphan? Bez reconciliation nevíte, jestli to opravdu funguje — jen doufáte.
5. Status polling a UPO
Odeslání je teprve začátek. Sledujeme stav až po UPO (Urzędowe Poświadczenie Odbioru) — oficiální potvrzení, že stát fakturu přijal. Teprve UPO je důkaz. Dokud ho nemáte, faktura není hotová.
6. Audit log a alerting
Každý přechod stavu generuje strukturovaný event. Na terminal-failure a uvíznuté stavy jde alert — dřív, než se z toho stane problém u kontroly. Tiché LogWarning bez alertu je jen odložený dluh.
7. Anti-corruption layer
Cizí KSeF SDK obalíme vlastní vrstvou, aby jeho zvláštnosti — cizí error stringy, číselné kódy, session TTL — neprosakovaly do vaší business logiky. Když se SDK změní, měníte jedno místo, ne celý kód.
Checklist: je vaše KSeF integrace robustní?
Projděte si to upřímně:
- Přežije odeslání faktury restart aplikace uprostřed procesu?
- Co se stane, když KSeF vrátí 500 nebo timeout — dohledáte tu fakturu?
- Máte důkaz (UPO) u každé odeslané faktury, nebo jen předpokládáte, že to prošlo?
- Existuje job, který každý den ověří, že nic neuvízlo?
- Přijde vám alert, když se něco zasekne, nebo to zjistíte až od účetní?
Pokud na některou odpovíte „ne", máte fire-and-forget integraci. Při grace periodu to projde. Od ledna 2027 už ne.
Ověřeno v produkci
Tohle nejsou teorie ze slidu. Pro TrafinOil jsme napojili fakturaci na KSeF a při forenzní recovery obnovili 15 141 chybějících dokumentů, které předchozí fire-and-forget pipeline tiše ztratila. Noční dataloader jsme zkrátili z 20 hodin na 30 minut. Retry, reconciliation a monitoring běží v produkci a hlídají, že se to nestane znovu.
KSeF deadline se blíží. Když to máte udělat, udělejte to tak, aby vám to v lednu 2027 nespadlo. Napište nám — řekneme vám, kde je vaše integrace zranitelná.