Skip to content

Building Invoices

Use ksef2.fa3 when your application owns invoice data as Python objects and you want the SDK to produce FA(3) XML. Use the sending workflows when you already have XML from another system.

from datetime import date
from decimal import Decimal
from ksef2.fa3 import FA3InvoiceBuilder, VatRate
builder = (
FA3InvoiceBuilder()
.header(system_info="billing-service")
.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_bytes = builder.to_xml().encode("utf-8")

Each .done() returns to the previous builder level.

  • standard()
  • simplified()
  • correction()
  • advance()
  • settlement()
  • correction_advance()
  • correction_settlement()

Persist builder state when invoice editing can span multiple requests or user sessions.

from ksef2.fa3 import FA3InvoiceBuilder, KsefInvoiceDraft
json_text = builder.dump_state_json(indent=2)
draft = KsefInvoiceDraft.model_validate_json(json_text)
restored = FA3InvoiceBuilder.from_state(draft)
from ksef2 import FormSchema
with auth.online_session(form_code=FormSchema.FA3) as session:
status = session.send_invoice_and_wait(invoice_xml=xml_bytes)
print(status.ksef_number)
  1. Map application data into the FA(3) builder.

  2. Choose the invoice kind and fill required nested sections.

  3. Save draft state if users can pause editing.

  4. Render XML with to_xml().

  5. Send the XML through an online or batch workflow.