Fakturnia Developers Quickstart API reference Polski

Creating documents

This is the complete guide to POST /external/v1/documents, the single endpoint you need to issue an invoice, proforma, advance, settlement, correction or order. It covers every request field, how transaction parties are resolved, the per-type logic and the KSeF annotations. For the money math and the full type map see Document types & amounts; here we focus on how to build a correct request.

If you are just starting, run through the Quickstart first. The full machine-generated schema for every field lives in the API reference.

Before you start

  • Scope: creating documents requires the documents:create permission. See Authentication.
  • Dictionaries are the source of truth: rather than hardcoding enum values, fetch them once from GET /external/v1/dictionaries. It returns the live lists: document types, payment methods and statuses, VAT rates, GTU codes, currencies, country codes, margin procedures, VAT exemption types and date headers. Your integration then won't drift when we add a new entry.
  • Idempotency: send every create with an Idempotency-Key header so a retry after a dropped connection never creates a duplicate. See Idempotency.

Full list of values. Every enum (document types, VAT rates, currencies, country codes, GTU, margin procedures, …) is described on the Dictionaries page, and you can fetch them live from GET /dictionaries. The dictionary returns exactly the document types this endpoint accepts.

Minimal request

The endpoint will create a document from just documentType, issueDate, a buyer with nip and name, and one line item. That is not enough for real use though: for the invoice to pass KSeF submission, the buyer must have a full address (street, postalCode, city, countryCode). So we treat the example with an address as the sensible minimum. The seller is resolved automatically from your company profile.

curl -s -X POST https://prod.api.fakturnia.pl/external/v1/documents \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 7c1f1d6e-0b2a-4a1e-9b1a-2a4e9b1a2a4e" \
  -d '{
    "documentType": "FakturaVAT",
    "issueDate": "2026-06-04",
    "buyer": {
      "nip": "5261040828",
      "name": "Acme Corp Sp. z o.o.",
      "street": "Marszałkowska 1",
      "postalCode": "00-001",
      "city": "Warszawa",
      "countryCode": "PL"
    },
    "products": [
      { "name": "Development service", "unitOfMeasure": "szt.", "quantity": 1, "netPrice": 100, "vatRate": 23 }
    ]
  }'

Buyer address and KSeF. Without an address the document is still created and you can download the PDF, but KSeF submission is rejected. If you issue invoices with KSeF in mind, treat the buyer address as required. For an individual (type: "person") provide firstName and lastName instead of name.

Everything else is optional with sensible defaults. Below we break the request down.

Document numbering

A document number is made of three parts: a symbol, a sequence number (documentNo) and a date part (numberingFormat). The most common layout is the number followed by the date:

{symbol}{documentNo}{numberingFormat}

For example symbol FV/, number 4 and format /MM/YYYY for issue date 2026-05-07 give FV/4/05/2026. The date part can also come before the number, depending on the chosen format (see "Available formats" below).

The three parts of a number

Part Field What it is
Symbol symbol Prefix, e.g. FV/, KOR/. Defaults from your company settings for the given document type.
Sequence number documentNo Integer ≥ 1. This is what increments within a period.
Format numberingFormat The "date" part pattern, e.g. /MM/YYYY. Defaults from settings, fallback /MM/YYYY.

The format substitutes only two tokens: MM (month, two digits) and YYYY (year), both from the issue date. Any other characters (slashes, dashes, letters) are inserted verbatim:

numberingFormat issueDate Date part Full number (symbol FV/, no. 4)
/MM/YYYY 2026-05-07 /05/2026 FV/4/05/2026
/YYYY 2026-05-07 /2026 FV/4/2026
-MM-YYYY 2026-05-07 -05-2026 FV/4-05-2026

Available formats

The position of the date part depends on the pattern: in a prefix variant the date comes after the number, in a suffix variant before it. Both are supported. In the "Layout" column, NUMER stands for documentNo.

Monthly (contain MM):

Format Layout Example (symbol FV/, no. 4, 2026-05)
/MM/YYYY NUMER/MM/YYYY FV/4/05/2026
/YYYY/MM NUMER/YYYY/MM FV/4/2026/05
-MM-YYYY NUMER-MM-YYYY FV/4-05-2026
-YYYY-MM NUMER-YYYY-MM FV/4-2026-05
YYYY/MM/ YYYY/MM/NUMER FV/2026/05/4
MM/YYYY/ MM/YYYY/NUMER FV/05/2026/4
YYYY-MM- YYYY-MM-NUMER FV/2026-05-4
MM-YYYY- MM-YYYY-NUMER FV/05-2026-4

