> ## Documentation Index
> Fetch the complete documentation index at: https://andcze.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Błędy i limity

> Kształt odpowiedzi błędu, kody statusu i kody maszynowe, limity żądań oraz bezpieczne ponawianie.

Całe API zwraca odpowiedzi w jednym, stałym kształcie. Ta strona mówi, jak rozpoznać błąd, kiedy go ponowić i jak nie przekroczyć limitów.

## Kształt odpowiedzi

Sukces:

```json theme={null}
{ "success": true, "data": { "...": "..." }, "message": "opcjonalnie" }
```

Niektóre endpointy dokładają pola kontekstowe — np. utworzenie zamówienia zwraca `redirectUrl`, a darmowe zamówienie `free: true`. Listy stronicowane zwracają `data`, `total`, `page`, `pages`, `hasNext`, `hasPrev`.

Błąd:

```json theme={null}
{
  "success": false,
  "statusCode": 409,
  "error": "This Idempotency-Key was already used for a different checkout",
  "code": "IDEMPOTENCY_KEY_REUSED",
  "timestamp": "2026-10-27T10:30:00.000Z",
  "path": "/api/v2/orders"
}
```

| Pole | Opis |
| - | - |
| `success` | zawsze `false` przy błędzie — sprawdzaj je zamiast samego kodu HTTP |
| `statusCode` | kod HTTP |
| `error` | czytelny komunikat (do logów, nie do pokazywania 1:1 użytkownikowi) |
| `code` | opcjonalny, stabilny kod maszynowy — po nim tłumacz komunikat w swoim UI |
| `details` | opcjonalnie, przy błędach walidacji: lista nieprawidłowych pól |
| `timestamp`, `path` | czas i ścieżka (bez query z danymi wrażliwymi) |

## Kody statusu

| Kod | Znaczenie | Typowa przyczyna | Ponowić? |
| - | - | - | - |
| `400` | Bad Request | błąd walidacji, zły format identyfikatora (ObjectId to 24 znaki hex) | nie — popraw żądanie |
| `401` | Unauthorized | brak, błędny, wygasły lub odwołany klucz; sfałszowany webhook | nie |
| `403` | Forbidden | za mały zakres klucza, inny sklep, brak roli, wymagana captcha | nie |
| `404` | Not Found | zasób nie istnieje albo nie należy do tego sklepu | nie |
| `409` | Conflict | konflikt stanu: idempotencja, trwający checkout, zmienione dokumenty prawne | zależy od `code` |
| `429` | Too Many Requests | przekroczony limit żądań | tak, z opóźnieniem |
| `500` | Internal Server Error | błąd po stronie serwera | tak, z backoffem |
| `503` | Service Unavailable | sklep chwilowo zajęty (`SHOP_BUSY`) | tak, z backoffem |

## Kody maszynowe

Wybrane wartości pola `code`, na które warto reagować w kodzie:

| `code` | HTTP | Co zrobić |
| - | - | - |
| `IDEMPOTENCY_KEY_REQUIRED` | `400` | dodaj nagłówek `Idempotency-Key` (32–128 znaków `A-Z a-z 0-9 _ -`) |
| `IDEMPOTENCY_KEY_REUSED` | `409` | ten klucz był użyty dla innej treści — wygeneruj nowy |
| `CHECKOUT_ATTEMPT_CLOSED` | `409` | próba zakupu zamknięta — zacznij nową z nowym kluczem |
| `CHECKOUT_IN_PROGRESS` | `409` | ten sam zakup jest właśnie przetwarzany — odczekaj i ponów z tym samym kluczem |
| `LEGAL_CONSENT_REQUIRED` | `400` | brak wymaganych zgód w kasie |
| `LEGAL_DOCUMENTS_CHANGED` | `409` | regulamin zmienił się w trakcie — pobierz aktualną wersję i poproś o zgodę ponownie |
| `CAPTCHA_REQUIRED` | `403` | pokaż widżet Turnstile i wyślij token |
| `PRODUCT_VARIANT_REQUIRED` / `INVALID_PRODUCT_VARIANT` | `400` | wybierz poprawny wariant produktu |
| `SHOP_PAYMENT_NOT_READY` | `400` | sklep nie ma gotowej metody płatności |
| `PAYMENT_INIT_FAILED` | `400` | bramka odrzuciła utworzenie płatności — spróbuj inną metodą |
| `SHOP_NOT_ACCEPTING_MUTATIONS` | `409` | sklep jest w trakcie operacji blokującej zmiany |
| `SHOP_BUSY` | `503` | ponów za chwilę |
| `CART_TOO_LARGE` | `400` | koszyk ma 1–20 pozycji — podziel zakup |
| `ORDER_NOT_FOUND` | `404` | zły numer zamówienia albo klucz statusu (status/odbiór w Storefront v1) |
| `ORDER_NOT_PAID` | `409` | treść cyfrowa jest wydawana dopiero po płatności |
| `DELIVERY_REVOKED` | `410` | zamówienie zwrócono lub zakwestionowano — treść nie jest już dostępna |
| `NO_DIGITAL_DELIVERY` | `404` | zamówienie nie ma treści cyfrowej |
| `DOWNLOAD_EXPIRED` / `DOWNLOAD_LIMIT_REACHED` / `DOWNLOAD_UNAVAILABLE` | `410` | link do pliku wygasł, wyczerpano pobrania albo pliku już nie ma — poproś sprzedawcę o nowy link |
| `VOUCHER_NOT_FOUND` / `VOUCHER_USED` / `VOUCHER_EXPIRED` | `400` | voucher nieznany lub wyłączony / już zrealizowany / wygasły (nieznany i wyłączony kod odpowiadają tak samo celowo) |
| `WORKSPACE_PRODUCTION_REQUIRES_APPROVAL` | `403` | publikacja produkcyjna z klucza, CLI, MCP lub agenta AI wymaga zatwierdzenia — wypromuj w panelu albo wyłącz politykę w **Workspace → Publikacje** |
| `SITE_BUILD_BUSY` | `409` | za dużo aktywnych buildów w planie (Free: 1, Pro: 2) — poczekaj na zakończenie |
| `SITE_BUILD_RATE_LIMIT` | `429` | godzinny limit buildów (Free: 10/h, Pro: 30/h) |
| `AI_USAGE_UNAVAILABLE` | `503` | nie da się teraz sprawdzić dziennego budżetu AI — ponów za chwilę |

