API reference
Invoices and corrections
An invoice comes from a paid order and goes through the queue: number, FA(3) XML, KSeF, PDF. A correction comes from a refund and refers to the invoice's KSeF number. Both documents share statuses and fields.
The Invoice object
A VAT invoice issued from a paid order. Its corrections are nested in corrections.
Attributes
idstringrequiredDocument id.
Prefix
inv_objectstringrequiredObject type.
One of:
invoice,correction· Alwaysinvoicelivemodebooleanrequiredtruein live mode,falsein test mode.statusstringrequiredpending→queued→sending→accepted,rejectedorerror; orskipped(cannot be invoiced) andwaiting_for_plan_limit(plan limit used up).One of:
pending,queued,sending,accepted,rejected,skipped,waiting_for_plan_limit,errororderobjectrequiredThe order the document comes from.
Show fields
external_idstringrequiredYour order id.
numberstring | nullrequiredOrder number.
numberstring | nullrequiredInvoice number (gapless per month)
ksef_numberstring | nullrequiredKSeF number
ksef_environmentstringrequiredKSeF environment:
testfor test keys,prodfor live keys.One of:
test,demo,prodissue_datestring | nullrequiredIssue date.
date
currencystring | nullrequiredInvoice currency.
total_grossstring | nullrequiredGross total in the invoice currency (negative for corrections).
buyer_nipstring | nullrequiredBuyer NIP.
pdf_urlstring | nullrequiredPublic link with an unguessable token
last_errornull | ErrorrequiredThe document's last error or
null. Error codesShow fields
typestringrequiredError category.
One of:
invalid_request_error,authentication_error,permission_error,not_found_error,idempotency_error,rate_limit_error,invoice_error,ksef_error,api_errorcodestringrequiredStable machine-readable code. All codes
One of:
parameter_missing,parameter_invalid,body_invalid_json,body_too_large,buyer_nip_missing,buyer_nip_invalid,order_not_paid,order_cancelled,currency_not_supported,vat_rate_missing,vat_rate_unsupported,order_unprocessable,correction_requires_invoice,livemode_mismatch,resource_missing,route_not_found,method_not_allowed,pdf_not_ready,api_key_missing,api_key_invalid,live_mode_disabled,idempotency_key_reused,idempotency_key_invalid,rate_limited,internal_error,seller_not_configured,plan_limit_reached,invoice_build_failed,invoice_schema_invalid,original_not_invoiced,original_rejected,ksef_not_connected,ksef_auth_failed,ksef_duplicate_number,ksef_rejected,ksef_unavailablemessagestringrequiredHuman-readable text; may change.
paramstringJSON path of the parameter
ksef_codeintegerKSeF's own numeric code (e.g. 440 duplicate
doc_urlstringrequiredLink to the code on the errors page.
createdintegerrequiredCreated (Unix seconds).
updatedintegerrequiredLast change (Unix seconds).
correctionsarray of CorrectionrequiredCorrections of this invoice.
{
"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": []
}The Correction object
A correction invoice (KOR) issued from a refund. Same fields as an invoice, plus invoice and refund.
Attributes
idstringrequiredDocument id.
Prefix
cor_objectstringrequiredObject type.
One of:
invoice,correction· Alwayscorrectionlivemodebooleanrequiredtruein live mode,falsein test mode.statusstringrequiredpending→queued→sending→accepted,rejectedorerror; orskipped(cannot be invoiced) andwaiting_for_plan_limit(plan limit used up).One of:
pending,queued,sending,accepted,rejected,skipped,waiting_for_plan_limit,errororderobjectrequiredThe order the document comes from.
Show fields
external_idstringrequiredYour order id.
numberstring | nullrequiredOrder number.
numberstring | nullrequiredInvoice number (gapless per month)
ksef_numberstring | nullrequiredKSeF number
ksef_environmentstringrequiredKSeF environment:
testfor test keys,prodfor live keys.One of:
test,demo,prodissue_datestring | nullrequiredIssue date.
date
currencystring | nullrequiredInvoice currency.
total_grossstring | nullrequiredGross total in the invoice currency (negative for corrections).
buyer_nipstring | nullrequiredBuyer NIP.
pdf_urlstring | nullrequiredPublic link with an unguessable token
last_errornull | ErrorrequiredThe document's last error or
null. Error codesShow fields
typestringrequiredError category.
One of:
invalid_request_error,authentication_error,permission_error,not_found_error,idempotency_error,rate_limit_error,invoice_error,ksef_error,api_errorcodestringrequiredStable machine-readable code. All codes
One of:
parameter_missing,parameter_invalid,body_invalid_json,body_too_large,buyer_nip_missing,buyer_nip_invalid,order_not_paid,order_cancelled,currency_not_supported,vat_rate_missing,vat_rate_unsupported,order_unprocessable,correction_requires_invoice,livemode_mismatch,resource_missing,route_not_found,method_not_allowed,pdf_not_ready,api_key_missing,api_key_invalid,live_mode_disabled,idempotency_key_reused,idempotency_key_invalid,rate_limited,internal_error,seller_not_configured,plan_limit_reached,invoice_build_failed,invoice_schema_invalid,original_not_invoiced,original_rejected,ksef_not_connected,ksef_auth_failed,ksef_duplicate_number,ksef_rejected,ksef_unavailablemessagestringrequiredHuman-readable text; may change.
paramstringJSON path of the parameter
ksef_codeintegerKSeF's own numeric code (e.g. 440 duplicate
doc_urlstringrequiredLink to the code on the errors page.
createdintegerrequiredCreated (Unix seconds).
updatedintegerrequiredLast change (Unix seconds).
invoicestring | nullrequiredId of the corrected invoice.
refundobjectrequiredThe refund the correction comes from.
Show fields
external_idstringrequiredYour refund id.
{
"id": "cor_8hG3jK2lMnBvCxZ1aS4dF6gH",
"object": "correction",
"livemode": false,
"status": "pending",
"order": {
"external_id": "SO-1001",
"number": null
},
"number": null,
"ksef_number": null,
"ksef_environment": "test",
"issue_date": null,
"currency": null,
"total_gross": null,
"buyer_nip": null,
"pdf_url": null,
"last_error": null,
"created": 1760951000,
"updated": 1760951000,
"invoice": "inv_4fJ2kP9xQwErTy7uI0oPaSdF",
"refund": {
"external_id": "RF-1"
}
}List invoices
GET /v1/invoices
Invoices, newest first, with their corrections nested. Paginate with limit and starting_after; external_id returns the invoice of one order.
Parameters
limitquery · integerHow many objects per page.
Default
10· 1-100starting_afterquery · stringId of the last object of the previous page.
external_idquery · stringOnly the invoice of this order.
Responses
- 200A page of invoices.
- 400Invalid request, e.g.
parameter_invalidbuyer_nip_invalidvat_rate_unsupported - 401Missing or invalid key:
api_key_missingapi_key_invalid - 404No such object (or it belongs to another account or mode):
resource_missing - 429Rate limit exceeded, wait
Retry-Afterseconds:rate_limited
curl "https://app.ksefshop.pl/v1/invoices?limit=10" \
-H "Authorization: Bearer $KSEF_API_KEY"<?php
$ch = curl_init('https://app.ksefshop.pl/v1/invoices?limit=10');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('KSEF_API_KEY'),
],
]);
$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 count($data['data']), ' objects', PHP_EOL;const res = await fetch("https://app.ksefshop.pl/v1/invoices?limit=10", {
headers: {
Authorization: `Bearer ${process.env.KSEF_API_KEY}`,
},
});
const data = await res.json();
if (!res.ok) throw new Error(`${data.error.code}: ${data.error.message}`);
console.log(data.data.length, data.has_more);import os
import requests
resp = requests.get(
"https://app.ksefshop.pl/v1/invoices?limit=10",
headers={
"Authorization": f"Bearer {os.environ['KSEF_API_KEY']}",
},
timeout=30,
)
data = resp.json()
if not resp.ok:
raise RuntimeError(f"{data['error']['code']}: {data['error']['message']}")
print(len(data["data"]), data["has_more"]){
"object": "list",
"url": "/v1/invoices",
"has_more": false,
"data": []
}{
"error": {
"type": "invalid_request_error",
"code": "buyer_nip_invalid",
"message": "buyer.nip is not a valid Polish NIP (checksum).",
"param": "order.buyer.nip",
"doc_url": "https://ksefshop.pl/api/errors#buyer_nip_invalid"
}
}{
"error": {
"type": "authentication_error",
"code": "api_key_invalid",
"message": "The API key is wrong, revoked, or the account is disabled.",
"doc_url": "https://ksefshop.pl/api/errors#api_key_invalid"
}
}{
"error": {
"type": "not_found_error",
"code": "resource_missing",
"message": "No such invoice: 'inv_4fJ2kP9xQwErTy7uI0oPaSdF'",
"doc_url": "https://ksefshop.pl/api/errors#resource_missing"
}
}Create an invoice from a paid order
POST /v1/invoices
Takes a paid order and answers at once with an invoice in status pending. The queue numbers it, builds FA(3), sends it to KSeF and renders the PDF; usually it is accepted after 10-60 seconds. The buyer needs a valid Polish NIP.
Send order (neutral format, gross prices) or woocommerce_order (a WooCommerce REST API v3 order). The same external_id returns the existing invoice with 200 instead of 201.
Parameters
Idempotency-Keyheader · stringAny unique text (1-255 characters), e.g.
order-SO-1001. A retry with the same key within 24 hours returns the first response. Idempotency
Request body (JSON)
Exactly one of order or woocommerce_order.
orderOrderThe order in the neutral format (gross prices, explicit VAT rates).
Show fields
external_idstringrequiredYour order id; one invoice per external_id.
numberstringOrder number printed on the invoice (defaults to external_id).
created_atstringWhen the order was placed.
ISO 8601 date and time
paid_atstringrequiredPayment time; the tax point and the NBP rate date follow it.
ISO 8601 date and time
currencystringPLN or a currency of NBP table A.
Default
PLNpayment_methodstringPayment method printed on the invoice.
One of:
card,transfer,cash,mobile· DefaultcardbuyerobjectrequiredThe buyer, with a Polish NIP.
Show fields
nipstringrequiredPolish NIP
namestringrequiredThe buyer's company name.
address_line1stringrequiredStreet and number.
address_line2stringPostal code and city.
emailstringThe PDF is emailed here.
linesarray of OrderLinerequiredOrder lines.
1-1000 items
Show fields
namestringrequiredProduct or service name.
max 512 characters
skustringProduct code (optional).
quantityintegerrequiredQuantity.
unit_pricedecimal stringrequiredAmount as a string with a dot, e.g.
"49.00"discountdecimal stringAmount as a string with a dot, e.g.
"49.00"vat_ratestringrequiredVAT rate:
23,8,5or0(0% domestic). Exempt supplies (zw) are not supported yet.One of:
23,8,5,0
shippingarray of objectShipping charges as separate lines.
Show fields
namestringrequiredShipping name, e.g. "Courier".
pricedecimal stringrequiredGross shipping price.
Amount as a string with a dot, e.g.
"49.00"vat_ratestringrequiredVAT rate of the shipping.
One of:
23,8,5,0
woocommerce_orderobjectWooCommerce REST API v3 order (fields id, number, status, currency, dates, billing, meta_data with the NIP, line_items, shipping_lines, fee_lines, tax_lines).
Responses
- 200An invoice for this
external_idalready exists (or anIdempotency-Keyreplay). - 201New invoice, status
pending. - 400Invalid request, e.g.
parameter_invalidbuyer_nip_invalidvat_rate_unsupported - 401Missing or invalid key:
api_key_missingapi_key_invalid - 403Live mode is not enabled yet:
live_mode_disabled - 409Idempotency-Key reused with another request, or the PDF is not ready:
idempotency_key_reusedpdf_not_ready - 413Invalid request, e.g.
parameter_invalidbuyer_nip_invalidvat_rate_unsupported - 422The order cannot become an invoice:
order_unprocessable - 429Rate limit exceeded, wait
Retry-Afterseconds:rate_limited - 500Our error; retry with the same
Idempotency-Key:internal_error
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": []
}{
"id": "inv_4fJ2kP9xQwErTy7uI0oPaSdF",
"object": "invoice",
"livemode": false,
"status": "pending",
"order": {
"external_id": "SO-1001",
"number": null
},
"number": null,
"ksef_number": null,
"ksef_environment": "test",
"issue_date": null,
"currency": null,
"total_gross": null,
"buyer_nip": null,
"pdf_url": null,
"last_error": null,
"created": 1760865185,
"updated": 1760865185,
"corrections": []
}{
"error": {
"type": "invalid_request_error",
"code": "buyer_nip_invalid",
"message": "buyer.nip is not a valid Polish NIP (checksum).",
"param": "order.buyer.nip",
"doc_url": "https://ksefshop.pl/api/errors#buyer_nip_invalid"
}
}{
"error": {
"type": "authentication_error",
"code": "api_key_invalid",
"message": "The API key is wrong, revoked, or the account is disabled.",
"doc_url": "https://ksefshop.pl/api/errors#api_key_invalid"
}
}Retrieve an invoice or a correction
GET /v1/invoices/{id}
Returns an invoice (inv_..., with its corrections) or a correction (cor_...). Use it to check the status, the KSeF number and last_error.
Parameters
idpath · stringrequiredThe object's id.
Prefix
inv_/cor_
Responses
- 200The invoice or the correction.
- 400Invalid request, e.g.
parameter_invalidbuyer_nip_invalidvat_rate_unsupported - 401Missing or invalid key:
api_key_missingapi_key_invalid - 404No such object (or it belongs to another account or mode):
resource_missing - 429Rate limit exceeded, wait
Retry-Afterseconds:rate_limited
curl https://app.ksefshop.pl/v1/invoices/inv_4fJ2kP9xQwErTy7uI0oPaSdF \
-H "Authorization: Bearer $KSEF_API_KEY"<?php
$ch = curl_init('https://app.ksefshop.pl/v1/invoices/inv_4fJ2kP9xQwErTy7uI0oPaSdF');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('KSEF_API_KEY'),
],
]);
$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['status'], true), ' ', var_export($data['ksef_number'], true), PHP_EOL;const res = await fetch("https://app.ksefshop.pl/v1/invoices/inv_4fJ2kP9xQwErTy7uI0oPaSdF", {
headers: {
Authorization: `Bearer ${process.env.KSEF_API_KEY}`,
},
});
const data = await res.json();
if (!res.ok) throw new Error(`${data.error.code}: ${data.error.message}`);
console.log(data.status, data.ksef_number);import os
import requests
resp = requests.get(
"https://app.ksefshop.pl/v1/invoices/inv_4fJ2kP9xQwErTy7uI0oPaSdF",
headers={
"Authorization": f"Bearer {os.environ['KSEF_API_KEY']}",
},
timeout=30,
)
data = resp.json()
if not resp.ok:
raise RuntimeError(f"{data['error']['code']}: {data['error']['message']}")
print(data["status"], data["ksef_number"]){
"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": []
}{
"error": {
"type": "invalid_request_error",
"code": "buyer_nip_invalid",
"message": "buyer.nip is not a valid Polish NIP (checksum).",
"param": "order.buyer.nip",
"doc_url": "https://ksefshop.pl/api/errors#buyer_nip_invalid"
}
}{
"error": {
"type": "authentication_error",
"code": "api_key_invalid",
"message": "The API key is wrong, revoked, or the account is disabled.",
"doc_url": "https://ksefshop.pl/api/errors#api_key_invalid"
}
}{
"error": {
"type": "not_found_error",
"code": "resource_missing",
"message": "No such invoice: 'inv_4fJ2kP9xQwErTy7uI0oPaSdF'",
"doc_url": "https://ksefshop.pl/api/errors#resource_missing"
}
}Download the PDF
GET /v1/invoices/{id}/pdf
The PDF in the Ministry of Finance layout, with the KSeF number and the KOD I verification QR code. While it renders you get 409 pdf_not_ready. For the buyer, share the public pdf_url of the invoice object instead.
Parameters
idpath · stringrequiredThe object's id.
Prefix
inv_/cor_
Responses
- 200The PDF file.
- 401Missing or invalid key:
api_key_missingapi_key_invalid - 404No such object (or it belongs to another account or mode):
resource_missing - 409Idempotency-Key reused with another request, or the PDF is not ready:
idempotency_key_reusedpdf_not_ready
curl https://app.ksefshop.pl/v1/invoices/inv_4fJ2kP9xQwErTy7uI0oPaSdF/pdf \
-H "Authorization: Bearer $KSEF_API_KEY" \
--fail -o invoice.pdf<?php
$ch = curl_init('https://app.ksefshop.pl/v1/invoices/inv_4fJ2kP9xQwErTy7uI0oPaSdF/pdf');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('KSEF_API_KEY'),
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
if ($status !== 200) {
throw new RuntimeException('PDF: HTTP ' . $status); // 409 pdf_not_ready: retry in a few seconds
}
file_put_contents('invoice.pdf', $body);import { writeFile } from "node:fs/promises";
const res = await fetch("https://app.ksefshop.pl/v1/invoices/inv_4fJ2kP9xQwErTy7uI0oPaSdF/pdf", {
headers: {
Authorization: `Bearer ${process.env.KSEF_API_KEY}`,
},
});
if (!res.ok) throw new Error(`PDF: HTTP ${res.status}`); // 409 pdf_not_ready: retry in a few seconds
await writeFile("invoice.pdf", Buffer.from(await res.arrayBuffer()));import os
import requests
resp = requests.get(
"https://app.ksefshop.pl/v1/invoices/inv_4fJ2kP9xQwErTy7uI0oPaSdF/pdf",
headers={
"Authorization": f"Bearer {os.environ['KSEF_API_KEY']}",
},
timeout=30,
)
resp.raise_for_status() # 409 pdf_not_ready: retry in a few seconds
with open("invoice.pdf", "wb") as f:
f.write(resp.content)%PDF-1.7
… PDF file (application/pdf) with the KSeF number and QR code{
"error": {
"type": "authentication_error",
"code": "api_key_invalid",
"message": "The API key is wrong, revoked, or the account is disabled.",
"doc_url": "https://ksefshop.pl/api/errors#api_key_invalid"
}
}{
"error": {
"type": "not_found_error",
"code": "resource_missing",
"message": "No such invoice: 'inv_4fJ2kP9xQwErTy7uI0oPaSdF'",
"doc_url": "https://ksefshop.pl/api/errors#resource_missing"
}
}{
"error": {
"type": "idempotency_error",
"code": "idempotency_key_reused",
"message": "Idempotency-Key \"k-1002\" was already used with a different request.",
"doc_url": "https://ksefshop.pl/api/errors#idempotency_key_reused"
}
}Create a correction (refund)
POST /v1/invoices/{id}/corrections
A refund becomes a correction invoice (KOR, TypKorekty 2) with difference lines (negative quantities) referring to the original invoice's KSeF number. The queue waits until the original is accepted in KSeF.
Send refund (neutral format) or woocommerce_order plus woocommerce_refund.
Parameters
idpath · stringrequiredThe object's id.
Prefix
inv_Idempotency-Keyheader · stringAny unique text (1-255 characters), e.g.
order-SO-1001. A retry with the same key within 24 hours returns the first response. Idempotency
Request body (JSON)
Either refund, or woocommerce_order + woocommerce_refund.
refundRefundThe refund in the neutral format.
Show fields
external_idstringrequiredYour refund id; one correction per
external_id.reasonstringCorrection reason printed on the invoice, e.g. "Returned goods".
created_atstringWhen the money was refunded.
ISO 8601 date and time
linesarray of objectReturned lines (at least one of
linesorshipping).Show fields
namestringrequiredLine name as on the invoice.
skustringProduct code.
quantityintegerrequiredReturned items (positive).
unit_pricedecimal stringrequiredGross unit price.
Amount as a string with a dot, e.g.
"49.00"vat_ratestringrequiredVAT rate of the line.
One of:
23,8,5,0
shippingobjectRefunded shipping.
Show fields
pricedecimal stringrequiredAmount as a string with a dot, e.g.
"49.00"
woocommerce_orderobjectThe WooCommerce order the refund belongs to.
woocommerce_refundobjectWooCommerce REST API v3 refund.
Responses
- 200A correction for this
refund.external_idalready exists. - 201New correction, status
pending. - 400Invalid request, e.g.
parameter_invalidbuyer_nip_invalidvat_rate_unsupported - 401Missing or invalid key:
api_key_missingapi_key_invalid - 404No such object (or it belongs to another account or mode):
resource_missing - 409Idempotency-Key reused with another request, or the PDF is not ready:
idempotency_key_reusedpdf_not_ready - 422The order cannot become an invoice:
order_unprocessable - 429Rate limit exceeded, wait
Retry-Afterseconds:rate_limited
curl -X POST https://app.ksefshop.pl/v1/invoices/inv_4fJ2kP9xQwErTy7uI0oPaSdF/corrections \
-H "Authorization: Bearer $KSEF_API_KEY" \
-H "Idempotency-Key: refund-RF-1" \
-H "Content-Type: application/json" \
-d '{
"refund": {
"external_id": "RF-1",
"reason": "Zwrot towaru",
"lines": [
{
"name": "Kubek ceramiczny 350 ml",
"sku": "KUB-350",
"quantity": 1,
"unit_price": "49.00",
"vat_rate": "23"
}
],
"shipping": {
"price": "15.99"
}
}
}'<?php
$payload = [
'refund' => [
'external_id' => 'RF-1',
'reason' => 'Zwrot towaru',
'lines' => [
[
'name' => 'Kubek ceramiczny 350 ml',
'sku' => 'KUB-350',
'quantity' => 1,
'unit_price' => '49.00',
'vat_rate' => '23',
],
],
'shipping' => ['price' => '15.99'],
],
];
$ch = curl_init('https://app.ksefshop.pl/v1/invoices/inv_4fJ2kP9xQwErTy7uI0oPaSdF/corrections');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('KSEF_API_KEY'),
'Idempotency-Key: refund-RF-1',
'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/inv_4fJ2kP9xQwErTy7uI0oPaSdF/corrections", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.KSEF_API_KEY}`,
"Idempotency-Key": "refund-RF-1",
"Content-Type": "application/json",
},
body: JSON.stringify({
refund: {
external_id: "RF-1",
reason: "Zwrot towaru",
lines: [
{
name: "Kubek ceramiczny 350 ml",
sku: "KUB-350",
quantity: 1,
unit_price: "49.00",
vat_rate: "23",
},
],
shipping: { price: "15.99" },
},
}),
});
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/inv_4fJ2kP9xQwErTy7uI0oPaSdF/corrections",
headers={
"Authorization": f"Bearer {os.environ['KSEF_API_KEY']}",
"Idempotency-Key": "refund-RF-1",
},
json={
"refund": {
"external_id": "RF-1",
"reason": "Zwrot towaru",
"lines": [
{
"name": "Kubek ceramiczny 350 ml",
"sku": "KUB-350",
"quantity": 1,
"unit_price": "49.00",
"vat_rate": "23",
},
],
"shipping": {"price": "15.99"},
},
},
timeout=30,
)
data = resp.json()
if not resp.ok:
raise RuntimeError(f"{data['error']['code']}: {data['error']['message']}")
print(data["id"], data["status"]){
"id": "cor_8hG3jK2lMnBvCxZ1aS4dF6gH",
"object": "correction",
"livemode": false,
"status": "pending",
"order": {
"external_id": "SO-1001",
"number": null
},
"number": null,
"ksef_number": null,
"ksef_environment": "test",
"issue_date": null,
"currency": null,
"total_gross": null,
"buyer_nip": null,
"pdf_url": null,
"last_error": null,
"created": 1760951000,
"updated": 1760951000,
"invoice": "inv_4fJ2kP9xQwErTy7uI0oPaSdF",
"refund": {
"external_id": "RF-1"
}
}{
"id": "cor_8hG3jK2lMnBvCxZ1aS4dF6gH",
"object": "correction",
"livemode": false,
"status": "pending",
"order": {
"external_id": "SO-1001",
"number": null
},
"number": null,
"ksef_number": null,
"ksef_environment": "test",
"issue_date": null,
"currency": null,
"total_gross": null,
"buyer_nip": null,
"pdf_url": null,
"last_error": null,
"created": 1760951000,
"updated": 1760951000,
"invoice": "inv_4fJ2kP9xQwErTy7uI0oPaSdF",
"refund": {
"external_id": "RF-1"
}
}{
"error": {
"type": "invalid_request_error",
"code": "buyer_nip_invalid",
"message": "buyer.nip is not a valid Polish NIP (checksum).",
"param": "order.buyer.nip",
"doc_url": "https://ksefshop.pl/api/errors#buyer_nip_invalid"
}
}{
"error": {
"type": "authentication_error",
"code": "api_key_invalid",
"message": "The API key is wrong, revoked, or the account is disabled.",
"doc_url": "https://ksefshop.pl/api/errors#api_key_invalid"
}
}