Yearly (YYYY only):

Format Layout Example (symbol FV/, no. 4, 2026)
/YYYY NUMER/YYYY FV/4/2026
-YYYY NUMER-YYYY FV/4-2026
YYYY/ YYYY/NUMER FV/2026/4
YYYY- YYYY-NUMER FV/2026-4

The default format is /MM/YYYY. numberingFormat is validated against the list above, so an unknown pattern is rejected with 400 VALIDATION_ERROR. When you send documentNumber manually, it must match the chosen format's layout (otherwise 422 NUMBER_MISMATCH).

Automatic numbering (default)

When you do not send documentNo, the backend assigns the number:

  • symbol, numberingFormat and the numbering mode come from your company settings (you can override each of them in the request).
  • The numbering mode is monthly (default) or yearly (the numberingType setting). It decides when the counter resets: monthly keeps a separate counter per month (period YYYY-MM), yearly per year (period YYYY).
  • The counter is atomic and separate per company + document type + period. The first document in a period gets 1, the next 2, and so on.
  • Corrections share one counter: FakturaKorygujaca, FakturaKorygujacaZaliczkowa and FakturaKorygujacaRozliczeniowa are numbered together.

Keep the format consistent with the mode. With monthly numbering the format should contain MM (e.g. /MM/YYYY). Number uniqueness is checked within the period implied by the format, so using /YYYY with the monthly mode collapses months into one period.

Manual numbering

To force your own number, send documentNo (≥ 1). The backend builds the full number from the symbol, the number and the date part following the chosen format's layout, and checks that the number is free: in its series (document type, numbering format, month or year of the issue date) and across the whole account, since two documents can never share the same full number, even of different types or from different months.

Optionally add documentNumber (the full string) as a safeguard: it must exactly match what the backend builds from symbol/documentNo/numberingFormat, otherwise you get 422 NUMBER_MISMATCH. This guards against your number drifting from ours.

{
  "documentType": "FakturaVAT",
  "issueDate": "2026-05-07",
  "symbol": "FV/",
  "documentNo": 4,
  "numberingFormat": "/MM/YYYY",
  "documentNumber": "FV/4/05/2026"
}

Manual numbering does not touch the automatic counter. If you mix both modes, keep your numbering continuous on your side so you don't create gaps or collisions.

Numbering fields

Field Type Required Notes
symbol string no Prefix. Defaults from settings for the given document type.
documentNo number no Sequence number ≥ 1. Omitted → automatic numbering.
numberingFormat string no Date-part pattern (MM, YYYY tokens). Defaults from settings.
documentNumber string no Full number for 1:1 validation against documentNo.

Numbering errors

Status Code Cause
422 NUMBER_MISMATCH documentNumber does not match the number the API builds for the chosen format's layout (PREFIX {symbol}{documentNo}{date} or SUFFIX {symbol}{date}{documentNo}).
409 DOCUMENT_NUMBER_EXISTS The number is taken in its series, or another document on the account already has the same full number.

Request anatomy

Document header

Field Type Required Notes
documentType string yes One of the ten types (see Document types). Immutable on edit.
issueDate string yes Issue date, ISO 8601 YYYY-MM-DD.
issuePlace string no Place of issue. Defaults from company settings.
currency string no Currency code, defaults to PLN. List in the currencies dictionary.
exchangeRate number no Exchange rate for non-PLN currencies: the NBP mid rate of the last business day before the tax point (usually before the sale date), or before the issue date when the invoice comes first (art. 31a of the VAT Act).
exchangeRateDate string no Day of the NBP table exchangeRate comes from (YYYY-MM-DD).
exchangeRateTable string no NBP table number, e.g. 190/A/NBP/2026. Printed on the PDF next to the rate.
comments string no Notes shown on the document. In KSeF they map to the invoice footer: Stopka/Informacje/StopkaFaktury.
invoiceName string no Display name. Defaults to type plus number.

Transaction parties: seller, buyer, receiver

This is the most common source of integrator questions, so we cover it carefully.

