Fakturnia Developers Quickstart API reference Polski

Document types & amounts

This page is the one to read before you build invoicing. It explains which document types exist, what you send, and exactly how amounts are computed, down to the grosz. Getting the money math right is the whole game, so the rules are spelled out precisely.

The golden rule: you send prices, we compute values

For every line you send a unit price and a VAT rate. The backend computes the rest. You never compute amountOfVat or grossValue yourself, and you shouldn't, because the server is the single source of truth and your numbers would only drift.

You send Meaning
quantity line quantity (required)
netPrice or grossPrice unit price before/after VAT (one of them)
vatRate VAT rate (number like 23, or a special code)
discount optional, percent 0–100

The backend returns, per line:

Field How it is computed
netValue round2(quantity × netPrice × (1 − discount/100))
amountOfVat round2(netValue × rate / 100)
grossValue round2(netValue + amountOfVat)

If you send grossPrice instead, the math runs "downwards": grossValue first, then netValue = round2(gross / (1 + rate/100)) and amountOfVat = round2(gross − netValue).

Rounding is half-up, to the grosz

All money is rounded to 2 decimal places using round half-up:

round2(x) = Math.round((x + Number.EPSILON) * 100) / 100

So 0.345 → 0.35 (not 0.34). The order of operations matters at the boundary: VAT is round2((net × rate) / 100), never net × (rate/100). The two differ by a grosz on some values. The same algorithm runs in our fakturnia-shared library, so a document created through the API is identical, to the grosz, to one created in the web app.

Per line, netValue + amountOfVat always equals grossValue. Summed over a document, netSum + vatSum === grossSum. If you ever see a one-grosz mismatch, it is a bug. Report it.

VAT rates

vatRate accepts a numeric percentage from the dictionary or a special code. Numeric rates: 23, 22, 8, 7, 5, 4, 3. Special codes (VAT = 0, net = gross):

Code Meaning
zw exempt (zwolnione)
np I, np II not subject (nie podlega)
oo reverse charge (odwrotne obciążenie)
0 WDT intra-community supply
0 EX export
0 KR domestic 0%

There is no bare 0 and no bare np; use the codes above. An unknown rate returns 400 VALIDATION_ERROR.

Document types

Ten document types are available through the API. Five legacy types are intentionally not exposed (use annotations instead, see below).

Type What it is Required extra fields
Faktura Non‑KSeF invoice, for VAT‑exempt entities (available until end of 2026) -
FakturaVAT VAT invoice, the equivalent of a basic invoice in KSeF -
FakturaProforma Proforma -
FakturaProformaBezVAT Proforma without VAT -
FakturaZaliczka Advance invoice linkedOrderId, advancePaymentAmount
FakturaRozliczeniowa Settlement (final) invoice linkedAdvanceInvoiceIds
FakturaKorygujaca Correction correctedInvoiceId
FakturaKorygujacaZaliczkowa Correction of an advance correctedInvoiceId, correctionAdvanceAmountAfter
FakturaKorygujacaRozliczeniowa Correction of a settlement correctedInvoiceId, correctionSettlementAmountAfter
Zamowienie Order -

KSeF and the future of invoice types. FakturaVAT is the equivalent of a basic invoice in KSeF. Faktura is a document that does not go to KSeF, dedicated to VAT‑exempt entities — available until the end of 2026. From January 1, 2027 the Faktura type will no longer be available, and FakturaVAT will become the FakturaPodstawowa type; for a transitional period both types may be used (legacy mode). For now, use FakturaVAT exclusively as the equivalent of a basic invoice.

Annotations

Special VAT settlement modes are not separate document types. Following KSeF FA(3), you set them in the annotations object on the document, regardless of its type. Available options:

Annotation Field Meaning
Split payment (MPP) isSplitPayment Marks the invoice as split payment. Mutually exclusive with the cash method. A dedicated VAT account can go in the payment fields (vatAccountNumber and friends).
Reverse charge isReverseCharge VAT is settled by the buyer.
Cash method isCashMethod VAT settled at the moment of payment. Mutually exclusive with split payment.
Self-invoicing isSelfInvoicing The invoice is issued by the buyer on the seller's behalf.
Margin procedure marginProcedure Object { enabled, procedureId }. Procedure ids (travel agency, second-hand goods, works of art, antiques) are listed in the marginProcedures dictionary.
VAT exemption vatExemption Object { enabled, exemptionType, legalBasis, showOnDocument }. Types A/B/C are described in the vatExemptionTypes dictionary.

Conflicting combinations (e.g. split payment together with the cash method) return 422 ANNOTATIONS_VALIDATION_ERROR (see Errors). The full field reference with request examples is in Creating documents → Annotations.

Additional information: invoice to a receipt

Next to annotations, KSeF FA(3) defines an "Additional information" section (additionalInfo). The API currently exposes one field there:

Field Meaning
additionalInfo.isInvoiceToReceipt Invoice issued to a receipt (art. 109(3d) of the Polish VAT Act).

