KSeF Faktury
PL
Zapisz się na start
Wczesny dostęp

API jest we wczesnym dostępie: klucze testowe (KSeF TEST) wydajemy partiami osobom z listy startowej. Tryb produkcyjny włączymy później.

Poproś o dostęp

Przewodniki

Idempotencja i bezpieczne ponawianie

Faktura w KSeF to dokument z numerem bez luk, więc dubel jest gorszy niż opóźnienie. Dwa mechanizmy pilnują, żeby każde zamówienie dało dokładnie jedną fakturę.

Po co to jest

Wysłałeś zamówienie, a połączenie zerwało się przed odpowiedzią. Czy faktura powstała? Bez idempotencji ponowienie mogłoby wystawić drugą fakturę z kolejnym numerem i wysłać ją do KSeF. Z idempotencją ponawiasz bez obaw: dostaniesz tę samą fakturę.

Dwa poziomy ochrony

  1. Nagłówek Idempotency-Key w każdym POST. Pierwszą odpowiedź pamiętamy przez 24 godziny i zwracamy ją dla tego samego klucza i tej samej treści.
  2. Naturalny klucz zamówienia. Niezależnie od nagłówka jedno order.external_id daje jedną fakturę, a jedno refund.external_id jedną korektę. Ponowne wysłanie zamówienia zwraca istniejącą fakturę z kodem 200 zamiast 201, także po 24 godzinach.

Jak działa Idempotency-Key

Sytuacja Odpowiedź
Pierwsze żądanie z kluczem Zwykła odpowiedź, np. 201
Ten sam klucz i ta sama treść w ciągu 24 h Ta sama odpowiedź i nagłówek Idempotent-Replayed: true
Ten sam klucz, inna treść 409 idempotency_key_reused
Klucz pusty lub dłuższy niż 255 znaków 400 idempotency_key_invalid
POST /v1/invoices
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"
      }
    ]
  }
}'

Jak dobrać klucz

Klucz ma opisywać operację, a nie próbę. Dobre klucze to order-SO-1001 dla faktury i refund-RF-1 dla korekty. Losowy UUID też jest w porządku, jeśli wygenerujesz go raz i zapiszesz razem z zamówieniem. Nowy UUID przy każdej próbie niszczy cały sens idempotencji.

Co ponawiać

  • Błąd sieci lub timeout: ponów z tym samym kluczem.
  • 429 rate_limited: odczekaj tyle sekund, ile mówi Retry-After.
  • 5xx: ponów z wykładniczym opóźnieniem (1, 2, 4, 8 s...).
  • Pozostałe 4xx: nie ponawiaj, popraw żądanie. Wyjątek to 409 pdf_not_ready przy pobieraniu PDF.
Ponawianie z tym samym kluczem
# --retry ponawia przy błędach sieci, 429 i 5xx i respektuje Retry-After
curl --retry 5 --retry-connrefused -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-SO-1001.json

Idempotencja dotyczy wszystkich POST: /v1/invoices, /v1/invoices/{id}/corrections i /v1/webhook_endpoints. Żądania GET i DELETE są idempotentne z natury.

KSeF Faktury

Wczesny dostęp do API

Klucze testowe wydajemy partiami. Zostaw e-mail: napiszemy, gdy dostęp będzie gotowy.