The seller (seller) is never sent in the request. It always comes from the authenticated user's company profile (user.company): name, NIP, EU VAT, REGON, KRS, BDO, address, and the personal details for a sole proprietorship. To change seller data, update the company profile, not the request. The buyer's NIP must not equal the seller's NIP (422).

The buyer (buyer) is required, and you pass it in one of two ways:

  • buyerId (string): the id of an existing contractor. Fetch it from GET /external/v1/clients.
  • buyer (object): inline data. The backend looks up a saved contractor (by NIP, VAT UE number or name) and, if none is found, creates a new one from the fields you sent. So you don't have to create the contractor separately before invoicing. Identifiers follow the contractor identifier rules: send a contractor from another EU country as "identifierType": "vatEu", "vatUE": "DE123456789", not in nip. An inferred type and moved numbers come back in data.warnings, contradictions as 422 PARTY_IDENTIFIER_INVALID.

Send buyerId or buyer, not both.

The receiver (receiver) is optional and identifies a separate entity that actually receives the invoice, distinct from the buyer. The typical case is local-government structures: the buyer is the parent unit that holds the NIP (e.g. a municipality), while the receiver is the subordinate unit that actually receives the invoice (e.g. a department or a public kindergarten). You pass it the same way as the buyer: receiverId or an inline receiver object. If you omit the receiver, the invoice has no separate receiver and the buyer remains the recipient.

The receiver can additionally be identified by an internal identifier: set identifierType to idWew and provide idWew (format NIP-NNNNN, e.g. 5252248481-16006), which is useful for local-government units (JST), among others. The seller has no such option; in KSeF it is always identified by its NIP.

The contractor object (buyer / receiver)

The same field set applies to buyer and receiver. All fields except the type marker are optional, but for a valid invoice include identifying and address data.

Field Type Notes
id string Id of an existing contractor (alternative to buyerId/receiverId).
type string company (default) or person. Decides whether you use name or firstName + lastName.
name string Company name (for company).
firstName, lastName string Given and family name (for person).
nip string Polish NIP (10 digits; spaces, dashes and the PL prefix are removed, the check digit is verified). Used to look up or create the contractor. Send a foreign VAT number in vatUE.
vatUE string EU VAT number with its country prefix, e.g. DE123456789; stored in uppercase without spaces.
pesel string Personal id of an individual.
regon, krs, bdo string Other registry identifiers.
street, postalCode, city string Address.
country, countryCode string ISO 3166-1 alpha-2 code (e.g. PL, DE), defaults to PL. List in the countries dictionary. Only countryCode matters for KSeF and the PDF; the country name is optional (the PDF derives it from the code anyway).
email, phoneNumber, www string Contact details.
identifierType string Which identifier identifies the party in KSeF: nip (field nip), vatEu (vatUE), other (countryCode and otherTaxIdentifier), idWew (idWew, receiver only), none (none). Without it the API infers the type from the data, see Contractor identifiers.
otherTaxIdentifier string Tax identifier for identifierType: "other", up to 50 characters, together with countryCode (KodKraju + NrID in KSeF).
idWew string Internal identifier (format NIP-NNNNN, e.g. 5252248481-16006), used when identifierType: "idWew". Only the receiver can have it: in the FA(3) schema IDWew exists only for the receiver (Podmiot3), not the buyer or seller.
fieldsToShow string[] Which fields to print on the document, e.g. ["nip","regon"].

Example of a buyer who is an individual:

{
  "buyer": {
    "type": "person",
    "firstName": "Jan",
    "lastName": "Kowalski",
    "street": "Długa 5",
    "postalCode": "80-001",
    "city": "Gdańsk",
    "countryCode": "PL"
  }
}

Tip. If you issue many documents to the same contractor, create it once via the contractors API and then pass buyerId. Faster, and no risk of drifting data from a typo in the name.

Line items (products)

The array of line items. Required for standard, settlement and correction invoices. For an advance invoice the items are derived from the linked order, so you don't send them (see below).

For each item you send a price and a VAT rate, and the backend fills in the values. Do not compute netValue, amountOfVat or grossValue yourself - the server is the single source of truth. The exact formulas and rounding rules are in Document types & amounts.

