Kształt odpowiedzi#
Wszystkie zasoby /v1/* zwracają ten sam obiekt — niezależnie od statusu HTTP. Tablica errors może mieć kilka pozycji (walidacja zgłasza wszystkie pola naraz); traceId jest też w nagłówku X-Trace-Id.
{
"traceId": "b7f3c2e1-4d9a-4c1e-9f2a-1d3e5f7a9b0c",
"errors": [
{
"code": "validation_error",
"message": "Integer amount in grosze (>= 0) required.",
"path": "price.amount"
},
{
"code": "validation_error",
"message": "Allowed: published, draft.",
"path": "status"
}
]
}| Pole | Zawsze | Znaczenie |
|---|---|---|
traceId | tak | Identyfikator żądania. Jedyna rzecz, jakiej potrzebujemy w zgłoszeniu. |
errors[].code | tak | Stabilny kod z tej strony. Programuj po nim, nie po message. |
errors[].message | tak | Dla programisty, po angielsku. Treść może się zmieniać. |
errors[].userMessage | nie | Po polsku, można pokazać sprzedawcy bez tłumaczenia. |
errors[].path | nie | Ścieżka pola w żądaniu (price.amount, carrier), gdy błąd dotyczy pola. |
{
"error": "invalid_grant",
"error_description": "Refresh token is invalid, expired or already used (tokens rotate on every refresh).",
"traceId": "9f2a1d3e-5f7a-9b0c-b7f3-c2e14d9a4c1e"
}Wszystkie kody#
- missing_user_agent400
- unauthorized401
- insufficient_scope403
- not_found404
- validation_error400
- rate_limited429
- internal_error500
- no_price_row422
- no_inventory_row422
- order_unpaid409
- order_cancelled409
- already_shipped409
- invalid_client401
- invalid_grant400
- invalid_scope400
- unsupported_grant_type400
- invalid_request400
- unsupported_response_type302
- access_denied302
- server_error500
Kody wspólne — każdy zasób /v1/*#
Zwracane przez bramkę API przed wykonaniem logiki zasobu (nagłówki, token, zakres, limit) albo przez walidację ciała żądania.
missing_user_agent
HTTP 400- Przyczyna
- Brak nagłówka User-Agent albo nie pasuje do wzoru NazwaAplikacji/Wersja. Bramka sprawdza wyrażenie ^[A-Za-z0-9][A-Za-z0-9._-]{0,63}/[A-Za-z0-9][A-Za-z0-9._-]{0,31} — domyślny User-Agent bibliotek HTTP (np. python-requests/2.31) formalnie przechodzi, ale nie identyfikuje Twojej aplikacji i przy problemach nie umiemy się z Tobą skontaktować.
- Co zrobić
- Ustaw własny nagłówek w formacie NazwaAplikacji/Wersja (+https://adres-dokumentacji). Nazwa bez spacji (zamień na myślnik), zgodna z nazwą zarejestrowaną w panelu. Sprawdź go walidatorem na stronie Limity.
unauthorized
HTTP 401- Przyczyna
- Brak nagłówka Authorization: Bearer, token nieznany, wygasły (access token żyje 12 h), odwołany (aplikacja usunięta lub zawieszona) albo to refresh token użyty jako access token. Odpowiedź niesie nagłówek WWW-Authenticate: Bearer realm="premiumsupply", error="invalid_token".
- Co zrobić
- Pobierz nowy token: client_credentials — kolejny POST /oauth/token; authorization_code — wymiana refresh_token. Nie ponawiaj żądania z tym samym tokenem. Jeśli message brzmi „Application no longer exists”, aplikacja została usunięta w panelu.
insufficient_scope
HTTP 403- Przyczyna
- Token jest ważny, ale nie zawiera zakresu wymaganego przez zasób (message podaje który). Zakresy są zamrażane w momencie wydania tokenu — dopisanie zakresu do aplikacji w panelu nie zmienia tokenów już wydanych.
- Co zrobić
- Dodaj zakres do aplikacji w panelu, a potem: client_credentials — pobierz nowy token; authorization_code — poproś sprzedawcę o ponowną zgodę (nowy /oauth/authorize z pełną listą zakresów). Sprawdź bieżące zakresy przez GET /v1/me.
not_found
HTTP 404- Przyczyna
- Zasób nie istnieje ALBO należy do innego sprzedawcy — celowo nie rozróżniamy tych przypadków, żeby nie zdradzać istnienia cudzych ofert i zamówień. Dla zamówień akceptujemy id oraz numer zamówienia.
- Co zrobić
- Sprawdź identyfikator (oferty: id z GET /v1/offers; zamówienia: id albo order_number). Jeśli zasób został usunięty po Twojej stronie synchronizacji, potraktuj 404 jako sygnał do usunięcia lokalnej kopii.
- Gdzie
GET /v1/offers/{id}PATCH /v1/offers/{id}GET /v1/orders/{id}POST /v1/orders/{id}/shipments
validation_error
HTTP 400- Przyczyna
- Pole żądania ma zły typ, format albo wartość poza dozwolonymi. Pole path wskazuje, które (np. price.amount, stock, status, carrier, tracking_number, limit, after, Idempotency-Key). W jednej odpowiedzi może być kilka wpisów errors[] — po jednym na pole.
- Co zrobić
- Popraw wskazane pola i wyślij ponownie. Typowe przyczyny: cena jako liczba dziesiętna zamiast groszy (integer), status poza published/draft, kursor after skopiowany z innego zasobu, klucz idempotencji dłuższy niż 128 znaków.
rate_limited
HTTP 429- Przyczyna
- Aplikacja przekroczyła 600 żądań w bieżącym oknie 60 s (limit liczony na client_id, nie na adres IP; wliczają się także żądania zakończone błędem). Nagłówek Retry-After podaje liczbę sekund do końca okna.
- Co zrobić
- Odczekaj Retry-After sekund i wznów. Nie ponawiaj natychmiast — kolejne żądania w tym oknie też dostaną 429 i liczą się do limitu. Śledź X-RateLimit-Remaining i zwalniaj zanim spadnie do zera. Potrzebujesz więcej? Napisz na api@premiumsupply.pl.
internal_error
HTTP 500- Przyczyna
- Nieoczekiwany błąd po naszej stronie. Treść wyjątku nie jest zwracana — jedyną informacją jest traceId (także w nagłówku X-Trace-Id).
- Co zrobić
- Ponów z wykładniczym odstępem (najwyżej 3 próby). Jeśli błąd się powtarza, wyślij zgłoszenie z X-Trace-Id, metodą, ścieżką i czasem UTC — patrz Kontakt.
Oferty#
Kody domenowe z PATCH /v1/offers/{id}. Status 422: żądanie poprawne składniowo, ale oferta nie ma czego zaktualizować.
no_price_row
HTTP 422- Przyczyna
- PATCH z polem price trafił na ofertę, której wariant nie ma ceny w PLN (brak wiersza ceny bez listy cenowej). API zmienia istniejącą cenę, nie tworzy nowej.
- Co zrobić
- Uzupełnij cenę oferty w panelu sprzedawcy, potem powtórz PATCH. Jeśli w GET /v1/offers/{id} pole price jest null, PATCH ceny zakończy się tym błędem.
- Gdzie
PATCH /v1/offers/{id}
no_inventory_row
HTTP 422- Przyczyna
- PATCH z polem stock trafił na ofertę bez poziomu magazynowego (wariant nie ma powiązanej pozycji inventory). Analogicznie do ceny — API nie zakłada stanów, tylko je zmienia.
- Co zrobić
- Ustaw stan w panelu sprzedawcy raz, ręcznie; od tej chwili PATCH stock działa. W GET /v1/offers/{id} taka oferta ma stock: null.
- Gdzie
PATCH /v1/offers/{id}
Zamówienia i przesyłki#
Kody z POST /v1/orders/{id}/shipments. Status 409 oznacza konflikt ze stanem zamówienia — powtórzenie tego samego żądania nic nie zmieni.
order_unpaid
HTTP 409- Przyczyna
- Zgłoszenie wysyłki do zamówienia, które nie jest opłacone (status API pending). Wysyłka przed płatnością jest zablokowana po obu stronach — w panelu i w API.
- Co zrobić
- Wysyłaj dopiero, gdy status zamówienia to processing (payment_status: paid). Odpytuj GET /v1/orders?status=processing albo — po uruchomieniu webhooków — reaguj na order.paid.
- Gdzie
POST /v1/orders/{id}/shipments
order_cancelled
HTTP 409- Przyczyna
- Zamówienie zostało anulowane; nie da się do niego zgłosić wysyłki.
- Co zrobić
- Zsynchronizuj status po swojej stronie (GET /v1/orders/{id}) i nie wysyłaj towaru. Jeśli paczka już poszła, skontaktuj się z obsługą.
- Gdzie
POST /v1/orders/{id}/shipments
already_shipped
HTTP 409- Przyczyna
- Zamówienie ma już zapisaną przesyłkę (numer w message). Operacja jest jednorazowa, bo wysyła kupującemu powiadomienie „paczka w drodze”.
- Co zrobić
- Jeśli to Twoja ponowiona próba po utracie odpowiedzi — powtórz żądanie z TYM SAMYM Idempotency-Key: dostaniesz zapamiętane 201 (nagłówek Idempotent-Replayed: true) zamiast 409. Numer przesyłki odczytasz z pola shipment w GET /v1/orders/{id}. Zmiana numeru po fakcie — tylko przez obsługę.
- Gdzie
POST /v1/orders/{id}/shipments
OAuth 2.0 — /oauth/token i /oauth/authorize#
Ten jeden obszar ma INNY kształt odpowiedzi, narzucony przez RFC 6749: { error, error_description, traceId }. Pole error odpowiada kodowi z tej listy.
invalid_client
HTTP 401- Przyczyna
- Nieznany client_id, zły client_secret, brak uwierzytelnienia klienta przy client_credentials (ani Basic, ani client_id/client_secret w ciele) albo aplikacja zawieszona. Na /oauth/authorize: nieznany client_id — odpowiedź 400 w JSON, bez przekierowania (RFC 6749 zabrania odsyłać na niezweryfikowany adres).
- Co zrobić
- Sprawdź parę client_id/client_secret w panelu. Po rotacji sekretu stary przestaje działać natychmiast. Nagłówek Basic to base64(client_id:client_secret) — bez znaków nowej linii. Sekret zaczyna się od pss_, client_id od psa_.
- Gdzie
POST /oauth/tokenGET /oauth/authorize
invalid_grant
HTTP 400- Przyczyna
- authorization_code: kod nieznany, wygasły (10 min), już użyty, wystawiony dla innego redirect_uri albo code_verifier nie zgadza się z code_challenge. refresh_token: token nieznany, wygasły (90 dni) albo już użyty — każde odświeżenie odwołuje stary refresh token (rotacja).
- Co zrobić
- Kod: rozpocznij autoryzację od nowa (/oauth/authorize). Refresh: jeśli zgubiłeś odpowiedź z nowym refresh_token, sesji nie da się odzyskać — sprzedawca musi ponownie wyrazić zgodę. Zapisuj nową parę tokenów atomowo, zanim użyjesz nowego access tokenu.
- Gdzie
POST /oauth/token
invalid_scope
HTTP 400także jako ?error= na redirect_uri- Przyczyna
- Żądany zakres nie istnieje albo nie został przyznany aplikacji w panelu (error_description wymienia które). Na /oauth/authorize dodatkowo: pusty parametr scope.
- Co zrobić
- Proś wyłącznie o podzbiór zakresów aplikacji; pełna lista na stronie Uwierzytelnianie. Pominięcie parametru scope przy client_credentials daje token ze wszystkimi zakresami aplikacji.
- Gdzie
POST /oauth/tokenGET /oauth/authorize
unsupported_grant_type
HTTP 400- Przyczyna
- grant_type inny niż client_credentials, authorization_code albo refresh_token (brak parametru też).
- Co zrobić
- Wysyłaj ciało jako application/x-www-form-urlencoded z poprawnym grant_type. Nie obsługujemy password, device_code ani implicit.
- Gdzie
POST /oauth/token
invalid_request
HTTP 400także jako ?error= na redirect_uri- Przyczyna
- /oauth/token: brak code, redirect_uri lub code_verifier (authorization_code); code_verifier poza 43–128 znakami [A-Za-z0-9-._~]; brak refresh_token. /oauth/authorize: redirect_uri niezarejestrowany (400 JSON, bez przekierowania), state krótszy niż 8 znaków, brak lub zły PKCE (code_challenge musi mieć 43 znaki base64url, metoda S256).
- Co zrobić
- Porównaj żądanie z przykładami na stronie Uwierzytelnianie. redirect_uri musi być identyczny znak w znak z zarejestrowanym (łącznie ze slashem na końcu i wielkością liter hosta).
- Gdzie
POST /oauth/tokenGET /oauth/authorize
unsupported_response_type
302 → redirect_uri- Przyczyna
- response_type inny niż code. Błąd wraca na redirect_uri z parametrami error, error_description i state.
- Co zrobić
- Używaj wyłącznie response_type=code — flow implicit nie jest i nie będzie wspierany.
- Gdzie
GET /oauth/authorize
access_denied
302 → redirect_uri- Przyczyna
- Sprzedawca odrzucił zgodę na ekranie premiumsupply.pl albo aplikacja ma status pending (cel „dla innych sprzedawców” czeka na akceptację) i nie może jeszcze prosić o dostęp do obcych kont. Wraca na redirect_uri jako ?error=access_denied&state=…
- Co zrobić
- Pokaż użytkownikowi czytelny komunikat i pozwól spróbować później. Status aplikacji sprawdzisz w panelu; na własne konto (client_credentials) aplikacja pending działa od razu.
- Gdzie
GET /oauth/authorize
server_error
HTTP 500- Przyczyna
- Nieoczekiwany błąd serwera tokenów. Odpowiedź zawiera traceId.
- Co zrobić
- Ponów po chwili; jeśli problem trwa, zgłoś z traceId na api@premiumsupply.pl.
- Gdzie
POST /oauth/token
Statusy HTTP#
Kiedy dokładnie który status. Klient generowany z kontraktu widzi je przy każdej operacji — w tym 429, które dotyczy wszystkich.
| Status | Kiedy |
|---|---|
200 OK | Udane GET oraz PATCH (zwraca zaktualizowany zasób). |
201 Created | Udane POST tworzące zasób: przesyłka, subskrypcja webhooka. |
204 No Content | Udane DELETE (subskrypcja webhooka). |
302 Found | Wyłącznie /oauth/authorize — przekierowanie na ekran zgody albo powrót na redirect_uri (z code albo error). |
400 Bad Request | missing_user_agent, validation_error, błędy OAuth invalid_request / invalid_grant / invalid_scope / unsupported_grant_type. |
401 Unauthorized | unauthorized (zasoby /v1), invalid_client (OAuth). |
403 Forbidden | insufficient_scope — token ważny, brak zakresu. |
404 Not Found | not_found — zasób nie istnieje albo należy do innego sprzedawcy. |
409 Conflict | already_shipped, order_unpaid, order_cancelled — stan zasobu wyklucza operację. |
422 Unprocessable Content | no_price_row, no_inventory_row — dane poprawne, oferta nie ma czego zaktualizować. |
429 Too Many Requests | rate_limited — patrz Retry-After. |
500 Internal Server Error | internal_error / server_error — zgłoś z X-Trace-Id. |
Brakuje kodu, który dostałeś? Napisz na Kontakt z X-Trace-Id — nieudokumentowany kod traktujemy jako błąd dokumentacji.