ksef2Open source, MIT

Typed Python for KSeF 2.0 invoicing.

ksef2 takes care of authentication, sessions, encryption and polling, so your integration reads like the workflow itself: sign in, send FA(3) invoices, download what KSeF returns.

pip install ksef2

Python 3.12 or newer. The CLI installs separately with uv tool install ksef2-cli

send_invoice.py
from pathlib import Path

from ksef2 import Client, Environment, FormSchema

client = Client(Environment.TEST)
auth = client.authentication.with_test_certificate(
    nip="5261040828",
)

with auth.online_session(form_code=FormSchema.FA3) as session:
    status = session.send_invoice(
        Path("invoice.xml").read_bytes()
    ).wait(timeout=60.0)

invoice_xml = auth.invoices.download(status.ksef_number)
print(status.ksef_number)

Everything between your system and KSeF.

The client is organised by task. Authenticate once, and the authenticated client exposes the branch that owns each job — every one of them has its own how-to guide.

2.8.1
KSeF OpenAPI version the SDK targets
83 / 83
API endpoints covered, checked daily against the published spec
sync + async
Client and AsyncClient share the same branches and method names
  • Authentication

    SDK-generated TEST certificates, KSeF tokens, XAdES certificates issued by MCU, or a profile shared with ksef2-cli.

    • with_test_certificate
    • with_token
    • with_xades
    • with_profile
  • Online and batch sessions

    Send FA(3) XML one invoice at a time or as a batch package, wait for processing and collect the UPO.

    • online_session
    • batch_session
    • invoice_sessions.download_upo
  • Query, download, export

    Filter invoice metadata, page through results, download a single invoice by KSeF number or schedule encrypted export packages.

    • invoices.search
    • invoices.download
    • invoices.export
  • FA(3) builder

    Build sendable FA(3) XML with a fluent, typed builder instead of hand-writing XML. Drafts can be saved and resumed.

    • FA3InvoiceBuilder
    • to_xml
  • Administration

    Generate and revoke tokens, grant and query permissions, enroll certificates, and read or override limits.

    • tokens
    • permissions
    • certificates
    • limits
  • Low-level API

    Schema-native endpoint wrappers for when you need custom signing, your own encryption custody or raw payloads for debugging.

    • client.raw
    • auth.raw
    • ksef2.raw.spec
Build FA(3) invoices in Pythonksef2.fa3
builder = (
    FA3InvoiceBuilder()
    .header(system_info="my app")
    .seller(
        name="ACME S.A.",
        tax_id="1234567890",
        country_code="PL",
        address_line_1="ul. Przykladowa 123",
    )
    .buyer(
        name="XYZ GmbH",
        country_code="DE",
        address_line_1="Unter den Linden 1",
    )
    .standard()
        .issue_place("Warszawa")
        .issue_date(date(2026, 3, 29))
        .invoice_number("FV/2026/03/0001")
        .rows()
            .add_line(
                name="Consulting service",
                supply_date=date(2026, 3, 29),
                unit_of_measure="h",
                quantity=Decimal("10"),
                unit_price_net=Decimal("100.00"),
                vat_rate=VatRate.VAT_23,
            )
        .done()
    .done()
)

xml_text = builder.to_xml()
Open the builder guide

One invoice, start to finish.

The same four steps, whether you write Python or drive KSeF from a shell script or CI job.

  1. 01

    Authenticate

    Pick the method that fits the environment. Secrets stay in environment variables.

    SDK

    login = client.authentication
    auth = login.with_token(
        ksef_token=token,
        nip="5261040828",
    )

    CLI

    ksef2 --profile test-company \
      auth login
  2. 02

    Open a session

    Online for single invoices, batch for many. The session closes itself when the block ends.

    SDK

    with auth.online_session(
        form_code=FormSchema.FA3,
    ) as session:

    CLI

    ksef2 invoices send \
      invoice-1.xml invoice-2.xml \
      --mode batch
  3. 03

    Send and wait

    No hand-written polling loops: wait for KSeF to process the invoice and assign its number.

    SDK

    status = session.send_invoice(
        xml,
    ).wait(timeout=60.0)

    CLI

    ksef2 invoices send \
      invoice.xml --wait
  4. 04

    Download and keep the UPO

    Fetch the invoice XML and the official receipt, now or later from a saved receipt.

    SDK

    auth.invoices.download(
        status.ksef_number,
    )

    CLI

    ksef2 invoices upo \
      --receipt invoice-receipt.json

Start with the docs.

The SDK and the CLI are documented here, in English and Polish.

ksef2 is community-maintained by Stacking. It is not published, endorsed or supported by Poland's Ministry of Finance, and the official KSeF documentation remains the source of truth for API behaviour. Official KSeF API documentation