Setting isInvoiceToReceipt: true on a FakturaVAT adds the <FP>1</FP> flag to the document sent to KSeF and an "invoice to a receipt" annotation on the PDF. It is still a regular VAT invoice, not a separate document type; amounts are computed the same way. KSeF has no field for the receipt number, so the API does not accept one either. Details in Creating documents → Additional information.

Standard invoices

Faktura, FakturaVAT, FakturaProforma, FakturaProformaBezVAT, Zamowienie are computed straight from their lines: grossSum = Σ grossValue, and so on. Nothing surprising.

Advance invoices (FakturaZaliczka)

An advance invoice books a prepayment against an order (Zamowienie). It is not the sum of the order's lines; its value is the advancePaymentAmount.

  • You pass linkedOrderId (an existing Zamowienie) and advancePaymentAmount.
  • The backend splits the advance proportionally across the order's VAT rates and that breakdown becomes the invoice's lines.
  • Therefore grossSum === advancePaymentAmount, with netSum / vatSum derived from the proportional split.
{
  "documentType": "FakturaZaliczka",
  "issueDate": "2026-06-04",
  "buyerId": "681a…",
  "linkedOrderId": "6820…",
  "advancePaymentAmount": 615
}

The advance may not exceed the order's gross value (422 ADVANCE_EXCEEDS_ORDER_VALUE).

Settlement invoices (FakturaRozliczeniowa)

A settlement (final) invoice closes out an order after one or more advances. Its gross is the amount still to pay, not the full line total.

  • You pass linkedAdvanceInvoiceIds (the advance invoices being settled) and the full products.
  • The backend computes settlementAmount = max(0, Σ products.gross − Σ advances.gross) (unless you set isSettlementAmountManual: true and supply settlementAmount).
  • grossSum === settlementAmount; netSum / vatSum come from splitting that amount proportionally over the product VAT rates.

So if your lines total 6 150 gross and the linked advances total 2 460, the settlement invoice's grossSum is 3 690, not 6 150.

Corrections

The full guide to issuing corrections via the API is in the Correcting documents article — the three correction types, zeroing out an invoice, and the proportional VAT rules.

A correction restates a document. products is the full "after" state, the whole document as it should look after correction. The backend computes the delta; you do not send "+/−" lines.

  • FakturaKorygujaca: totals are the line delta: Σ after − Σ corrected. To cancel a document, send the same lines with quantity: 0.
  • FakturaKorygujacaZaliczkowa corrects an advance. Totals are the advance-amount delta: grossSum = correctionAdvanceAmountAfter − advancePaymentAmountBefore, with VAT from the difference of the two proportional breakdowns.
  • FakturaKorygujacaRozliczeniowa corrects a settlement. grossSum = correctionSettlementAmountAfter − settlementAmountBefore, VAT proportional.
{
  "documentType": "FakturaKorygujaca",
  "issueDate": "2026-06-04",
  "correctedInvoiceId": "681a…",
  "correctionReason": "Zmiana ilości",
  "products": [
    { "name": "Usługa", "unitOfMeasure": "szt.", "quantity": 2, "netPrice": 100, "vatRate": 23 }
  ]
}

Why this matters for integrators. Advance, settlement and correction grossSum values are not Σ products. If you mirror invoice totals in your own system, take them from the API response, don't recompute from the lines.

Payment & dates

Field Notes
paymentMethodId 1 Cash · 2 Card · 3 Voucher · 4 Cheque · 5 Credit · 6 Transfer · 7 Mobile
paymentStatusId 0 Paid (requires additionalPaymentDate) · 1 To pay (requires paymentDeadlineDate)
bankAccounts[] for transfer; first becomes the primary account, the rest are shown as additional
issueDate, subDate, subDateTo issue date / sale date or period (ISO YYYY-MM-DD)
paymentInstallments, paymentDeadlineTerm instalments and a due date in words for an unpaid invoice, see Creating documents
exchangeRate, exchangeRateDate, exchangeRateTable the NBP rate of the business day before the tax point, its day and table

Mark a payment that arrived after the issue with PATCH /documents/{id}/payment-status, receivedPayment: RECEIVED and an optional paymentDate (the day of the payment, YYYY-MM-DD; by default today in Poland, never in the future). For the cash method it is the tax point (art. 21 ust. 1 of the VAT Act). GET /documents/{id} returns it as payment.receivedPaymentDate.

Deleting and editing documents

Whether a document can still be changed or removed depends on its KSeF status. DELETE /documents/{id} and document updates follow the same rule:

  • Once a document has a KSeF number (it was confirmed in KSeF), it is final. Delete or update returns 400 KSEF_CONFIRMED.
  • While a document is sent to KSeF and awaiting confirmation, it is locked. Delete or update returns 400 KSEF_SENT.
  • If the KSeF send failed (the document carries a KSeF error), the lock is lifted. You can delete the document or fix it and send again.

Documents that were never sent to KSeF can always be deleted or edited. Check a document's state with GET /documents/{id}/ksef-status before attempting a change.

Validate before you commit

POST /documents/validate runs the full pipeline (numbering, totals, party resolution) and returns a preview without persisting. Use it to show users a confirmation screen or to dry-run an integration.

See the API reference for the complete request schema and every field.