Field Type Required Notes
name string yes Product or service name.
unitOfMeasure string yes Unit, e.g. szt., godz., kg. Free text, suggested values in the dictionary.
quantity number yes Quantity. For corrections 0 is allowed (cancel a line).
vatRate number | string yes VAT rate (see VAT rates).
netPrice number yes* Net unit price.
grossPrice number yes* Gross unit price (alternative to netPrice).
discount number no Percentage discount 0-100.
gtu string no GTU code (GTU_01 to GTU_13). Validated against the dictionary.
pkwiu string no PKWiU symbol.
marginPurchaseValue number no vatRate: "marza" only: gross purchase amount of the whole line in PLN. See Margin scheme.
marginTaxRate number no vatRate: "marza" only: rate of the tax on the margin, 23, 8, 5 or 0. Default 23.

* Send netPrice or grossPrice. If you pass grossPrice, the math runs "downward" from gross.

VAT rates

vatRate takes a numeric percentage or a special string code. The full list with descriptions is in the vatRates dictionary.

  • Percentage rates: 23, 22, 8, 7, 5, 4, 3.
  • Special codes (VAT = 0, net = gross): zw (exempt), np I and np II (not subject), oo (reverse charge), 0 KR (domestic 0%), 0 WDT (intra-EU supply), 0 EX (export), marza (margin scheme, see below).

There is no bare 0 or bare np. An unknown rate returns 400 VALIDATION_ERROR.

Margin scheme

