> ## 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.

# Storefront API

> Publiczne API v1 dla stron sklepów: sklep, produkty, metody płatności, rabaty, kasa, vouchery i widżety — bez klucza.

Storefront API v1 to publiczne API, z którego korzysta strona sklepu w przeglądarce. Nie wymaga klucza i nie przyjmuje sekretów — sklep jest identyfikowany po `shopId` albo domenie. Odpowiedzi są cache'owane na CDN, a CORS pozwala na zapytania z domen sklepu i adresów podglądu.

> [!TIP]
>
> Na stronie używaj [SDK](https://andcze.mintlify.site/pl/developers/sdk/typescript.md) — `createStorefront()` sam ustawia `shopId`, adres API i język. Surowe endpointy przydają się w innych językach i do debugowania.

## Endpointy

Adres bazowy: `https://itemshop.dev/api/v2/storefront/v1`

| Metoda | Ścieżka | Opis | SDK |
| - | - | - | - |
| `GET` | `/shops/:shopIdOrDomain` | Sklep: nazwa, logo, waluta, języki, serwery (online), linki, regulamin | `sf.shop.get()` |
| `GET` | `/shops/:shopId/products` | Produkty z kategoriami, wariantami, pakietami, cenami po rabatach | `sf.products.list()` |
| `GET` | `/shops/:shopId/products/:slugOrId` | Jeden produkt | `sf.products.get()` |
| `GET` | `/shops/:shopId/payment-methods` | Kod, nazwa, logo, limity kwot | `sf.paymentMethods.list()` |
| `POST` | `/shops/:shopId/discounts/validate` | Sprawdzenie kodu rabatowego dla koszyka | `sf.discounts.validate()` |
| `POST` | `/shops/:shopId/checkout` | Utworzenie zamówienia (1–20 pozycji) → `{ orderId, orderNumber, statusKey, redirectUrl, … }` | `sf.checkout.create()` |
| `POST` | `/shops/:shopId/vouchers/redeem` | Realizacja vouchera → `{ orderNumber, statusKey, status, productName }` | `sf.vouchers.redeem()` |
| `GET` | `/orders/by-number/:orderNumber/status?key=` | Status zamówienia lub grupy po numerze i kluczu statusu | `sf.orders.statusByNumber()` |
| `GET` | `/orders/by-number/:orderNumber/delivery?key=` | Odbiór treści cyfrowej (klucze, plik, wiadomość) | `sf.orders.delivery()` |
| `GET` | `/downloads/:token` | Pobranie pliku z podpisanego linku | — |
| `GET` | `/orders/:orderId/status` | **Przestarzały** — tylko zamówienia sprzed 3.0 | `sf.orders.status()` |
| `GET` | `/shops/:shopId/widgets/recent-purchases` | Ostatnie zakupy | `sf.widgets.recentPurchases()` |
| `GET` | `/shops/:shopId/widgets/top-spenders` | Najwięksi kupujący | `sf.widgets.topSpenders()` |
| `GET` | `/shops/:shopId/widgets/monthly-goal` | Cel miesięczny | `sf.widgets.monthlyGoal()` |
| `GET` | `/shops/:shopId/widgets/online-players` | Gracze online | `sf.widgets.onlinePlayers()` |

## Przykład: lista produktów

```bash theme={null}
curl https://itemshop.dev/api/v2/storefront/v1/shops/65f1c0ffee0000000000abcd/products
```

## Kasa

```bash theme={null}
curl -X POST https://itemshop.dev/api/v2/storefront/v1/shops/<shopId>/checkout \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 7f9c2b1e-4d3a-4b8e-9c61-2a5f0e8d1c34" \
  -d '{
    "items": [{ "productId": "<productId>", "quantity": 1 }],
    "nick": "Steve",
    "email": "steve@example.com",
    "paymentMethodCode": "blik",
    "discountCode": "LATO10",
    "consents": { "terms": true, "immediateDelivery": true, "legalVersion": "<legal.version sklepu>" },
    "returnUrl": "https://sklep.megacraft.pl/dziekujemy"
  }'
```

```json Odpowiedź theme={null}
{
  "success": true,
  "data": {
    "orderId": "664f1a2b3c4d5e6f7a8b9c0d",
    "orderNumber": "A1B2C3D4",
    "statusKey": "k7m2q9x4tz",
    "status": "pending",
    "groupId": null,
    "orderIds": ["664f1a2b3c4d5e6f7a8b9c0d"],
    "redirectUrl": "https://pay.imoje.pl/…",
    "free": false
  }
}
```

Zasady kasy:

* **Koszyk to 1–20 pozycji** w `items`; więcej to `400 CART_TOO_LARGE`. Jedna pozycja = zwykłe zamówienie. Dwie lub więcej = **grupa płatności**: jedna transakcja u operatora na sumę, a wewnątrz osobne zamówienie na pozycję. Odpowiedź ma wtedy `groupId` i `orderIds[]`, a `orderId` i `orderNumber` wskazują grupę. Kod rabatowy liczy się raz na cały koszyk, a limity min/maks metody płatności liczą się od sumy.
* **Nick lub e-mail**: w sklepie typu `game` wymagany jest `nick` (3–16 znaków `a-zA-Z0-9_`, inaczej `NICK_REQUIRED`); w sklepie ogólnym — `email` (inaczej `EMAIL_REQUIRED`). Produkt z dostawą cyfrową (`deliveryKind` inne niż `commands`) zawsze wymaga `email`, także w sklepie `game`.
* **Zgody są wymagane**: `terms` (regulamin) i `immediateDelivery` (połączona zgoda na natychmiastową dostawę i utratę prawa odstąpienia) oraz `legalVersion` — wersja dokumentów z `GET /shops/:shopIdOrDomain`, które pokazałeś kupującemu. Gdy sklep zmieni regulamin, kasa zwróci `LEGAL_DOCUMENTS_CHANGED` — pobierz sklep ponownie i pokaż nowe dokumenty.
* **`Idempotency-Key`** (np. UUID) jest wymagany. Ponowienie z tym samym kluczem nie utworzy drugiego zamówienia.
* **`returnUrl`** musi wskazywać domenę sklepu lub adres podglądu (inaczej `RETURN_URL_NOT_ALLOWED`). Po płatności kupujący wraca na ten adres z parametrami `?itemshop_order=<numer>&itemshop_key=<klucz statusu>` (fragment `#…` jest usuwany) — odczytaj je z `location.search` i pobierz status po numerze i kluczu. W produkcji adresy `localhost`, `127.0.0.1` i `[::1]` są odrzucane (także jako `Origin`). Bez `returnUrl` kupujący trafia na hostowaną stronę statusu sklepu.
* **Zamówienie darmowe** (rabat 100%) ma `free: true` i `redirectUrl` prowadzący od razu do strony statusu.
* **Metoda płatności** to `code` z `/payment-methods` — sklep może mieć kilka metod tego samego operatora.
* **Ochrona przed botami** działa adaptacyjnie: nie blokuje zwykłych zakupów, a chronią ją też limit zapytań i blokada powtórzeń.
* Strona **nie przetwarza płatności** — tylko przekierowuje na `redirectUrl`.

## Błędy

Każdy błąd ma tę samą kopertę z maszynowym kodem `code` — po nim tłumacz komunikat w UI; pole `error` jest tylko dla dewelopera.

```json theme={null}
{
  "success": false,
  "statusCode": 404,
  "code": "SHOP_NOT_FOUND",
  "error": "Shop not found",
  "timestamp": "2026-10-27T12:00:00.000Z",
  "path": "/api/v2/storefront/v1/shops/moj-sklep"
}
```

| Kod | Kiedy |
| - | - |
| `VALIDATION_FAILED` | Niepoprawne dane (szczegóły w `details`). |
| `DISCOUNT_INVALID` | Kod rabatowy nie istnieje, wygasł lub nie pasuje do koszyka. |
| `LEGAL_CONSENT_REQUIRED`, `LEGAL_DOCUMENTS_CHANGED` | Brak zgód albo nieaktualna wersja dokumentów. |
| `SHOP_PAYMENT_NOT_READY`, `PAYMENT_INIT_FAILED` | Sklep nie ma działającej metody płatności / bramka nie odpowiedziała. |
| `NICK_REQUIRED`, `EMAIL_REQUIRED`, `CART_EMPTY`, `CART_TOO_LARGE` | Brak nicku/e-maila, pusty koszyk albo więcej niż 20 pozycji. |
| `PRODUCT_NOT_FOUND`, `PRODUCT_UNAVAILABLE`, `OUT_OF_STOCK`, `PRODUCT_VARIANT_REQUIRED`, `INVALID_PRODUCT_VARIANT`, `INVALID_QUANTITY` | Problem z produktem, wariantem lub ilością. |
| `VOUCHER_NOT_FOUND`, `VOUCHER_USED`, `VOUCHER_EXPIRED` | Voucher nieznany lub wyłączony (ta sama odpowiedź celowo), już zrealizowany (także gdy realizacja trwa) albo wygasły. Wszystkie `400`. |
| `ORDER_NOT_FOUND` | Zły numer albo klucz statusu. |
| `ORDER_NOT_PAID`, `DELIVERY_REVOKED`, `NO_DIGITAL_DELIVERY` | Odbiór: zamówienie nieopłacone (`409`), zwrot lub spór (`410`), brak treści cyfrowej (`404`). |
| `DOWNLOAD_EXPIRED`, `DOWNLOAD_LIMIT_REACHED`, `DOWNLOAD_UNAVAILABLE` | Link do pliku wygasł, wyczerpano pobrania albo plik niedostępny (`410`). |
| `RETURN_URL_NOT_ALLOWED` | `returnUrl` spoza domen sklepu. |
| `CAPTCHA_REQUIRED` | Ochrona przed botami wymaga weryfikacji. |
| `CHECKOUT_IN_PROGRESS`, `IDEMPOTENCY_KEY_REUSED` | Ta sama próba zakupu już trwa / klucz użyty z innymi danymi. |
| `ORIGIN_NOT_ALLOWED` | Zapytanie z domeny, która nie należy do sklepu. |
| `RATE_LIMITED` | Za dużo zapytań — odczekaj chwilę. |

## Realizacja vouchera

`POST /shops/:shopId/vouchers/redeem` z `{ code, nick }` i opcjonalnie `email` (adres na treść cyfrową; także `turnstileToken` albo nagłówek `cf-turnstile-response`) zwraca `{ orderId, orderNumber, statusKey, status, productName, serverName, nick }`. Voucher tworzy darmowe zamówienie dostarczane tak jak zwykły zakup.

## Status zamówienia

`GET /orders/by-number/:orderNumber/status?key=<statusKey>` zwraca `{ orderId, orderNumber, shopId, status, productName, serverName, nick, amount, currency, createdAt, groupId, items[], delivery }`. Numer może wskazywać zamówienie albo grupę; dla grupy `status` jest zbiorczy (może być `partially_refunded`), a `items[]` zawiera pozycje (`orderId`, `orderNumber`, `status`, `productName`, `variant`, `quantity`, `serverName`, `amount`). Zły lub brakujący klucz to `404 ORDER_NOT_FOUND`. W sklepie ogólnym `nick` jest zamaskowanym e-mailem. `statusKey` (10 znaków) dostają zamówienia od 3.0 — wraca z kasy i vouchera oraz w adresie powrotu. Stary `GET /orders/:orderId/status` działa tylko dla zamówień sprzed 3.0.

## Odbiór treści cyfrowej

Gdy `delivery.ready` w statusie jest `true`, pobierz treść: `GET /orders/by-number/:orderNumber/delivery?key=<statusKey>` (limit 20/min/IP, `no-store`). Odpowiedź to `{ orderNumber, items[] }`, a pozycja ma `kind` (`license_keys`, `download`, `text`), `state` (`pending`, `awaiting_stock`, `delivered`, `revoked`), `keys[]`, `pendingUnits`, `text` i `download { url, fileName, expiresAt, maxDownloads, remaining, expired }`. `text` wyświetlaj jako zwykły tekst, nie HTML. `awaiting_stock` z `pendingUnits > 0` oznacza pustą pulę kluczy — klucze dojdą też e-mailem. Link `download.url` (`GET /downloads/:token`) zużywa jedno pobranie przy każdym otwarciu. Nieopłacone zamówienie to `409 ORDER_NOT_PAID`, zwrot lub spór `410 DELIVERY_REVOKED`. Konfiguracja po stronie sprzedawcy: [Dostawa treści cyfrowych](https://andcze.mintlify.site/pl/shop/digital.md).

## Widżety i prywatność

Właściciel może w ustawieniach sklepu wyłączyć dane publiczne (ostatnie zakupy, najwięksi kupujący, cel miesięczny, gracze online). Wyłączony widżet zwraca **pustą listę** dla wszystkich — strona powinna wtedy ukryć sekcję.

## Cache i limity

* Dane katalogu są cache'owane na CDN przez krótki czas — zmiana ceny w panelu pojawia się na stronie po chwili.
* Kasa i vouchery mają limit zapytań na IP. Zobacz [Błędy i limity](https://andcze.mintlify.site/pl/developers/errors-and-limits.md).

> **[SDK TypeScript](https://andcze.mintlify.site/pl/developers/sdk/typescript.md)**
>
> Wygodna warstwa nad tym API.

> **[API z kluczem](https://andcze.mintlify.site/pl/developers/api-keys.md)**
>
> Zarządzanie sklepem z serwera.


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