Configure the KSeF outbound hook for automatic registration of invoices with the Polish e-invoicing system.
The PSB has two KSeF hooks: an outbound hook for outgoing invoices (selling party / Podmiot1) and an inbound hook for incoming invoices (buying party / Podmiot2). Both automate the exchange with the Krajowy System e-Faktur (KSeF), the Polish national e-invoicing system. The outbound hook is described first below; the inbound hook is at the bottom of this page.
The KSeF outbound hook automates the registration of outgoing invoices with KSeF. Invoices are transformed from Peppol BIS Billing 3.0 / UBL to the Polish FA(3) format and registered as a batch. The customer may also supply FA(3) directly, in which case the transformation step is skipped. After successful processing, the hook returns the UPO (Urzędowe Poswiadczenie Odbioru, the official acknowledgement of receipt) and a PDF proof via the PSB platform.
For testing and acceptance, the Polish government provides two environments in addition to production:
The hook supports both an online flow (direct registration) and an offline flow (when KSeF is temporarily unavailable, for example during the daily cutoff). In the offline flow, an offline PDF is generated based on the offline certificate.
.key + .crt; authentication during the online flow).key + .crt; QR codes in the PDF output, both for online and offline processing)After receiving an invoice notification, the hook goes through seven steps:
POST /v2/sessions/batch)GET /v2/sessions/{referenceNumber}/status)When KSeF is unavailable (daily cutoff or outage), the offline flow starts automatically: an offline PDF is generated via the offline certificate, after which the invoice is sent through the regular channel.
Register the hook via the Hooks API:
{
"id": "ksef-sender",
"action": "ksef",
"name": "KSeF Hook Sender",
"topics": [
"ClearInvoiceBatched"
],
"output": [
{
"when": "200",
"topic": "SendInvoice"
},
{
"when": "410",
"topic": "SendInvoice"
}
],
"init": {
"onlineCertificate": "{{path-to-online-certificate}}",
"onlineCertificatePassword": "{{password}}",
"offlineCertificate": "{{path-to-offline-certificate}}",
"offlineCertificatePassword": "{{password}}"
},
"isActive": true
}
onlineCertificateonlineCertificatePasswordofflineCertificateofflineCertificatePasswordtopicsClearInvoiceBatched for outgoing invoicesoutputisActivetrue to activate the hookImportant: All four certificate fields are required. The online certificate is needed for authentication during the online flow. The offline certificate is needed for generating QR codes in the PDF, both during online and offline processing.
200SendInvoice201InvoiceCleared410SendInvoice429InvoiceClearedRetry500InvoiceClearedErrorWith status code 410, the PSB automatically starts the offline flow. The invoice is then processed locally with the offline certificate and sent once KSeF is available again. With 429, the PSB schedules an automatic retry.
KSeF has a daily cutoff period during which the system is unavailable for batch registration. After approximately 23:00 Polish local time, the offline flow kicks in when KSeF is unreachable (status code 410):
After KSeF returns, invoices processed offline are still registered and the invoice receives status code 201 (InvoiceCleared). The invoice is not resent to the recipient; the previously sent Offline QR code points to the confirmed KSeF registration once the later registration is complete.
After online clearance, KSeF returns a reference number. This number appears in the UPO and in the outgoing webhook details, for example:
"details": {
"clearanceReference": "234563218-20260220-50683A000001-11",
"clearanceSystem": "KSeF"
}
Store the reference number in the sending ERP as proof of registration with KSeF.
For high volumes: place a batch hook before the KSeF hook so that invoices are sent periodically (for example every 15 seconds or a maximum of 100 at a time) as a batch to KSeF. This keeps the integration from hitting KSeF rate limits. Topic pattern: ClearInvoice → batch → ClearInvoiceBatched → KSeF hook.
Example batch action (parameters to be tuned per customer):
{
"id": "batchClearInvoice",
"name": "Batch Invoices for KSeF",
"action": "batch://zip?period=00:01:00&maxBatchSize=100&excludePrimaryAttachment=false&includeAdditionalAttachments=true&hashAlgorithm=sha256&includeRefToMetaAttributes=true&targetDocumentTypeId=econnect-docid%3A%3Ahttp%3A%2F%2Fcrd.gov.pl%2Fwzor%2F2025%2F06%2F25%2F13775%3A%3AFaktura%23%23ksef%3A%3A3.0",
"topics": ["ClearInvoice"],
"isActive": true
}
Short action form (same FA(3) target; period for example 00:00:15):
batch://zip?period=00:00:15&maxBatchSize=100&excludePrimaryAttachment=false&includeAdditionalAttachments=true&hashAlgorithm=sha256&includeRefToMetaAttributes=true&targetDocumentTypeId=econnect-docid%3A%3Ahttp%3A%2F%2Fcrd.gov.pl%2Fwzor%2F2025%2F06%2F25%2F13775%3A%3AFaktura%23%23ksef%3A%3A3.0
Some customers cannot send invoices with topic ClearInvoice (for example Business Central). In that case, adjust the batch hook to listen on SendInvoice and still publish ClearInvoiceBatched:
{
"id": "batchClearInvoice",
"name": "Batch Invoices for KSeF",
"action": "batch://zip?period=00:01:00&maxBatchSize=100&excludePrimaryAttachment=false&includeAdditionalAttachments=true&hashAlgorithm=sha256&includeRefToMetaAttributes=true&targetDocumentTypeId=econnect-docid%3A%3Ahttp%3A%2F%2Fcrd.gov.pl%2Fwzor%2F2025%2F06%2F25%2F13775%3A%3AFaktura%23%23ksef%3A%3A3.0",
"topics": ["SendInvoice"],
"output": [
{ "when": "200", "topic": "ClearInvoiceBatched" },
{ "when": "500", "topic": "ClearInvoiceBatchedError" },
{ "when": "429", "topic": "ClearInvoiceBatchedRetry" }
],
"isActive": true
}
The PSB uses the online certificate to authenticate with KSeF during the online registration flow. The offline certificate is needed for QR codes in the PDF output, both during online and offline processing. All four fields (both certificate paths and passwords) must therefore be filled in.
With 410, KSeF is offline (for example during the cutoff period); the PSB starts the offline flow with an offline PDF and then sends via the regular channel. With 429, there is temporarily no capacity; the PSB automatically schedules a retry on InvoiceClearedRetry.
Use ClearInvoiceBatched in topics so that the hook listens to the correct batch notifications. The output object maps HTTP status codes to follow-up topics such as SendInvoice or InvoiceCleared, depending on the registration result.
Want to learn more about e-invoicing in Poland? Read the country page on the Polish KSeF obligation.
View the API documentation
The KSeF inbound hook processes incoming invoices for the buying party (Podmiot2). The hook periodically polls KSeF for new invoices, retrieves the invoice XML per KSeF number and delivers it via the PSB platform.
Authentication towards KSeF is exclusively via an online certificate (.key + .crt + password). The inbound flow has no offline variant, unlike the outbound hook. In the event of temporary KSeF unavailability, polling is retried according to the configured retry policy.
POST /v2/invoices/query/metadata). Pagination via HasMore / NextPageOffset (inner loop); truncation via IsTruncated / HwmDate (outer loop) for more than 10,000 items.GET /v2/invoices/ksef/{ksefNumber}) and uploads it to the DocumentCarrier. Duplicate invoices (HTTP 409) are skipped. After each successful upload the pending key is removed, so the step can be fully resumed on retry.HwmDate ?? ToDate) and schedules the next polling cycle at the next fixed clock slot.If no invoice is found during Fetch, the hook jumps directly to Complete: nothing is processed or published.
onlineCertificate and onlineCertificatePassword are required (no offline certificate fields).The inbound hook is set up via TechSupport: certificate handling is a techsupport-only procedure, not self-service.
The action parameter determines the time window the hook looks back over: ksef:inbound?lookbackWindow=<window>. The init block only contains the online certificate.
Standard (publishes on topic ReceiveInvoice):
{
"id": "ksef-inbound",
"action": "ksef:inbound?lookbackWindow=08:00:00",
"name": "KSeF Hook Inbound",
"publishTopics": ["ReceiveInvoice"],
"init": {
"onlineCertificate": "{{path-to-online-certificate}}",
"onlineCertificatePassword": "{{password}}"
},
"isActive": true
}
A follow-up hook that further processes the received invoice should always follow the inbound hook.
Collabrr platform variant: on the Collabrr platform, the hook listens in the tenant with publishTopics: ["InvoiceReceived"]. The organization must be registered for Peppol receipt on the platform. Example action: ksef:inbound?lookbackWindow=08.00:00:00.
The lookbackWindow parameter determines the time window the hook looks back over when polling/creating:
"08:00:00""60.00:00:00"KSeF limits the lookback to a maximum of 3 months. Exceeding this returns an error:
21405: Błąd walidacji danych wejściowych. - 'dateRange' must not exceed 3 months.
There is also a request rate limit towards KSeF. Take this into account when activating multiple entities with a (large) lookbackWindow.