Skip to content

Sending Invoices

This guide shows how to send invoices to KSEF using the library.

Prerequisites

Before sending invoices, you must be authenticated with KSEF.

from ksef.auth.token import TokenAuthorization
from ksef.client import Client
from ksef.constants import Environment

auth = TokenAuthorization(token="your-token", environment=Environment.TEST)
auth.authorize(nip="1234567890")
client = Client(authorization=auth, environment=Environment.TEST)

Creating an Invoice

First, create an Invoice object with all required data:

from datetime import date, datetime, timezone
from decimal import Decimal

from ksef.models.invoice import (
    Address,
    Invoice,
    InvoiceData,
    InvoiceType,
    Issuer,
    IssuerIdentificationData,
    Subject,
    SubjectIdentificationData,
)
from ksef.models.invoice_annotations import (
    FreeFromVat,
    IntraCommunitySupplyOfNewTransportMethods,
    InvoiceAnnotations,
    MarginProcedure,
    ReverseCharge,
    SelfInvoicing,
    SimplifiedProcedureBySecondTaxPayer,
    SplitPayment,
    TaxSettlementOnPayment,
)
from ksef.models.invoice_rows import InvoiceRow, InvoiceRows

invoice = Invoice(
    # Issuer (seller) information
    issuer=Issuer(
        identification_data=IssuerIdentificationData(
            nip="1234567890",
            full_name="My Company Sp. z o.o.",
        ),
        address=Address(
            country_code="PL",
            city="Warszawa",
            street="Przykładowa",
            house_number="1",
            apartment_number="2A",
            postal_code="00-001",
        ),
        email="contact@example.com",
        phone="+48 123456789",
    ),

    # Recipient (buyer) information
    recipient=Subject(
        identification_data=SubjectIdentificationData(
            nip="0987654321",
        ),
    ),

    # Invoice details
    invoice_data=InvoiceData(
        currency_code="PLN",
        issue_date=date.today(),
        issue_number="FV/2026/001",
        sell_date=date.today(),
        total_amount=Decimal("1230.00"),
        invoice_type=InvoiceType.REGULAR_VAT,

        # Invoice line items
        invoice_rows=InvoiceRows(rows=[
            InvoiceRow(name="Consulting services", tax=23),
            InvoiceRow(name="Software license", tax=23),
        ]),

        # Required annotations (usually all NO for standard invoices)
        invoice_annotations=InvoiceAnnotations(
            tax_settlement_on_payment=TaxSettlementOnPayment.REGULAR,
            self_invoice=SelfInvoicing.NO,
            reverse_charge=ReverseCharge.NO,
            split_payment=SplitPayment.NO,
            free_from_vat=FreeFromVat.NO,
            intra_community_supply_of_new_transport_methods=IntraCommunitySupplyOfNewTransportMethods.NO,
            simplified_procedure_by_second_tax_payer=SimplifiedProcedureBySecondTaxPayer.NO,
            margin_procedure=MarginProcedure.NO,
        ),
    ),

    # Creation timestamp (required for FA(3) schema)
    creation_datetime=datetime.now(tz=timezone.utc),
)

Sending with the Convenience Method

The simplest way to send an invoice is using the send_invoice() method, which handles the entire session lifecycle automatically:

response = client.send_invoice(nip="1234567890", invoice=invoice)

print(f"Invoice submitted! Reference: {response.reference_number}")

This method:

  1. Opens an encrypted session with KSEF
  2. Encrypts and sends your invoice
  3. Closes the session
  4. Returns the submission reference number

Asynchronous Processing

KSEF processes invoices asynchronously. The reference_number returned is for tracking - the actual KSEF invoice number (ksef_reference_number) is assigned after processing completes.

Sending Multiple Invoices (Session-Based)

For sending multiple invoices efficiently, use the session-based approach:

# Open a session
session_context = client.open_session(nip="1234567890")

try:
    # Send multiple invoices in the same session
    for invoice in invoices:
        response = client.send_invoice_in_session(
            session_context=session_context,
            invoice=invoice,
        )
        print(f"Submitted: {response.reference_number}")

finally:
    # Always close the session
    client.close_session(session_context)

Session Benefits

Using a single session for multiple invoices is more efficient because:

  • Encryption keys are generated only once
  • Fewer API round-trips
  • Better performance for batch operations

Invoice Types

The library supports all KSEF invoice types:

Type Enum Value Description
Regular VAT InvoiceType.REGULAR_VAT Standard VAT invoice
Correction InvoiceType.CORRECTION Correction invoice
Advance InvoiceType.ADVANCE Advance payment invoice
Settlement InvoiceType.SETTLEMENT Settlement invoice
Simplified InvoiceType.SIMPLIFIED Simplified invoice
Correction Advance InvoiceType.CORRECTION_ADVANCE Correction of advance invoice
Correction Settlement InvoiceType.CORRECTION_SETTLEMENT Correction of settlement invoice

Error Handling

Handle potential errors during invoice submission:

from requests.exceptions import HTTPError

try:
    response = client.send_invoice(nip="1234567890", invoice=invoice)
    print(f"Success: {response.reference_number}")
except HTTPError as e:
    print(f"KSEF API error: {e.response.status_code}")
    print(f"Details: {e.response.text}")
except Exception as e:
    print(f"Error: {e}")

Next Steps