Błędy
API używa standardowych kodów statusu HTTP oraz spójnej koperty błędu. Każdy błąd zawiera stabilny, czytelny maszynowo message (kod błędu) oraz, gdy ma to znaczenie, szczegóły w errors.
Struktura błędu
{
"success": false,
"data": null,
"message": "AMBIGUOUS_PARTY",
"executionTime": 5,
"errors": ["Podaj albo buyerId, albo buyer, ale nie oba."]
}
Zawsze podejmuj decyzje na podstawie message (kodu), a nie czytelnego dla człowieka tekstu. Tekst może się zmienić, kod nie. Pole errors ma dwie postacie: przy walidacji pól to lista obiektów { field, code?, message }, w pozostałych przypadkach lista zdań wyjaśniających, np. ["REST API wymaga planu MAX."].
Kody statusu
| Status | Znaczenie |
|---|---|
200 / 201 |
sukces |
400 |
nieprawidłowe parametry zapytania lub ścieżki, operacja niedozwolona dla stanu dokumentu, a przy tworzeniu dokumentów także błędny kształt treści żądania (np. brak documentType, issueDate, products albo nabywcy) |
401 |
brakujący, nieprawidłowy lub wygasły token, albo unieważnione konto API |
403 |
uwierzytelniono, ale brak uprawnień: scope, plan MAX, lista dozwolonych adresów IP |
404 |
nie znaleziono zasobu (także gdy należy do innego konta) |
409 |
konflikt (np. numer dokumentu już istnieje, webhook dla adresu już zarejestrowany) |
422 |
niepowodzenie walidacji treści żądania: brak pola, zły format, reguły zależne od typu, sprzeczne adnotacje (przy tworzeniu dokumentów część tych sprawdzeń zwraca 400, patrz VALIDATION_ERROR) |
429 |
przekroczony limit żądań albo pełna kolejka renderowania PDF |
500 |
nieoczekiwany błąd serwera |
503 |
zewnętrzny rejestr chwilowo nie odpowiada (wyszukiwanie firmy w GUS); ponów za chwilę |
Kody błędów
| Kod | Status | Kiedy |
|---|---|---|
UNAUTHORIZED |
401 | brakujący lub nieprawidłowy token; także token unieważnionego konta API |
TOKEN_EXPIRED |
401 | token wygasł, pobierz nowy z /v1/oauth/token |
NO_PERMISSIONS |
403 | token nie ma wymaganego scope (errors[0] podaje, którego) |
SUBSCRIPTION_REQUIRED |
403 | konto bez aktywnego planu MAX (całe REST API jest modułem MAX) |
FORBIDDEN |
403 | adres IP spoza listy dozwolonych dla konta API |
DOCUMENT_LIMIT_EXCEEDED |
403 | plan konta nie pozwala wystawiać ani edytować dokumentów (errors[0] zaczyna się od „Subskrypcja nieaktywna” albo „Subskrypcja wygasła”) |
VALIDATION_ERROR |
422 / 400 | treść żądania nie przeszła walidacji; szczegóły w errors. Zwykle 422, ale tworzenie dokumentów (POST /documents, POST /documents/validate) i dokumentów magazynowych (POST /warehouse/documents, POST /warehouse/documents/validate) zwraca 400 przy błędach kształtu żądania (brak documentType, issueDate albo products, zły format daty, błędna pozycja). Traktuj oba statusy z tym kodem jako błąd walidacji |
PARTIAL_PAYMENTS_INVALID |
422 | zapłaty częściowe nie zgadzają się z kwotą albo statusem płatności |
DOCUMENT_DATES_INVALID |
422 | daty dokumentu przeczą sobie albo ustawie o VAT (okres sprzedaży, data sprzedaży ponad 60 dni po wystawieniu, zapłata po wystawieniu, korekta przed fakturą korygowaną) |
PAYMENT_INSTALLMENTS_INVALID |
422 | raty nie zgadzają się z kwotą do zapłaty, terminami albo statusem płatności, albo paymentInstallmentsSplit nie da się wykonać (np. kwota za mała na tyle rat) |
PARTY_IDENTIFIER_INVALID |
422 | identyfikatory nabywcy albo odbiorcy podanych danymi przy dokumencie są sprzeczne (np. nip z numerem DE…, vatEu z numerem PL… albo XI…, błędna cyfra kontrolna NIP-u, idWew u nabywcy); errors podaje pole, np. buyer.vatUE. Kontrahenci (/clients) zwracają takie błędy jako VALIDATION_ERROR. Zob. Identyfikatory kontrahenta |
ADVANCE_RECEIPTS_INVALID |
422 | wpłaty na fakturze zaliczkowej nie zgadzają się z kwotą zaliczki, datami albo kursami |
INVALID_PARAMS |
400 | nieprawidłowe parametry zapytania (np. nieznany documentType, zła data) |
BAD_REQUEST |
400 | brak wymaganego elementu żądania poza walidacją pól |
AMBIGUOUS_PARTY |
400 | podano jednocześnie buyerId i buyer (albo receiverId i receiver) |
BUYER_REQUIRED |
400 | nie podano ani buyerId, ani buyer |
NOT_FOUND / DOCUMENT_NOT_FOUND |
404 | brak zasobu |
DOCUMENT_NUMBER_EXISTS |
409 | numer zajęty w swojej serii albo ten sam pełny numer ma już inny dokument na koncie |
CONFLICT |
409 | stan zasobu nie pozwala na operację (np. jedyny magazyn, webhook dla adresu już istnieje, zakończona reguła cykliczna) |
KSEF_CONFIRMED |
400 | usunięcie/edycja dokumentu już zatwierdzonego w KSeF (posiada numer KSeF) |
KSEF_SENT |
400 | usunięcie/edycja dokumentu wysłanego do KSeF i oczekującego na potwierdzenie |
DOCUMENT_CORRECTED |
409 | edycja albo usunięcie faktury, do której istnieje korekta (zmianę wprowadza kolejna korekta) |
CORRECTED_INVOICE_HAS_CORRECTION |
409 | nowa korekta dokumentu, który ma już korektę (kolejną zmianę wystaw jako korektę jego ostatniej korekty, numer i id w errors[0]) |
ADVANCE_INVOICE_SETTLED |
409 | edycja albo usunięcie faktury zaliczkowej rozliczonej fakturą rozliczeniową |
ORDER_HAS_ADVANCE_INVOICES |
400 | edycja albo usunięcie zamówienia z wystawionymi fakturami zaliczkowymi |
WAREHOUSE_LINES_LOCKED |
409 | zmiana pozycji dokumentu magazynowego przez PUT/PATCH (usuń i wystaw nowy) |
STOCK_SHORTAGE |
422 | WZ/RW/MM zeszłoby ze stanem poniżej zera (allowNegativeStock: true wystawia mimo braku) |
WAREHOUSE_INVALID |
422 | nieznany albo cudzy magazyn, MM bez magazynu docelowego albo z tym samym magazynem |
PRODUCT_NOT_FOUND |
404 | pozycja dokumentu magazynowego wskazuje nieznany produkt |
KSEF_CONNECTION_REQUIRED |
409 | wysyłka bez skonfigurowanego połączenia z KSeF |
KSEF_CONNECTION_NOT_AUTHORIZED |
422 | połączenie istnieje, ale nie przeszło autoryzacji |
KSEF_ALREADY_PROCESSING / KSEF_SEND_NOT_ALLOWED |
409 | wysyłka w toku albo dokument w stanie niepozwalającym na wysyłkę |
INVALID_PAYMENT_STATUS / PAYMENT_STATUS_UPDATE_NOT_ALLOWED |
400 | zła wartość receivedPayment albo dokument nie jest „Do zapłaty” |
EMAIL_TAKEN / EMPLOYEE_LIMIT_REACHED |
409 | e-mail pracownika zajęty albo limit 20 kont |
INVALID_NIP / COMPANY_NOT_FOUND |
400 / 404 | wyszukiwanie firmy po NIP |
GUS_UNAVAILABLE |
503 | rejestr GUS nie odpowiada przy wyszukiwaniu firmy po NIP; ponów za chwilę |
RATE_LIMIT_EXCEEDED |
429 | przekroczony limit zapytań, ponów po Retry-After (zobacz Limity zapytań) |
WAIT_PDF_QUEUE |
429 | pełna kolejka renderowania PDF, ponów po Retry-After (zobacz Kolejka renderowania PDF) |
INTERNAL_SERVER_ERROR |
500 | nieoczekiwany, bezpieczny do idempotentnego ponowienia |
Pełna tabela kodów ze statusami jest też na górze specyfikacji OpenAPI (info.description).
Nagłówki odpowiedzi
Każda odpowiedź niesie nagłówek X-Request-ID z unikalnym identyfikatorem żądania. Zapisuj go w logach integracji i podawaj w zgłoszeniach do pomocy: pozwala odnaleźć konkretne wywołanie po stronie Fakturnii. Nagłówki X-RateLimit-* i Retry-After opisuje strona Limity zapytań, a Idempotent-Replayed strona Idempotentność.
Obsługa błędów
const res = await fetch(url, opts);
const body = await res.json();
if (!body.success) {
switch (body.message) {
case 'TOKEN_EXPIRED': // refresh the token and retry once
case 'UNAUTHORIZED': // re-authenticate; a revoked API account needs a new one
case 'SUBSCRIPTION_REQUIRED': // the account needs the MAX plan; tell the user, do not retry
case 'RATE_LIMIT_EXCEEDED': // wait Retry-After seconds, then retry
case 'DOCUMENT_NUMBER_EXISTS': // pick a new number or let the API auto-number
case 'VALIDATION_ERROR': // 400 or 422: inspect body.errors
default:
throw new Error(`${body.message} [${res.headers.get('X-Request-ID')}]: ${JSON.stringify(body.errors ?? [])}`);
}
}
Błędy 5xx i 429 można bezpiecznie ponawiać z odczekiwaniem (backoff) wtedy, gdy żądanie zawierało Idempotency-Key. Zobacz Idempotentność.