KSeF and Dynamics 365 Business Central: how to connect them
How to actually connect KSeF to Dynamics 365 Business Central — invoice mapping, durable submit, status polling, UPO back into BC, reconciliation, and outage handling. Tested on 40,000+ documents in production.
KSeF and Dynamics 365 Business Central — a sentence that sounds simple. Connect the ERP to the government system, invoices go out, done. In practice it does not work that way.
We built the invoicing connection to KSeF in an environment where Business Central was the primary system for issuing invoices. Below I describe what you have to solve and where it actually breaks down. If you are looking for someone to do this, we do it.
Why BC + KSeF is not just configuration
Business Central is a heavyweight ERP with a mature invoicing module. KSeF is an asynchronous, rate-limited government system with its own state. Put them together and you get friction points that no Marketplace configurator will fully resolve.
Three things that complicate it:
KSeF is asynchronous. You send an invoice, you get a reference number. The confirmation (UPO) arrives later — minutes, sometimes longer. Between submission and UPO you have to persist and track the state somewhere.
BC has its own invoice state machine. Posted Invoice, Sent, Cancelled — these states have to stay in sync with what KSeF says. When states diverge, accountants cannot tell what has been invoiced and what has not.
KSeF rate limits are real. Batch-processing a larger volume and you will hit them. Without throttling you will stall the entire invoicing pipeline halfway through the month.
Integration architecture
An integration that does not fall over rests on several pillars. I describe them in the order you will encounter them.
1. BC → KSeF format mapping
Business Central stores data in a different structure than KSeF FA(2) XML. The mapping is not trivial.
What you have to solve:
- Counterparty identifiers (NIP, VAT number) — BC may hold them in multiple places; KSeF accepts one specific format
- Invoice number series — KSeF has its own numbering logic, BC has its own; you have to decide which is authoritative and how to inform the other system
- Invoice types — sales, credit, prepayment; each has different mandatory fields
- Rounding and VAT rates — BC calculates tax its way; KSeF requires values to a specific number of decimal places
The mapping is a living source of truth, not a one-off script. It changes with legislation.
2. Durable submit with idempotency key
The biggest mistake I see in existing integrations: an HTTP request calls the KSeF API directly from a BC event handler. When the request fails — timeout, 503, server restart — the invoice either does not register or registers twice.
Every invoice submission to KSeF must be:
- Persisted — written to a queue before sending, not after
- Idempotent — a deterministic key derived from the invoice number in BC; KSeF will reject it if an invoice with this key already exists
- Retryable — when it fails, retry runs again without side effects
In .NET we handle this via Hangfire or a similar job scheduler — not a background service with an in-memory queue, because that does not survive a restart.
3. Status polling and UPO back into BC
You sent the invoice. KSeF returned a reference number. Now you have to track status until UPO arrives.
UPO (Urzędowe Poświadczenie Odbioru) is the only proof that the government accepted the invoice. Without UPO the invoice is not done, regardless of what BC says.
Polling must:
- Respect KSeF rate limits (not call every second)
- Use exponential backoff on errors
- Update the record in BC once UPO arrives — KSeF number, acceptance date, link to the UPO document
- Alert when an invoice is stuck longer than the expected maximum
We store UPO back into BC as an attachment or in a dedicated table. Accountants need the proof accessible directly in the ERP, not in an external system.
4. Reconciliation
Almost everyone skips this step. It is the most important one.
Once a day (or more often) you run a job that compares:
- Invoices in BC with status "sent to KSeF"
- Invoices for which we have UPO
- Invoices for which UPO is missing or status is unknown
If you find a discrepancy, you want to know before the customer or auditor does. The reconciliation job is the safety net that ensures fire-and-forget errors do not get silently buried in the data.
5. Outage handling and test environments
KSeF has test and production environments. Switching between them must be configurable without rewriting code.
The KSeF test environment behaves differently from production — different limits, different response times, sometimes different error codes. The architecture must absorb these differences, not expose them into business logic.
Production KSeF outages are real. The integration must:
- Detect the outage (distinguish "KSeF unavailable" from "my invoice has an error")
- BC invoicing continues normally — invoices accumulate in the queue
- Once availability is restored, the queue drains automatically, in order, without duplicates
Where it actually breaks down
From experience: most time gets spent on these.
Number series. BC has its own invoice number series. KSeF assigns its own numbers. Mapping both series so the accountant does not lose their mind requires careful design.
Credit notes. Credit notes and corrective invoices have a different format in KSeF and different mandatory fields. You have to map the reference to the original invoice — including cases where the original invoice existed in the system before the integration was launched.
Retry without duplicates. Retry logic must be correctly set up on both the BC and KSeF sides. A simple retry without an idempotency key creates duplicate invoices in the government system — and cancelling them is extra work.
Monitoring for accountants. Technical logs are not enough. Accountants need to see the status of each invoice in terms they understand: sent, awaiting confirmation, confirmed, rejected. You have to build this on top of the technical state machine.
Production numbers
In the systems where we built these integrations, they have processed over 40,000 documents in production. 100% delivered with UPO. No lost invoice, no duplicate.
That is not a number from a presale slide deck. It is the result of an architecture that accounts for KSeF being occasionally slow, occasionally unavailable, and the network being unreliable.
How we can help
I build KSeF to Business Central connections as custom integrations. The deliverable includes:
- BC → KSeF format mapping for your invoice types
- Submit pipeline with idempotency key and retry
- Status polling with UPO back into BC
- Reconciliation job
- Invoice status dashboard for accountants
- Test / production environment switching
If you have an existing integration and want an audit, I can do that. If you are building a new one, start right.
Get in touch — we will tell you what your specific BC setup requires.
FAQ
Does KSeF integration work as a standard BC extension from the Marketplace?
A Marketplace extension can cover a basic scenario if you have standard invoices and do not expect outages. Once volume increases, non-standard invoice types appear, or you need reconciliation, you will find the extension has fixed limitations. A custom integration gives full control over every step.
How long does implementation take?
It depends on the scope of your invoicing process. A basic connection (submit + UPO) is a matter of weeks. With reconciliation, a dashboard, and edge case handling, count on 6–10 weeks. I can give a more precise estimate after analysing your BC setup.
Do we need our own .NET infrastructure, or can it work differently?
The integration runs as a standalone service outside BC. You do not need to change BC code. You need an environment where a .NET background service and job scheduler can run — cloud (Azure, AWS) or on-premise. If you have BC in the Microsoft cloud, we handle it as a separate microservice with an API connection to BC.