A margin-scheme invoice (art. 119 of the VAT Act for travel agencies, art. 120 for second-hand goods, works of art, collectors' items and antiques) shows the buyer gross amounts only. Mark a margin line with vatRate: "marza":

  • send grossPrice; netValue = grossValue, amountOfVat = 0,
  • the document needs annotations.marginProcedure with enabled: true and a procedureId (1 travel agencies, 2 second-hand goods, 3 works of art, 4 collectors' items and antiques); without it you get 422 MARGIN_LINE_WITHOUT_PROCEDURE,
  • in KSeF the line has no rate (P_12) and its sum goes to P_13_11,
  • margin lines and regular rates can share one invoice (e.g. a travel agency: services bought for the tourist under the margin scheme and its own service at 23%).

The tax is due on the margin, the difference between the price and the purchase amount. Fakturnia computes it for the VAT register and JPK_V7 (K_19 and K_20 for 23%, MR_T or MR_UZ), so a line can carry:

  • marginPurchaseValue: the gross purchase amount of the whole line in PLN (second-hand goods: the purchase price; travel agencies: the costs of services bought directly for the tourist). It never appears on the invoice or in KSeF. Without it the reports leave the VAT on the margin of that line out and show a warning, and MCP warns with MARGIN_PURCHASE_MISSING. You can add it later with PUT /documents/{id},
  • marginTaxRate: the rate of the tax on the margin, 23 (default), 8, 5 or 0.

You can also set the purchase amount after the invoice is issued, including once it is in KSeF: PATCH /documents/{id}/margin-purchases with { "lines": [{ "index": 0, "marginPurchaseValue": 1500, "marginTaxRate": 23 }] }, where index is the position in products (from 0). Only these two fields change; the invoice content stays. A key you leave out keeps the stored value, null clears it. A line outside the margin scheme returns 422 MARGIN_LINE_NOT_FOUND, a wrong value 422 MARGIN_PURCHASES_INVALID. The MCP tool updateDocumentMarginPurchases does the same.

When PUT or PATCH /documents/{id} sends a margin line without marginPurchaseValue and marginTaxRate, the values stored on the line with the same name stay.

VAT on the margin = margin × rate / (100 + rate). A negative margin gives 0 tax and does not lower the margin of other lines. In a correction, margin fields you leave out are taken from the corrected line with the same name, the purchase amount in proportion to the quantity (returning one of three items lowers it by a third).

A margin line has no net, so the document's netSum counts it with its gross (KSeF reports it apart, in P_13_11). The POST /documents/validate preview gives this sale in preview.totals.marginSaleSum, and the net of the ordinary rates is netSum minus marginSaleSum. Without margin lines marginSaleSum is 0.

{
  "documentType": "FakturaVAT",
  "annotations": { "marginProcedure": { "enabled": true, "procedureId": 3 } },
  "products": [
    { "name": "Oil painting", "unitOfMeasure": "szt.", "quantity": 1, "grossPrice": 5000, "vatRate": "marza", "marginPurchaseValue": 3000, "marginTaxRate": 23 }
  ]
}

Payment

Field Type Notes
paymentMethodId number 1 Cash · 2 Card · 3 Voucher · 4 Cheque · 5 Credit · 6 Transfer · 7 Mobile payment
paymentStatusId number 0 Paid · 1 Unpaid
paymentDeadlineDate string Due date. Required when paymentStatusId = 1.
additionalPaymentDate string Payment date. Required when paymentStatusId = 0.
additionalPaymentDateHeaderId number Header above the payment date (paymentDateHeaders dictionary).
paymentDescription string Extra payment note.
showPaymentSection boolean Whether to show the payment section on the PDF. Defaults to true.

Partial payments (partialPayments)

When the buyer paid part of the amount by the issue date (or the whole amount in several payments), send the list of payments. They go to KSeF as ZaplataCzesciowa and appear on the PDF as payment information.

Field Type Meaning
partialPayments[].amount number gross payment amount
partialPayments[].date string payment date (YYYY-MM-DD), not later than issueDate
partialPayments[].paymentMethodId number payment form like paymentMethodId (optional)

The rules depend on paymentStatusId:

  • 1 (Due): the payments must sum to less than the amount due; the rest is due on paymentDeadlineDate.
  • 0 (Paid): at least two payments summing exactly to the amount due; additionalPaymentDate is then not required.

Inconsistent payments answer 422 PARTIAL_PAYMENTS_INVALID. When the invoice has partial payments, the payment date of the whole (additionalPaymentDate) is not sent to KSeF: the dates go with the payments. In the response payment carries partialPayments (an empty list when there are none), paidAmount (paid according to the invoice) and amountDue (still due), so the integration does not have to compute them.

{
  "paymentMethodId": 6,
  "paymentStatusId": 1,
  "paymentDeadlineDate": "2026-10-10",
  "partialPayments": [
    { "amount": 500, "date": "2026-09-20", "paymentMethodId": 6 }
  ]
}

Instalments (paymentInstallments)

An invoice payable on several dates lists instalments, each with a due date and an amount. In KSeF every instalment is its own TerminPlatnosci, and the instalment amounts go to DodatkowyOpis (FA(3) has no field for an instalment amount). On the PDF the instalments replace the single due date.

Field Type Meaning
paymentInstallments[].date string due date of the instalment (YYYY-MM-DD)
paymentInstallments[].amount number gross amount of the instalment, in the document currency

Rules: only with paymentStatusId = 1, at least two instalments and at most 100, due dates in order and not before issueDate, adding up to the amount due. Without paymentDeadlineDate the document is due on the first instalment. Inconsistent instalments answer 422 PAYMENT_INSTALLMENTS_INVALID. An empty list ([]) in PUT or PATCH removes them. The API computes equal instalments for you: see Equal instalments.

{
  "paymentStatusId": 1,
  "paymentMethodId": 6,
  "paymentInstallments": [
    { "date": "2026-10-20", "amount": 615 },
    { "date": "2026-11-20", "amount": 615 }
  ]
}

Equal instalments (paymentInstallmentsSplit)

When the instalments should be equal, do not compute the amounts yourself: send the number of instalments and the API splits the amount due once the document totals are computed. The document gets ordinary paymentInstallments (in the response, in the validate preview and in KSeF); the split itself is not stored.

Field Type Meaning
paymentInstallmentsSplit.count number number of instalments, 2 to 100 (required)
paymentInstallmentsSplit.firstDate string due date of the first instalment (YYYY-MM-DD), not before issueDate; defaults to paymentDeadlineDate from the request, otherwise issueDate + 14 days
paymentInstallmentsSplit.every string month (monthly, the default), week (every 7 days) or 14days (every 14 days)

How the API computes the instalments:

  • The amount due (gross, in the document currency; on a settlement invoice the amount left after the advances) becomes grosze once, rounding halves away from zero.
  • Every instalment gets the same number of grosze and the remainder goes to the last one: 100.00 in 3 instalments is 33.33 + 33.33 + 33.34. The instalments always add up to the amount due.
  • Monthly instalments are counted from the first date: 31 January, 28 February, 31 March.
  • The document's payment deadline (paymentDeadlineDate) becomes the date of the first instalment.

Rules: only with paymentStatusId = 1. On create without paymentStatusId the document becomes unpaid (to pay); status 0 (paid) is an error. Do not combine it with paymentInstallments: instalments with different amounts (e.g. a larger first instalment) go in paymentInstallments. A PATCH without products splits the amount stored in the document and, without firstDate, starts on the stored payment deadline. Less than one grosz per instalment, a wrong count, date or interval answer 422 PAYMENT_INSTALLMENTS_INVALID, with the reason in errors[0] (in Polish, e.g. "Kwota jest za mała na tyle rat.", the amount is too small for that many instalments). null means no split.

Request (part of POST /external/v1/documents, gross total 1,230.00 PLN):

{
  "documentType": "FakturaVAT",
  "issueDate": "2026-10-07",
  "paymentMethodId": 6,
  "paymentStatusId": 1,
  "paymentInstallmentsSplit": { "count": 3, "firstDate": "2026-10-31", "every": "month" }
}

Response (part of data.document):

{
  "paymentDeadlineDate": "2026-10-31",
  "paymentInstallments": [
    { "date": "2026-10-31", "amount": 410 },
    { "date": "2026-11-30", "amount": 410 },
    { "date": "2026-12-31", "amount": 410 }
  ]
}

POST /external/v1/documents/validate returns the same instalments in preview.paymentInstallments, so you can show them before issuing.

Due date in words (paymentDeadlineTerm)

The due date can also be described in words, e.g. "14 days from the invoice date". It goes to TerminOpis in KSeF and next to the due date on the PDF.

Field Type Meaning
paymentDeadlineTerm.count number number of units, a whole number from 1
paymentDeadlineTerm.unit string day, week or month
paymentDeadlineTerm.event string what the term counts from: issue (the issue of the invoice), invoice_delivery (delivery of the invoice), supply (supply of goods or services), acceptance (acceptance)

paymentDeadlineDate still gives the due date; with event: issue it should follow from the description. null in PUT or PATCH removes the description.

Several receipts on an advance invoice (advanceReceipts)

An advance invoice can document several payments received before it was issued (ZaliczkaCzesciowa in KSeF, example 16 of the Ministry of Finance brochure). Each receipt is its own tax point (art. 19a ust. 8 of the VAT Act), so the VAT report and JPK place them separately.

Field Type Meaning
advanceReceipts[].date string the day the payment arrived, not later than issueDate
advanceReceipts[].amount number gross amount of the payment
advanceReceipts[].exchangeRate number in a foreign currency: the NBP rate of the business day before the payment arrived (required)
advanceReceipts[].exchangeRateDate string day of the NBP table of that rate (optional)

Rules: only FakturaZaliczka with paymentStatusId = 0, from two to 31 receipts, adding up to advancePaymentAmount. The document's payment date is the last receipt's. Inconsistent receipts answer 422 ADVANCE_RECEIPTS_INVALID.

Bank accounts

For a bank transfer (paymentMethodId = 6) supply bankAccounts, unless you have a default account in company settings. The first account becomes the primary one, the rest are shown as additional.

Field Type Required Notes
accountNumber string yes Account number / IBAN.
bank string no Bank name.
swift string no SWIFT code for international transfers.
accountDescription string no Account description on the document.
bankOwnAccountType number no 1, 2 or 3.

For split payment you can additionally provide a separate VAT account: vatAccountNumber, vatAccountBank, vatAccountSwift, vatAccountDescription. The MPP annotation itself is enabled via annotations.isSplitPayment (see below).

Sale dates

Field Type Notes
subDate string Sale / delivery / service date (KSeF P_6); with subDateTo the start of a period. For KSeF types and orders it defaults to issueDate. A correction without subDate takes the sale date or period of the corrected invoice.
subDateTo string End of the sale period, e.g. a service for a whole month (KSeF OkresFa). null in PUT or PATCH goes back to a single date.
subDateHeaderId number Header above the sale date (additionalDateHeaders dictionary).
taxPointRule string Tax point at the issue of the invoice (art. 19a ust. 5 of the VAT Act): art19a5p3a construction services, art19a5p3b supply of books and press, art19a5p3c printing of books and press, art19a5p4 utilities, telecommunications, rent, lease, leasing, security, ongoing legal and office services. Not sent to KSeF; it decides the period in VAT reports and the day of the exchange rate. null means the usual rules.

The dates of a document cannot contradict each other. The API refuses with 422 DOCUMENT_DATES_INVALID (messages in errors):

  • a sale period whose start is after its end;
  • a sale date more than 60 days after the issue date (art. 106i ust. 7; a billing period is exempt);
  • a payment date (additionalPaymentDate) later than the issue date with paymentStatusId = 0. Mark a payment that arrived after the issue with PATCH /documents/{id}/payment-status and paymentDate;
  • a correction issued before the corrected invoice.

A due date earlier than the issue date is allowed (a late invoice may carry a due date that has passed).

Annotations (annotations)

Annotations are the modern, KSeF FA(3) compatible way to flag special VAT settlement modes. They replace the old, separate invoice types (such as FakturaMPP or FakturaVATMarza), which the API deliberately does not expose.

Field Type Meaning
isSplitPayment boolean Split payment mechanism (MPP). Mutually exclusive with isCashMethod.
isReverseCharge boolean Reverse charge.
isCashMethod boolean Cash method. Mutually exclusive with isSplitPayment.
isSelfInvoicing boolean Self-invoicing.
marginProcedure object Margin scheme.
vatExemption object VAT exemption.

Margin scheme (annotations.marginProcedure):

Field Type Notes
enabled boolean Enables the scheme.
procedureId number Required when enabled = true. Values in the marginProcedures dictionary (e.g. travel agency, used goods, works of art, antiques).

VAT exemption (annotations.vatExemption):

Field Type Notes
enabled boolean Enables the exemption.
exemptionType string A (statute), B (Directive 2006/112/EC) or C (other legal basis).
legalBasis string Legal basis as text, e.g. art. 43 ust. 1 pkt 19 ustawy o VAT.
showOnDocument boolean Whether to show the note on the PDF. Does not affect the document sent to KSeF (the exemption still maps to P_19/P_19A/P_19B/P_19C) — it only controls the PDF display.
{
  "annotations": {
    "isSplitPayment": true,
    "vatExemption": {
      "enabled": true,
      "exemptionType": "A",
      "legalBasis": "art. 113 ust. 1 ustawy o VAT"
    }
  }
}

Additional information (additionalInfo)

The KSeF FA(3) "Additional information" section — separate from annotations. For now it exposes a single field:

Field Type Meaning
isInvoiceToReceipt boolean Invoice issued to a receipt ("faktura do paragonu", art. 109 ust. 3d of the Polish VAT Act).

When you set isInvoiceToReceipt: true, the document sent to KSeF carries the <FP>1</FP> flag and the PDF shows the note "Faktura do paragonu, o której mowa w art. 109 ust. 3d ustawy". The document type (RodzajFaktury) does not change — this is a regular VAT invoice with an extra marker, not a separate document type. KSeF has no field for the receipt number, so the API does not accept one either.

{
  "additionalInfo": {
    "isInvoiceToReceipt": true
  }
}

Signatures (signatures)

Optional signature blocks on the PDF.

{
  "signatures": {
    "issuerSignature": { "show": true, "value": "Jan Nowak" },
    "receiverSignature": { "show": false }
  }
}

Other fields

  • ksefJst (boolean): document for a local-government unit for KSeF purposes.

Account defaults

A document issued through the API looks like a new document from the app editor: fields you do not send get the account's settings. A field you send always wins (including an empty string "" or an empty object {}), and useAccountDefaults: false switches all account defaults off.

Field Default
comments The comments from the document settings.
issuePlace The place of issue from the settings, or the company address city when empty.
signatures Signature fields per the signature setting; the issuer is the owner or the employee issuing the document.
annotations Automatic annotations (when enabled): split payment with the VAT account (vatAccountNumber from the account marked as VAT) and the margin procedure. Corrections do not get them.
annotations.vatExemption Lines with the zw rate get the exemption basis from the settings (type A/B/C and legal basis).
paymentMethodId 6 (bank transfer) with the default account.
paymentStatusId The default status from the settings: paid (payment date = issue date) or to pay (due date = issue date).
products[].vatRate The account's default VAT rate.
taxPointRule The default rule of the setting „Obowiązek podatkowy z datą wystawienia faktury” (tax point at the issue of the invoice; Settings → Autocomplete), when it is on and has a rule chosen. Applies to KSeF sales invoices other than corrections and advance invoices; an explicit taxPointRule: null does not get it.
seller The seller's visible fields from the settings (fieldsToShow).
PKWiU on the print Per the PKWiU display setting.

POST /documents/validate lists every applied default in preview.appliedDefaults (code, field, a sentence to show the user), and preview.resolved shows the payment, place, comments and annotations after them.

Corrections take the buyer, receiver, currency with its rate and annotations (with the VAT account) from the corrected invoice when you do not send them, so buyerId is optional for them. An invoice that has a correction cannot be changed or deleted (409 DOCUMENT_CORRECTED): another correction changes it. Once its last correction is deleted, the invoice is editable again.

FakturaProformaBezVAT always has 0 VAT on its lines, like in the app, whatever rate you send. FakturaZaliczka has no sale date.

Document types and their fields

The endpoint accepts ten types. Below are only the extra fields required per type; the sum-calculation rules for advances, settlements and corrections are in Document types & amounts.

Type What it is Extra required
Faktura Invoice outside KSeF (VAT-exempt entities, until end of 2026) -
FakturaVAT VAT invoice (the KSeF basic-invoice equivalent) -
FakturaProforma Proforma -
FakturaProformaBezVAT Proforma without VAT -
FakturaZaliczka Advance invoice linkedOrderId, advancePaymentAmount (no products)
FakturaRozliczeniowa Settlement (final) invoice linkedAdvanceInvoiceIds, products
FakturaKorygujaca Correction invoice correctedInvoiceId, products (the full "after" state); buyer from the corrected invoice
FakturaKorygujacaZaliczkowa Advance correction correctedInvoiceId, correctionAdvanceAmountAfter
FakturaKorygujacaRozliczeniowa Settlement correction correctedInvoiceId, correctionSettlementAmountAfter
Zamowienie Order -

Fields tied to special types:

Field Type For
linkedOrderId string FakturaZaliczka: the linked Zamowienie.
advancePaymentAmount number FakturaZaliczka: advance amount (≥ 0.01, ≤ order value).
linkedAdvanceInvoiceIds string[] FakturaRozliczeniowa: the advance invoices being settled.
settlementAmount number FakturaRozliczeniowa: amount to settle (auto, unless isSettlementAmountManual).
isSettlementAmountManual boolean FakturaRozliczeniowa: forces a manual settlementAmount.
correctedInvoiceId string Corrections: the invoice being corrected.
correctionReason string Corrections: reason (free text).
correctionAdvanceAmountAfter number FakturaKorygujacaZaliczkowa: new advance amount after correction.
correctionSettlementAmountAfter number FakturaKorygujacaRozliczeniowa: new settlement amount after correction.

Sums do not always equal Σ products. For advances, settlements and corrections, grossSum follows separate logic. If you mirror amounts on your side, take them from the API response, don't recompute them. Full formulas in Document types & amounts.

Dry-run validation

POST /external/v1/documents/validate runs the full pipeline (numbering, party resolution, sums) and returns a preview without saving the document. Ideal for showing a confirmation screen or testing an integration without cluttering the account.

Idempotency

Send an Idempotency-Key header (a UUID v4 is recommended). Repeating the same request with the same key returns the stored response instead of creating a duplicate (24 h cache). The same key with a different body returns an error. See Idempotency.

Common errors

Status Code Cause
400 VALIDATION_ERROR Invalid or missing type, date, VAT rate, field structure.
403 NO_PERMISSIONS Token without the documents:create scope.
404 DOCUMENT_NOT_FOUND Unknown buyerId, receiverId, correctedInvoiceId or linkedOrderId.
409 DOCUMENT_NUMBER_EXISTS The document number already exists.
422 DOCUMENT_DATES_INVALID The document's dates contradict each other or the VAT Act (see Sale dates).
422 PAYMENT_INSTALLMENTS_INVALID Instalments do not match the amount, the due dates or the payment status, or paymentInstallmentsSplit cannot be made.
422 ADVANCE_RECEIPTS_INVALID Advance receipts do not match the advance amount, the dates or the rates.
422 - Domain rules: advance larger than the order, isSplitPayment together with isCashMethod, missing required payment date, buyer NIP equal to seller NIP.

The full list of codes and the error envelope are in Errors.

What's next