Fakturnia Developers Quickstart API reference Polski

Changelog

The API is versioned in the path (/external/v1). Breaking changes ship under a new major version; additive changes (new fields, new endpoints, new optional parameters) roll out within v1. Treat unknown response fields as forward-compatible: ignore what you don't recognise.

v1 (current)

2026-10-09: margin-scheme invoices

  • Margin lines. The rate vatRate: "marza" marks a line sold under the margin scheme (art. 119 and 120 of the VAT Act): the invoice shows gross amounts only, in KSeF the line has no P_12 and its sum goes to P_13_11. The document needs annotations.marginProcedure (otherwise 422 MARGIN_LINE_WITHOUT_PROCEDURE). Margin lines and regular rates can share one invoice.
  • Purchase amount and VAT on the margin. New line fields marginPurchaseValue (gross purchase amount in PLN) and marginTaxRate (23, 8, 5, 0) in POST, PUT and PATCH /documents and in GET /documents/{id} responses. They never appear on the invoice or in KSeF; the margin and the VAT on it in the VAT register and JPK_V7 come from them. New codes: 422 MARGIN_TAX_RATE_INVALID, 422 MARGIN_PURCHASE_INVALID. Guide: Margin scheme.
  • Purchase amount after issue. PATCH /documents/{id}/margin-purchases (scope documents:update, MCP tool updateDocumentMarginPurchases) sets the purchase amount and the margin VAT rate of margin lines also after the KSeF send. Codes 422 MARGIN_LINE_NOT_FOUND and 422 MARGIN_PURCHASES_INVALID. PUT and PATCH /documents/{id} without the margin fields on a line keep the stored values.
  • Margin sale in the preview. POST /documents/validate returns preview.totals.marginSaleSum (the margin sale inside netSum, P_13_11 in KSeF), and the MCP tool prepareDocument gives the net of the ordinary rates apart from the margin sale in its summary. The stored netSum keeps its meaning.
  • Correcting a margin invoice downloaded from KSeF. A margin-scheme sales invoice issued in another program (lines without P_12, the sum in P_13_11) gets lines with the marza rate once read and can be corrected. 422 CORRECTED_INVOICE_MARGIN_LINES remains only for lines without a rate on an invoice without the margin procedure annotation.

2026-10-09: correcting a sales invoice downloaded from KSeF

  • Correction of an invoice issued outside Fakturnia. POST /documents accepts in correctedInvoiceId a sales invoice downloaded from KSeF (source: "ksef", direction: "income", type FakturaVAT). The API reads its lines, totals and buyer address from the invoice XML (fetching it from KSeF when needed), computes the correction as a difference and names the KSeF number of the original invoice in KSeF. New codes: 422 CORRECTED_INVOICE_NOT_INCOME, 422 CORRECTED_INVOICE_WITHOUT_POSITIONS; CORRECTED_INVOICE_TYPE_MISMATCH now also covers imports of other types. Guide: Corrections.
  • Lines of invoices downloaded from KSeF. GET /documents/{id} of an invoice downloaded from KSeF returns products, netSum and vatSum once its XML has been read (after it was opened in the app or corrected); such invoices used to carry only grossSum.

2026-10-09: contractor identifiers ready for KSeF

  • One set of identifier rules for contractors and document parties. POST and PUT /clients and a buyer and receiver given as data in POST /documents, POST /documents/validate, PUT and PATCH /documents/{id} store identifiers in the form KSeF accepts: the NIP as 10 digits, the VAT UE number with its country prefix in vatUE (Greece EL), other with a country. Guide: Contractor identifiers.
  • A VAT UE number typed in nip goes to vatUE. Without identifierType the number DE123456789 in nip is stored as vatEu in vatUE with countryCode from the prefix, not as a NIP.
  • Warnings in data.warnings. Contractor and document responses (also validate) say how the identifiers were read: an inferred type, a moved number, an inferred country (code, field, message). The MCP tool prepareDocument returns them in identifierNotes.
  • Contradictions are refused. Contractors: 422 VALIDATION_ERROR, documents: the new code 422 PARTY_IDENTIFIER_INVALID, always naming the field. This also covers a NIP with a wrong check digit sent without identifierType (accepted before) and an idWew in a form other than NIP-NNNNN.
  • Data saved earlier stays editable. Identifiers equal to the stored ones are not re-checked on PUT /clients or on PUT and PATCH of a document.