Nowe kody mogą się pojawiać — nieznany `code` traktuj według `statusCode`.

## Walidacja

API odrzuca nieprawidłowe dane, zanim zacznie je przetwarzać. Pola spoza schematu są ignorowane, a typy konwertowane automatycznie (np. liczby z query string). Listy przyjmują `page` i `limit`; `limit` jest przycinany do bezpiecznego maksimum (zwykle 100).

## Limity żądań

Całe REST API ma globalny limit per rzeczywisty adres IP klienta. Konfiguracja produkcyjna: **200 żądań na minutę** (`RATE_LIMIT_MAX=200`, `RATE_LIMIT_WINDOW=60000`); operator platformy może zmienić obie wartości.

Wrażliwe trasy mają dodatkowe, ostrzejsze okna stałe, liczone per IP i trasa:

| Operacja | Limit / minuta |
| - | - |
| Utworzenie publicznego checkoutu | 12 |
| Publiczne sprawdzenie statusu zamówienia | 30 |
| Wysłanie kodu zmiany nicku | 5 |
| Weryfikacja kodu zmiany nicku | 10 |
| Realizacja vouchera | 8 |
| Storefront v1: kasa / realizacja vouchera | 12 |
| Storefront v1: odbiór treści cyfrowej | 20 |
| Sprawdzenie istnienia vouchera | 20 |
| Walidacja / sprawdzenie rabatu | 30 |
| Utworzenie klucza API | 10 |
| Mutacja sesji płatności | 15 |
| Publiczny beacon analityczny | 60 |

Trasy logowania mają osobne limity przeciw brute-force. Webhooki płatności są chronione per operator i sklep, z zachowaniem semantyki ponowień operatora.

> [!NOTE]
>
> Liczniki wrażliwych tras są współdzielone przez Redis między instancjami API. Gdy Redis jest chwilowo niedostępny, każda instancja utrzymuje ograniczony licznik w pamięci — ochrona nie znika, tylko staje się lokalna dla instancji.

Plugin gry nie odpytuje REST — połączenie Socket.IO ma własne uwierzytelnianie, walidację, debounce i limity zdarzeń (zobacz [Protokół pluginu](https://andcze.mintlify.site/pl/developers/plugin-protocol.md)).

## Ponawianie

Ponawiaj tylko `429`, `500`, `503` i błędy sieci. Nie ponawiaj `400`, `401`, `403`, `404`.

* Jeśli odpowiedź `429` ma nagłówek `Retry-After`, odczekaj tyle sekund. Nie każda odpowiedź go zawiera (ostrzejsze limity tras go nie wysyłają) — wtedy użyj backoffu.
* Backoff wykładniczy z jitterem: np. 1 s, 2 s, 4 s ± losowe 0–500 ms, maksymalnie kilka prób.
* Nie ponawiaj natychmiast w pętli — to tylko przedłuża blokadę.

```ts theme={null}
async function withRetry<T>(fn: () => Promise<Response>, attempts = 4): Promise<T> {
  for (let i = 0; ; i++) {
    const res = await fn();
    if (res.ok) return (await res.json()) as T;
    const retryable = res.status === 429 || res.status >= 500;
    if (!retryable || i === attempts - 1) throw await res.json();
    const retryAfter = Number(res.headers.get("retry-after"));
    const delay = retryAfter > 0 ? retryAfter * 1000 : 2 ** i * 1000 + Math.random() * 500;
    await new Promise((r) => setTimeout(r, delay));
  }
}
```

## Idempotencja

Utworzenie zamówienia (`POST /orders`, w 3.0 także `POST /storefront/v1/shops/<shopId>/checkout`) **wymaga** nagłówka `Idempotency-Key`:

* losowa wartość 32–128 znaków (`A-Z a-z 0-9 _ -`), np. UUID bez myślników albo base64url;
* generuj ją **raz na próbę zakupu** i używaj ponownie tylko przy ponowieniu identycznego żądania;
* ponowienie z tym samym kluczem i tą samą treścią zwraca to samo zamówienie zamiast tworzyć drugie;
* ten sam klucz z inną treścią → `409 IDEMPOTENCY_KEY_REUSED`; zamknięta próba → `409 CHECKOUT_ATTEMPT_CLOSED`.

Serwer przechowuje tylko skrót SHA-256 klucza. Po stronie płatności ItemShop jest idempotentny także wobec powtórzonych powiadomień operatorów — opłacenie zamówienia przetwarza się dokładnie raz.

## Dalej

> **[API z kluczem](https://andcze.mintlify.site/pl/developers/api-keys.md)**
>
> Klucze, zakresy i pierwsze żądanie.

> **[Webhooki](https://andcze.mintlify.site/pl/developers/webhooks.md)**
>
> Powiadomienia Discord i webhooki operatorów płatności.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.