API for developers · early access
KSeF Faktury API
You send a paid order as JSON. We assign a gapless invoice number, build the FA(3) XML checked against the official XSD, send it to KSeF and return the KSeF number and a PDF with the QR code. With test and live keys, idempotency and signed webhooks.
- OpenAPI 3.1 and a Postman collection
- KSeF TEST with no invoice limit
- Samples in cURL, PHP, Node.js and Python
curl -X POST https://app.ksefshop.pl/v1/invoices \
-H "Authorization: Bearer $KSEF_API_KEY" \
-H "Idempotency-Key: order-SO-1001" \
-H "Content-Type: application/json" \
-d '{
"order": {
"external_id": "SO-1001",
"number": "1001",
"paid_at": "2026-10-19T09:13:05Z",
"currency": "PLN",
"payment_method": "card",
"buyer": {
"nip": "5260250274",
"name": "Testowa Firma sp. z o.o.",
"address_line1": "ul. Prosta 20",
"address_line2": "00-850 Warszawa",
"email": "jan@example.com"
},
"lines": [
{
"name": "Kubek ceramiczny 350 ml",
"sku": "KUB-350",
"quantity": 2,
"unit_price": "49.00",
"vat_rate": "23"
},
{
"name": "Książka: Podstawy księgowości",
"sku": "KS-001",
"quantity": 1,
"unit_price": "59.90",
"discount": "9.90",
"vat_rate": "5"
}
],
"shipping": [
{
"name": "Kurier InPost",
"price": "15.99",
"vat_rate": "23"
}
]
}
}'<?php
$payload = [
'order' => [
'external_id' => 'SO-1001',
'number' => '1001',
'paid_at' => '2026-10-19T09:13:05Z',
'currency' => 'PLN',
'payment_method' => 'card',
'buyer' => [
'nip' => '5260250274',
'name' => 'Testowa Firma sp. z o.o.',
'address_line1' => 'ul. Prosta 20',
'address_line2' => '00-850 Warszawa',
'email' => 'jan@example.com',
],
'lines' => [
[
'name' => 'Kubek ceramiczny 350 ml',
'sku' => 'KUB-350',
'quantity' => 2,
'unit_price' => '49.00',
'vat_rate' => '23',
],
[
'name' => 'Książka: Podstawy księgowości',
'sku' => 'KS-001',
'quantity' => 1,
'unit_price' => '59.90',
'discount' => '9.90',
'vat_rate' => '5',
],
],
'shipping' => [
['name' => 'Kurier InPost', 'price' => '15.99', 'vat_rate' => '23'],
],
],
];
$ch = curl_init('https://app.ksefshop.pl/v1/invoices');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('KSEF_API_KEY'),
'Idempotency-Key: order-SO-1001',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_UNICODE),
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
$data = json_decode($body, true);
if ($status >= 400) {
throw new RuntimeException($data['error']['code'] . ': ' . $data['error']['message']);
}
echo var_export($data['id'], true), ' ', var_export($data['status'], true), PHP_EOL;const res = await fetch("https://app.ksefshop.pl/v1/invoices", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.KSEF_API_KEY}`,
"Idempotency-Key": "order-SO-1001",
"Content-Type": "application/json",
},
body: JSON.stringify({
order: {
external_id: "SO-1001",
number: "1001",
paid_at: "2026-10-19T09:13:05Z",
currency: "PLN",
payment_method: "card",
buyer: {
nip: "5260250274",
name: "Testowa Firma sp. z o.o.",
address_line1: "ul. Prosta 20",
address_line2: "00-850 Warszawa",
email: "jan@example.com",
},
lines: [
{
name: "Kubek ceramiczny 350 ml",
sku: "KUB-350",
quantity: 2,
unit_price: "49.00",
vat_rate: "23",
},
{
name: "Książka: Podstawy księgowości",
sku: "KS-001",
quantity: 1,
unit_price: "59.90",
discount: "9.90",
vat_rate: "5",
},
],
shipping: [
{ name: "Kurier InPost", price: "15.99", vat_rate: "23" },
],
},
}),
});
const data = await res.json();
if (!res.ok) throw new Error(`${data.error.code}: ${data.error.message}`);
console.log(data.id, data.status);import os
import requests
resp = requests.post(
"https://app.ksefshop.pl/v1/invoices",
headers={
"Authorization": f"Bearer {os.environ['KSEF_API_KEY']}",
"Idempotency-Key": "order-SO-1001",
},
json={
"order": {
"external_id": "SO-1001",
"number": "1001",
"paid_at": "2026-10-19T09:13:05Z",
"currency": "PLN",
"payment_method": "card",
"buyer": {
"nip": "5260250274",
"name": "Testowa Firma sp. z o.o.",
"address_line1": "ul. Prosta 20",
"address_line2": "00-850 Warszawa",
"email": "jan@example.com",
},
"lines": [
{
"name": "Kubek ceramiczny 350 ml",
"sku": "KUB-350",
"quantity": 2,
"unit_price": "49.00",
"vat_rate": "23",
},
{
"name": "Książka: Podstawy księgowości",
"sku": "KS-001",
"quantity": 1,
"unit_price": "59.90",
"discount": "9.90",
"vat_rate": "5",
},
],
"shipping": [
{"name": "Kurier InPost", "price": "15.99", "vat_rate": "23"},
],
},
},
timeout=30,
)
data = resp.json()
if not resp.ok:
raise RuntimeError(f"{data['error']['code']}: {data['error']['message']}")
print(data["id"], data["status"]){
"id": "inv_4fJ2kP9xQwErTy7uI0oPaSdF",
"object": "invoice",
"livemode": false,
"status": "accepted",
"order": {
"external_id": "SO-1001",
"number": "1001"
},
"number": "FV/2026/10/1",
"ksef_number": "4235405606-20261019-0E7570400000-57",
"ksef_environment": "test",
"issue_date": "2026-10-19",
"currency": "PLN",
"total_gross": "163.99",
"buyer_nip": "5260250274",
"pdf_url": "https://app.ksefshop.pl/pdf/cmgxa1b2c0000/Qk9tZ2FsX3ZhbGlkX3Rva2VuX2V4YW1w",
"last_error": null,
"created": 1760865185,
"updated": 1760865214,
"corrections": []
}What happens after you send an order
The request returns at once. The queue does the rest; you follow it in the status field, in events and in webhooks.
pendingThe API checked the order (NIP, VAT rates, amounts) and stored the document.queuedThe invoice got its number: gapless, separate for every month.sendingThe FA(3) XML, checked against the XSD, goes to KSeF with the seller's certificate or token.acceptedKSeF assigned the KSeF number. The PDF with the QR code is ready and emailed to the buyer.rejectedKSeF rejected the document. KSeF's code and our error code are in last_error.skippedThe order cannot be invoiced, e.g. a missing VAT rate. Reason in last_error.
Where to start
Quickstart
A test key, one order, the KSeF number and the PDF. Four requests.
Authentication and keys
sk_test_ and sk_live_ keys, the Bearer header, rolling, the KSeF certificate.
Webhooks
Event types, HMAC signatures in 4 languages, retries for 3 days.
Errors and codes
Every error code and how KSeF answers such as 440 map to them.
Idempotency
Retrying after network errors without duplicate invoices in KSeF.
Corrections and refunds
Returned items or shipping as a correction invoice.
Foreign currency and NBP rate
Invoices in EUR and other currencies, VAT in PLN at the NBP rate.
WooCommerce and PrestaShop
The WooCommerce plugin and a PrestaShop module sketch.
All endpoints
Every endpoint with fields, responses and samples.
What the API does
- FA(3) invoices from paid orders with a Polish NIP: 23, 8, 5 and 0% VAT, discounts, shipping, up to 1000 lines.
- Gapless numbering assigned in the queue, per month, with your own pattern.
- Sending to KSeF with your KSeF certificate or token, retried automatically when KSeF does not answer.
- PDF in the Ministry of Finance layout with the KSeF number and QR code, plus a public link for the buyer.
- Corrections for returned items and shipping, linked to the original invoice's KSeF number. Corrections
- Foreign currencies from NBP table A, with VAT in PLN at the NBP rate. Currencies
- Test and live keys with separate data, idempotency, signed webhooks and events for reconciliation.
- WooCommerce format: send a WooCommerce REST order as it is. WooCommerce
A Shopify store does not need the API: the KSeF Faktury app does the same with no code.
Specification and Postman collection
This documentation is generated from the OpenAPI 3.1 file we test the API against. The Postman collection has two folders: Reference (every endpoint) and Scenarios (first invoice, EUR, WooCommerce, wrong NIP, idempotency, correction, PDF, webhooks). Put your key in place of REPLACE_ME in the environments.
- openapi.yamlOpenAPI 3.1 specification · 42 KB
- ksef-faktury.postman_collection.jsonPostman collection v2.1 · 167 KB
- test.postman_environment.jsonEnvironment: test (KSeF TEST) · 392 B
- live.postman_environment.jsonEnvironment: live (after launch) · 392 B
- local.postman_environment.jsonEnvironment: localhost:3000 · 391 B