2026-10-09: FA(3) dates, instalments, several advance receipts, the day of payment

  • Sale period: subDateTo. With subDate as its start it gives OkresFa in KSeF (e.g. a service for a whole month). PATCH keeps a stored period and date label.
  • Exchange rate with its NBP day and table: exchangeRateDate, exchangeRateTable. An invoice's rate is the rate of the business day before the tax point, or before the issue date when the invoice comes first (art. 31a of the VAT Act). A correction without exchangeRate takes the corrected invoice's rate, day and table (art. 31b ust. 1).
  • Tax point at the issue of the invoice: taxPointRule. For construction services, books and press, utilities, telecommunications, rent, leasing, security and ongoing services (art. 19a ust. 5 pkt 3 and 4). It decides the period in VAT reports and the day of the rate. When the account has the setting on with a default rule, a document without taxPointRule gets it from the settings (preview.appliedDefaults: TAX_POINT_RULE); useAccountDefaults: false or an explicit null skips it.
  • Instalments and a due date in words: paymentInstallments, paymentDeadlineTerm. Several due dates with amounts, or a term like "14 days from delivery of the invoice"; TerminPlatnosci and TerminOpis in KSeF. Inconsistent instalments: 422 PAYMENT_INSTALLMENTS_INVALID. Guide: Creating documents.
  • Equal instalments computed by the API: paymentInstallmentsSplit. POST, PUT and PATCH /documents and POST /documents/validate accept { count, firstDate?, every? }; the API splits the amount due to the grosz (the remainder on the last instalment) and stores ordinary paymentInstallments. The validate preview lists them in preview.paymentInstallments, and the MCP tools prepareDocument and patchDocument take the same field. Guide: Creating documents.
  • Several receipts on an advance invoice: advanceReceipts. Each receipt with its date, amount and rate; ZaliczkaCzesciowa in KSeF. Inconsistent receipts: 422 ADVANCE_RECEIPTS_INVALID.
  • Correction dates: correctionEffectDate, correctionConfirmationDate. The day the correction takes effect (an increase after the sale whose cause arose in another month gives TypKorekty 3) and the day the buyer confirmed a correction issued outside KSeF. A correction without subDate takes the sale date or period of the corrected invoice. Guide: Correcting documents.
  • The day of payment when marking it. PATCH /documents/{id}/payment-status accepts paymentDate (today in Poland by default, never in the future); GET returns it as payment.receivedPaymentDate. For the cash method it is the tax point.
  • Dates checked like in the app: 422 DOCUMENT_DATES_INVALID. A sale period starting after its end, a sale date more than 60 days after the issue, a payment date after the issue, a correction issued before the corrected invoice. PUT and PATCH also check the date format.
  • KSeF: more dates in the XML. Place of issue (P_1M), instalments and a due date in words, advance receipts. A date with a time is the day in Poland, and an unreadable date is a validation error instead of today's date.

All new fields are optional: integrations that do not send them work as before.

2026-10-09: correction of a correction

  • One correction per document. A new correction of a document that already has one gets 409 CORRECTED_INVOICE_HAS_CORRECTION with the number and the id of the latest correction of the chain in errors[0]. You issue the next change as a correction of that correction, so its "before" state includes the earlier changes and the amounts do not count them twice. PUT and PATCH answer the same when you move a correction to a document that has another correction. Guide: Correcting documents.
  • A correction of a correction names the original invoice in KSeF. DaneFaKorygowanej gives the number, date and KSeF number of the original invoice, not of the previous correction (KSeF 2.0 manual, part II, section 2.13.3). The printout shows the original invoice and the previous correction.
  • Original invoice without a KSeF number. POST /documents/validate returns notes that do not stop the document in preview.warnings. On an account connected to KSeF, a correction whose original invoice has no KSeF number gets the code CORRECTION_ORIGINAL_KSEF_PENDING, CORRECTION_ORIGINAL_NOT_SENT_TO_KSEF or CORRECTION_ORIGINAL_OUTSIDE_KSEF. Sending to KSeF works as before. Guide: Correcting documents.
  • Correction of an advance correction. FakturaKorygujacaZaliczkowa can correct a previous advance correction: the order and the advance before the correction are the state after it.

