Poland KSeF FA(3)
Poland's structured invoice: what Beliq generates and validates against the Ministry of Finance FA(3) XSD, the builder's scope, and the KSeF boundary.
FA(3) is the structured invoice (faktura ustrukturyzowana) of KSeF, the Krajowy System e-Faktur run by Poland’s Ministerstwo Finansów (MF). It is Poland’s own XML format, not EN 16931 UBL or CII: a root Faktura element in namespace http://crd.gov.pl/wzor/2025/06/25/13775/ (CRD pattern 2025/06/25/13775, schema version 1-0E). There are no BR-* Schematron rule IDs on Beliq’s validation path. FA(3) validation runs the W3C XSD published on crd.gov.pl and the document-level acceptance checks the MF documents for KSeF.
FA(3) replaced FA(2) on 2026-02-01, and live KSeF rejects FA(2). Beliq generates FA(3) only. An FA(2) document sent to POST /v1/validate is recognised but never passes: it comes back valid: false with a leading POLAND_KSEF_FA2_SUPERSEDED error that names FA(3).
What Beliq emits
Call POST /v1/generate with standard: "ksef" and output: "xml". The profile field defaults to fa3 and can be omitted. The response labels the document poland_ksef_fa3. FA(3) has no hybrid PDF form, so output: "pdf" returns a visualization PDF instead: a rendering with no embedded XML, and it needs a template or pdfTemplateId. The legal artifact is the XML.
The builder covers a narrow slice of FA(3). Read this list before you integrate:
- Ordinary VAT invoices only (
RodzajFakturyVAT). Corrections (KOR), advance invoices (ZAL) and settlements (ROZ) are not built.documentType: "creditnote"is refused with a 422, and so is atypeCode, because KSeF uses its own document-type vocabulary. - PLN only. Any other
currencyCodeis refused. - VAT rates 23, 22, 8, 7 and 5 only. Each maps to its fixed FA(3) summary slot. A zero-rated, exempt, reverse-charge or margin line is refused rather than slotted by guess.
- Polish parties. The seller needs a Polish NIP (10 digits, with or without the
PLprefix). The buyer carries a Polish NIP or no identifier at all, which Beliq writes asBrakID. A foreign buyer VAT ID is refused. Both parties need an address; Beliq never fills in a missing one. - Totals must match the lines. Beliq takes the VAT once per rate on the summed net, as FA(3) defines
P_14_x, and writesP_15as net plus VAT.totalNetAmount,totalTaxAmount,totalGrossAmountand everytaxSummaryrow must agree with that to the grosz, or the request is refused with a 400 that names the expected value. VAT rounded line by line can be a grosz off on a multi-line invoice. - What is written: the two parties, the lines, the VAT summary slots and the gross total (
P_15). Payment terms (dueDate,paymentMeans), references and notes are not carried into the FA(3) document, and document-level allowances and charges are not supported.paidAmountandroundingAmountmust be zero, becausetotalGrossAmountis the amount due. - Not built: VAT groups, authorised entities (
PodmiotUpowazniony), structured attachments (Zalacznik), the KSeF payment ID (IPKSeF,LinkDoPlatnosci) and partial-payment markers.
The optional invoice.poland block sets the FA(3) fields that have no EN 16931 source. Every field has a default:
| Field | FA(3) element | Default |
|---|---|---|
adnotacje.P_16, P_17, P_18, P_18A, P_23 |
The Adnotacje markers: cash accounting, self-billing, reverse charge, split payment, simplified triangular procedure |
"2" (no) |
jst |
Podmiot2/JST, buyer is a subordinate unit of a local-government unit (JST) |
"2" (no) |
gv |
Podmiot2/GV, buyer is a VAT-group member |
"2" (no) |
placeOfIssue |
P_1M, place of issue |
not written |
dataWytworzenia |
Naglowek/DataWytworzeniaFa, creation timestamp |
the time Beliq generates the document, in UTC |
Flags take "1" (yes) or "2" (no), the FA(3) TWybor1_2 values. The other Adnotacje sub-blocks (exemption, new means of transport, margin schemes) are written with their negative branch.
Validation pipeline
For FA(3), the validation chain is the XSD plus the MF’s document-level acceptance checks. There is no EN 16931 Schematron layer:
Input -> FA(3) XSD (FA3_13775_schemat.xsd + the MF StrukturyDanych, ElementarneTypyDanych and KodyKrajow imports) -> KSeF acceptance checks -> Result
Structural failures surface in the API response with ruleId: "XSD". The acceptance checks come from the MF’s list of the checks KSeF runs on every invoice (weryfikacja-faktury.md), and each failure has its own ruleId:
ruleId |
KSeF rejects |
|---|---|
KSEF_UTF8_BOM |
a UTF-8 byte-order mark |
KSEF_XML_ENCODING |
an XML declaration naming another encoding than UTF-8, or bytes that are not UTF-8 |
KSEF_PROCESSING_INSTRUCTION |
any processing instruction, such as <?xml-stylesheet?> |
KSEF_DISCOURAGED_CHARACTER |
the Unicode ranges XML 1.0 discourages, such as U+007F to U+0084 and U+FDD0 to U+FDEF |
KSEF_FILE_SIZE |
more than 1,000,000 bytes, or 3,000,000 with attachments |
The checks on that list that need KSeF itself are not run: duplicate invoice numbers per seller NIP, the issue date against the time KSeF accepts the invoice, and the session, encryption and permission checks. Neither is the NIP checksum KSeF applies in production.
Responses carry FA(3)-specific metadata fields (polandKsefFa3XsdBundle, polandKsefFa3RuntimeVersion) instead of schematronVersion, and report profileDetected: "poland-ksef-fa3-13775". Use format=poland_ksef_fa3 on POST /v1/validate or rely on auto-detect (the engine matches the FA(3) root namespace).
The runtime XSD bundle is pinned as {VERSION.poland_ksef_fa3} in the engine and listed on the validation artifacts page.
Verification
FA(3) is Schema-checked: Beliq validates against the MF’s official XSD. The MF publishes no machine-readable business rules for FA(3). KSeF checks them itself when an invoice is submitted, so an invoice that passes Beliq’s checks can still be rejected at submission for a business-rule reason. The XSD and the MF’s document-level acceptance checks are as far as a client-side tool can check this format.
Coverage details: a golden round-trip path (generate → XSD validate), four spec-derived negative fixtures, each confirmed by a second, separate XSD validation path, and a Beliq-authored positive sample. The MF announces sample files on its FA(3) page but did not link any when we last checked (2026-09-28), so no official positive corpus is wired yet.
What Beliq does NOT do
- KSeF submission. No session, no interactive or batch send, no KSeF number, no UPO. Not offered; your chosen intermediary or your own KSeF integration does this.
- KSeF authentication. Beliq holds no KSeF tokens or certificates and registers nothing with the tax office.
- Signing and encryption of the KSeF submission envelope.
- Offline and outage modes (offline24 and emergency mode).
- Archiving. Retention of your invoices and UPOs stays with you or your intermediary.
- FA(2). Superseded and rejected by KSeF; Beliq recognises it only to tell you so.
Related
- Poland country guide for the mandate dates and the KSeF boundary
- POST /v1/generate with
standard: "ksef" - POST /v1/validate with the
format=poland_ksef_fa3query parameter - Validation artifacts with the XSD bundle pin and runtime metadata fields
- FA(3) schema at crd.gov.pl authority publication