Integrations

KSeF retries and idempotency: avoid duplicate invoices

Why you must not blindly retry a timed-out KSeF submission, and the idempotency-key and status-check pattern that prevents duplicate invoices.

Published 3 min readBy Tomek

Overview

Retrying a timed-out KSeF submission blindly can create a duplicate invoice, because the request may have reached KSeF even though you never saw the response. The safe pattern is to attach a stable idempotency key on your side to every submission, check the invoice's status against KSeF before resubmitting, and only resubmit when you are certain no earlier attempt succeeded.

Why timeouts are dangerous

KSeF (Krajowy System e-Faktur) is Poland's national e-invoicing platform run by the Ministry of Finance (Ministerstwo Finansów). When you submit a FA(3) invoice over the network, a timeout is ambiguous: the request may have failed before reaching KSeF, or it may have been accepted and only the response was lost. If you assume the worst and resend the same document, you can end up with two structured invoices for one transaction.

The idempotency-key pattern

The fix is to make each submission identifiable. Attach a stable idempotency key on your side — a unique value derived from your own invoice identifier, recorded in your own request record. The KSeF API itself does not accept a native idempotency-key parameter; the key is client-side bookkeeping that makes each attempt recognisable as the same logical document, not a new one. Generate it once per invoice and reuse it for every retry of that invoice.

Check status before you retry

Before resubmitting anything, ask KSeF for the invoice's current status. If the earlier attempt actually landed, the status will show it, and the correct action is to stop and read the result (the KSeF number and the UPO) instead of sending again. Only when you can confirm no earlier attempt succeeded should you submit a fresh attempt with the same idempotency key.

Backoff, not hammering

When KSeF or your own connection is unavailable, retry with backoff — a short delay that grows with each attempt — rather than firing requests in a tight loop. This gives the platform time to recover and avoids piling load onto a service that is already struggling. A timeout is a signal to slow down and verify, not to resend immediately.

How Notaly handles it

Notaly tracks each invoice through its lifecycle and only promotes it to submitted once KSeF has acknowledged receipt, so the same document is not sent twice. The final result — accepted with a KSeF number and UPO, or rejected with an error code — reaches you through a signed webhook rather than through polling. That removes the retry ambiguity from your integration.

FAQ

Can a timed-out KSeF request still create an invoice? Yes. A timeout means you did not receive the response; the request may still have reached KSeF. Check status before resubmitting.

What is an idempotency key? A stable identifier you attach on your side to each submission, so the same document is never submitted twice by accident.

Disclaimer

Notaly is not a tax, accounting or legal advisor. This article is general information, not tax advice, and may be outdated. You are responsible for your own VAT compliance; confirm with a qualified accountant where required.

Sources

Source: api-test.ksef.mf.gov.pl

Frequently asked questions

Can a timed-out KSeF request still create an invoice?

Yes. A timeout means you did not receive the response; the request may still have reached KSeF. Check the invoice status before resubmitting.

What is an idempotency key?

A stable identifier you attach on your side to each invoice submission, so the same document is never submitted twice by accident.

How does Notaly handle retries?

Notaly tracks each invoice's state and only advances it to submitted once KSeF has acknowledged it, so the same document is not sent twice.

Issue your first KSeF test invoice today

Create a sandbox account: API key in seconds, 3 free test invoices on KSeF TEST, no credit card.