2026-10-09: cause and type of a correction, limit of the correction reason

  • Cause of a correction (correctionCause) and its KSeF type (correctionType). A correction can say why you issue it: after_sale (an event after the sale: discount, return, complaint) or mistake (an error on the corrected invoice). From the cause and the amounts Fakturnia works out the TypKorekty sent to KSeF, until now always 2; correctionType (1, 2, 3) sets it by hand. POST, PUT and PATCH /documents accept both fields, and GET /documents/{id} and the document webhooks return them. The cause also decides the period of the correction in the app's reports (VAT register, JPK_V7, KPiR). Integrations that do not send the new fields work as before. Guide: Correcting documents.
  • Correction reason up to 256 characters. That is what KSeF accepts in PrzyczynaKorekty. A longer correctionReason now gets a validation error right away (400 on POST, 422 on PUT and PATCH) instead of a rejection by KSeF when sending.

2026-10-02: KSeF connection with a token

  • KSeF token as a connection method. POST /ksef/connection accepts connectionType: TOKEN with a token generated in the KSeF Taxpayer Application, or a certificate as before (connectionType: CERTIFICATE). Saving one method replaces the other. GET /ksef/connection reports connectionType, hasToken and hasCertificate.

2026-10-01: webhooks for documents from the app and from KSeF, rate limits, unique numbers

  • document.created for documents created in the app. A document saved in the web or mobile app (drafts and warehouse documents included) fires document.created, like a document from the API, MCP or a recurring rule. A correction issued in the app also fires document.updated for the corrected invoice. You no longer need to poll GET /documents to see documents issued in the app. Guide: Webhooks.
  • Issuing a draft in the app fires document.updated. The same event arrives when a document is turned back into a draft and when its isSent, isPrinted or isDownloaded mark changes in the app (the first print or download included), always only on a real change. An integration knows right away when a draft became an issued document (isDraft: false).
  • Invoices downloaded from KSeF: document.ksefImported. A KSeF sync reports new invoices (purchase invoices and sales invoices issued outside Fakturnia) with one event carrying data.documentIds, up to 100 ids per delivery; a larger import arrives as several deliveries. These invoices do not fire document.created.
  • source and direction on documents. GET /documents and GET /documents/{id} return source (local or ksef) and direction (income, expense or order), so a purchase invoice from KSeF is not mistaken for your own sale.
  • More events from the app. document.updated after a warehouse release is confirmed or reverted, after the last correction is deleted (for the corrected invoice), after a WZ is issued for an invoice (for the invoice), after a recurring rule e-mails its document and when a KSeF sync adds a KSeF number; client.created for a contractor saved from the buyer data of an API or MCP document; client.updated when e-mail addresses are saved on a contractor.
  • Rate limits count per application. The counters in the Rate limits table now belong to the application (API account) identified by the token, not to the IP address, so several integrations behind one NAT no longer share a budget. A new general limit of 240 requests per minute per IP address is checked before authentication; requests with a missing, invalid or expired token count only against it. The 429 RATE_LIMIT_EXCEEDED code and the headers are unchanged.
  • Document numbers are unique across the account. POST /documents and PUT / PATCH /documents/{id} return 409 DOCUMENT_NUMBER_EXISTS also when a document of another type (e.g. a proforma and a proforma without VAT sharing a symbol) or a document moved to another month already has the same full number. PUT and PATCH check this when you change the number, and the message in errors[0] names the document that holds it.
  • The document schema in the OpenAPI spec lists every field the API returns: isDraft, invoiceName, externalSource, externalOrderId, externalOrderNumber, correctionAdvanceAmountAfter, correctionSettlementAmountAfter, ksefNumber, ksefReferenceNumber, ksefStatus and ksefSent. API responses did not change: these fields were already there.

