GitHub

Invoice lifecycle

Understand how an invoice moves from XML submission to KSeF number, metadata, download, and UPO.

On this page

In KSeF, sending an invoice is the start of processing, not the final outcome. The API first accepts encrypted invoice data into a session. KSeF then validates and processes that invoice asynchronously.

The SDK reflects that model: sending returns a processing handle first. A KSeF number, metadata visibility, invoice download, and UPO come later.

FA(3) XML
  -> online or batch session
    -> invoice reference number
      -> KSeF processing
        -> KSeF number
          -> metadata, download, UPO
        -> failed invoice status
text

The stages

  1. Prepare valid invoice XML.

    The SDK can send bytes from a file or bytes generated by the FA(3) builder.

  2. Submit the XML through an online or batch session.

    Online sessions send one invoice at a time. Batch sessions upload a prepared ZIP package and expose per-invoice results after package processing.

  3. Store the returned references.

    The invoice reference number is the first durable handle for a submitted invoice. The session reference tells KSeF where that invoice was submitted.

  4. Poll the session or invoice status.

    A successful HTTP response does not mean the invoice has a KSeF number yet.

  5. Use the final identifiers for retrieval and audit.

    After successful processing, the KSeF number becomes the stable identifier for direct download, reconciliation, metadata lookup, and many support workflows.

Send is not acceptance

send_invoice() encrypts the XML and submits it into an open online session. It returns an invoice reference_number.

send_invoice() returns an InvoiceSubmission handle. Its wait() polls the invoice status until KSeF assigns a ksef_number, reaches a failed terminal status, or the local timeout expires.

submission = session.send_invoice(xml_bytes)
print(submission.reference_number)

status = session.get_invoice_status(
    invoice_reference_number=sent.reference_number,
)
print(status.status.code, status.ksef_number)
python

Identifiers to keep straight

IdentifierWhere it appearsWhat it is for
Local invoice numberInside the invoice XML and local system.Business correlation before and after KSeF processing.
Session reference numberOpening an online or batch session.Finding the remote sending workflow.
Invoice reference numberResponse from sending, and session invoice status.Polling one invoice and downloading invoice UPO by reference.
Invoice hashSession invoice status and batch preparation.Correlating batch results with local source documents.
KSeF numberSuccessful invoice status and metadata.Stable KSeF identifier for download, reconciliation, and support.
UPO referenceSession status when collective UPO is available.Downloading a UPO page for the session or batch.

For batch sending, the invoice reference number may not be visible until KSeF processes the uploaded package. Keep the prepared batch metadata so the invoice_hash and invoice_file_name can connect KSeF results back to local files.

Metadata and download are later surfaces

Session status tells you what happened to a submission. Metadata and invoice download are retrieval surfaces used after KSeF has processed and materialized the invoice.

Use the surfaces for different jobs:

SurfaceBest question
Session invoice statusDid this submitted invoice get a KSeF number or fail?
Metadata queryWhich processed invoices match these filters, roles, and dates?
Direct invoice downloadGive me the XML for this known KSeF number.
Export packageGive me a larger filtered set of invoice XML files.
UPOGive me official confirmation for the accepted invoice or session.
invoice_xml = auth.invoices.download(status.ksef_number)
print(len(invoice_xml))
python

Dates are not interchangeable

KSeF metadata exposes several dates. Choose the date based on the workflow, not on the label that looks convenient.

DateMeaning
issue_dateDate declared on the invoice document.
invoicing_dateDate KSeF received the invoice for processing.
acquisition_dateDate the invoice became available to a party in KSeF.
permanent_storage_dateDate used by durable storage and incremental export workflows.

For incremental synchronization, prefer the Permanent Storage model described in the querying/export pages. It is designed to avoid missing invoices while KSeF processing is asynchronous.