KSeF hooks: registering and receiving invoices with the Polish KSeF

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.

KSeF outbound hook (outgoing, Podmiot1)

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.

KSeF environments (government)

For testing and acceptance, the Polish government provides two environments in addition to production:

EnvironmentURLDemohttps://ksef-demo.mf.gov.pl/Testhttps://ksef-test.mf.gov.pl/

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.

Prerequisites
  • A valid online certificate for KSeF (.key + .crt; authentication during the online flow)
  • A valid offline certificate for KSeF (.key + .crt; QR codes in the PDF output, both for online and offline processing)
  • The corresponding passwords for both certificates
  • The hook must be activated in the configuration
Workflow

After receiving an invoice notification, the hook goes through seven steps:

StepActionDescription1UploadUploads the invoice package as a batch to KSeF (POST /v2/sessions/batch)2StatusPolls the batch status until processing is complete (GET /v2/sessions/{referenceNumber}/status)3RetrieveInvoicesRetrieves the processed invoice results per page4RetrieveUpoRetrieves the UPO document for the session5PrintGenerates a PDF per document based on UPO data and verification link, and registers it as an attachment6DispatchSends all buffered events in a batch to the Ingestor7FinalizeCleans up the state and closes the session

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.

Configuration

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
}
Parameters
ParameterDescriptiononlineCertificatePath to the online certificate file for authentication with KSeF during the online flowonlineCertificatePasswordThe password for the online certificateofflineCertificatePath to the offline certificate file, used for generating QR codes in the PDF outputofflineCertificatePasswordThe password for the offline certificatetopicsThe topics the hook listens to. Use ClearInvoiceBatched for outgoing invoicesoutputDefines which topic is sent for a given status codeisActiveMust be set to true to activate the hook

Important: 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.

Status codes
CodeDescriptionOutput topic200Invoice successfully registered with KSeF (online)SendInvoice201Invoice successfully registered after offline processingInvoiceCleared410KSeF is offline; offline flow is startedSendInvoice429Temporarily unavailable; retry is automatically scheduledInvoiceClearedRetry500Internal server errorInvoiceClearedError

With 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.

Online vs. offline flow

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):

  • Online: the invoice is directly registered with KSeF, the UPO is retrieved and a PDF with QR codes is generated
  • Offline: the invoice is processed locally, an offline PDF with an Offline QR code is generated via the offline certificate. The invoice is sent to the recipient without having been registered with KSeF yet.

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.

KSeF reference number (clearance)

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.

Batch hook before KSeF (rate limiting)

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
Alternative: no ClearInvoice topic (for example Business Central)

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
}
Frequently asked questions
Why are both an online and an offline certificate required in the init configuration?

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.

What does the PSB do with status code 410 or 429 from KSeF?

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.

Which topic should I set on the hook for outgoing invoices to KSeF?

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


KSeF inbound hook (incoming, Podmiot2)

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.

Workflow per polling cycle
StepActionDescription1FetchQueries KSeF for metadata of new invoices within the time window (POST /v2/invoices/query/metadata). Pagination via HasMore / NextPageOffset (inner loop); truncation via IsTruncated / HwmDate (outer loop) for more than 10,000 items.2ProcessRetrieves the invoice XML per KSeF number (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.3CompleteSaves the checkpoint (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.

Prerequisites for the inbound hook
  • A valid online certificate for KSeF (.key + .crt) plus the corresponding password.
  • The hook must be activated in the configuration.
  • Init fields 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.

Configuration inbound hook

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.

Parameter lookbackWindow

The lookbackWindow parameter determines the time window the hook looks back over when polling/creating:

  • In hours, for example "08:00:00"
  • In days, for example "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.