2026-09-27 (spec version 1.3.0): warehouse documents and account defaults

  • Warehouse documents through the API. POST /warehouse/documents issues WZ, PZ, PW, RW and MM with catalogue lines and books the movements; POST /warehouse/documents/validate returns a preview with the stock before and after. New scope warehouse:documents:create. Guide: Warehouse.
  • Missing goods block an issue. WZ, RW and MM (including wz-from-invoice) that would take stock below zero get 422 STOCK_SHORTAGE, like in the app; allowNegativeStock: true issues them anyway.
  • WZ for an invoice gets the WZ symbol and the account settings, checks the warehouse (422 WAREHOUSE_INVALID) and stores the WZ number on the invoice (print and KSeF).
  • Account defaults when creating documents: comments, signatures, place of issue, automatic annotations (split payment with the VAT account, margin), exemption basis for the zw rate, payment method and status, line VAT rate, PKWiU display. New field useAccountDefaults, preview preview.appliedDefaults and preview.resolved. Guide: Creating documents.
  • Corrections take the buyer, receiver, currency and annotations from the corrected invoice; an invoice with a correction, a settled advance invoice and an order with advance invoices cannot be changed or deleted (409 DOCUMENT_CORRECTED, 409 ADVANCE_INVOICE_SETTLED, 400 ORDER_HAS_ADVANCE_INVOICES).
  • Advance invoice without lines (the lines are the split of the advance) and without a sale date; proforma without VAT always has 0 VAT.
  • KSeF: the margin procedure reaches the XML (P_PMarzy with the procedure flag); an unknown procedure number is a validation error. A VAT exemption enabled without a type or legal basis is rejected.
  • Products: warehouse fields productType, sku, ean, purchasePrice in reads, creation and updates (updates only the ones sent); quantity optional on creation.
  • Warehouse documents through /documents: deleting reverses the movements, changing the date moves them, changing the lines returns 409 WAREHOUSE_LINES_LOCKED. A stock adjustment with quantity: 0 and unitCost is a revaluation (WYCENA).

2026-09-26: MCP server

  • MCP server for AI assistants. https://prod.api.fakturnia.pl/mcp (sandbox: https://sandbox.api.fakturnia.pl/mcp): ChatGPT, Claude, Claude Code and custom agents work on a user's account after an OAuth 2.1 sign-in (RFC 9728/8414 discovery, PKCE, dynamic registration, client ID metadata documents, refresh token rotation) or with an fmcp_… key. Tools generated from this specification plus guided document issuing (prepareDocument, issueDocument), confirm=true on irreversible operations, employee permissions, plan gate. Guide: MCP server.

2026-09 (spec version 1.2.0)

  • The REST API is a MAX plan module. API accounts, every /external/v1 endpoint and webhooks require an active MAX plan. The token endpoint answers 403 access_denied with error_code: SUBSCRIPTION_REQUIRED, calls with a token 403 SUBSCRIPTION_REQUIRED. Described in Authentication.
  • Stable error codes across the envelope. 401 returns UNAUTHORIZED or TOKEN_EXPIRED, 403 without a scope NO_PERMISSIONS, 429 RATE_LIMIT_EXCEEDED; the explanatory sentence moves to errors[0]. Body validation errors carry the VALIDATION_ERROR code, usually with status 422; creating documents (warehouse documents included) answers 400 for request-shape problems, so treat both statuses as a validation failure. New code table in Errors.
  • Revoking an API account and the IP allowlist take effect immediately, on every call, not only when the token expires (401 UNAUTHORIZED, 403 FORBIDDEN).
  • Webhooks: full management. POST /webhooks with a choice of events, GET/PATCH/DELETE /webhooks/{id}, secret rotation, delivery history (/deliveries) and a test ping (/test). New scopes webhooks:update and webhooks:delete. Guide: Webhooks.
  • Webhooks: new delivery body. Every delivery carries an id (also in the X-Webhook-Delivery header) and a data block with the id named after the resource type (documentId, clientId, ...). resourceId/resourceIds stay for compatibility. Schema WebhookEventPayload in the spec.
  • New events document.ksefRejected (KSeF rejected the document or the send failed) and document.paymentStatusChanged (payment marked or reverted). document.sentToKSeF now also fires for sends from the app and the queue, and document.updated after an order link.
  • Email accounts (read-only). GET /email-accounts and GET /email-accounts/{id} with the scopes email-accounts:browse and email-accounts:read; no secrets. Guide: Email accounts.
  • Complete OpenAPI specification. Every operation has a description, a response schema with the shape of data, a request body schema with an example, and documented 401/403/429/500. New headers X-Request-ID, X-RateLimit-*, Retry-After, Idempotent-Replayed. The Postman collection takes request examples from the spec.
  • History through the API. GET /documents/{id}/history (document journal), GET /activity (whole-account activity, new scope activity:read), GET /employees/{id}/activity (employee activity) and GET /warehouse/movements (stock ledger). Guide: History & activity.
  • New reads by id: GET /warehouse/{id}, GET /employees/{id}; the stock report accepts productId.
  • Pagination for lists that lacked it: GET /recurring-rules, GET /recurring-rules/{id}/history and GET /webhooks/{id}/deliveries return currentPage, itemsPerPage, totalCount, totalPages (limit still works as an alias of itemsPerPage).
  • Lists up to 100 items per page (itemsPerPage, previously 20) in GET /documents, /clients, /products.
  • Deletes return data.id for documents, contractors and products too; DELETE /documents/{id}/external-reference returns the cleared link fields.

2026-07

  • Recurring documents in the API. New /recurring-rules endpoints: rule list with a summary (statuses, next generation, monthly recurring gross), rule details, generation history, and pause/resume. New recurring:* scopes (3). Requires the MAX plan. Guide: Recurring documents.
  • Warehouse module in the API. New /warehouse endpoints: warehouses (CRUD), stock adjustments (stocktaking), a stock report with the asOf parameter and automatic WZ documents for sales invoices. Requires the MAX plan. Guide: Warehouse.
  • Employees and permissions in the API. New /employees endpoints: permission registry, creating and updating employee accounts, deactivation and deletion. Guide: Employees & permissions.
  • New scopes: warehouse:* (7) and employees:* (4), described in Authentication.
  • The documentType filter on the document list now also accepts warehouse types (e.g. WZ).
  • Document list filters. GET /documents accepts documentType (a single type or a comma-separated list) and an issue-date range via dateFrom/dateTo. See Pagination and filtering.
  • The Postman collection and the CLI cover the whole API (products, settings, webhooks, KSeF connection, auth/me, company lookup by NIP, order references).
  • New guides. Clients, Products, Settings, KSeF connection, Order references and Company lookup.

2026-06

  • Beta available in the sandbox environment. The API can be tested at sandbox.app.fakturnia.pl.
  • Amounts unified to grosz-exact, round half-up. Per-line and per-document totals now match the fakturnia-shared engine exactly. netValue + amountOfVat === grossValue on every line.
  • FakturaRozliczeniowa now derives grossSum from settlementAmount (remaining to pay = lines − linked advances) instead of the full line total; linked advance metadata is populated automatically.
  • FakturaZaliczka totals derive from the proportional advance breakdown (grossSum === advancePaymentAmount).
  • FakturaProforma / FakturaProformaBezVAT accepted by POST /documents.
  • Advance/settlement corrections (FakturaKorygujacaZaliczkowa, FakturaKorygujacaRozliczeniowa) compute the amount delta with proportional VAT.
  • PUT and PATCH /documents/{id}; multiple bankAccounts[] on create/update.

Versioning policy

  • Path-versioned. v1 is stable. A v2 would only appear for breaking changes.
  • Additive within v1. New optional request fields and new response fields can appear without a version bump.
  • Deprecations are announced here with a migration window before removal.

Subscribe to changes by watching this page or the OpenAPI spec (its info.version tracks releases).