Skip to main content
Storefront API v1 is the public API your shop’s site uses in the browser. It needs no key and accepts no secrets — the shop is identified by shopId or domain. Responses are cached on the CDN, and CORS allows requests from shop domains and preview addresses.
On the site, use the SDK — createStorefront() sets the shopId, API address and language for you. Raw endpoints are handy in other languages and for debugging.

Endpoints

Base URL: https://itemshop.dev/api/v2/storefront/v1

Example: product list

Checkout

Response
Checkout rules:
  • A cart is 1–20 lines in items; more is 400 CART_TOO_LARGE. One line is a regular order. Two or more form a payment group: one transaction at the provider for the total, with a separate order per line inside. The response then has groupId and orderIds[], and orderId and orderNumber point to the group. A discount code is applied once for the whole cart, and a payment method’s min/max limits are checked against the total.
  • Nick or e-mail: a game shop requires nick (3–16 characters a-zA-Z0-9_, otherwise NICK_REQUIRED); a general shop requires email (otherwise EMAIL_REQUIRED). A product with digital delivery (deliveryKind other than commands) always requires email, even in a game shop.
  • Consents are required: terms (the terms) and immediateDelivery (a combined consent to immediate delivery and loss of the right of withdrawal), plus legalVersion — the version of the documents from GET /shops/:shopIdOrDomain that you showed the buyer. If the shop changes its terms, checkout returns LEGAL_DOCUMENTS_CHANGED — fetch the shop again and show the new documents.
  • Idempotency-Key (e.g. a UUID) is required. Retrying with the same key won’t create a second order.
  • returnUrl must point to the shop’s domain or a preview address (otherwise RETURN_URL_NOT_ALLOWED). After payment the buyer returns to it with ?itemshop_order=<number>&itemshop_key=<status key> (any #… fragment is dropped) — read them from location.search and fetch the status by number and key. In production localhost, 127.0.0.1 and [::1] are rejected (also as Origin). Without returnUrl the buyer lands on the shop’s hosted status page.
  • A free order (100% discount) has free: true and a redirectUrl that leads straight to the status page.
  • The payment method is the code from /payment-methods — a shop can have several methods from the same provider.
  • Bot protection is adaptive: it doesn’t block regular purchases, and checkout is also protected by a rate limit and duplicate-request blocking.
  • The site does not process payments — it only redirects to redirectUrl.

Errors

Every error has the same envelope with a machine-readable code — translate the message in your UI based on it; the error field is for the developer only.

Redeeming a voucher

POST /shops/:shopId/vouchers/redeem with { code, nick } and an optional email (an address for digital content; also turnstileToken or the cf-turnstile-response header) returns { orderId, orderNumber, statusKey, status, productName, serverName, nick }. A voucher creates a free order delivered like a normal purchase.

Order status

GET /orders/by-number/:orderNumber/status?key=<statusKey> returns { orderId, orderNumber, shopId, status, productName, serverName, nick, amount, currency, createdAt, groupId, items[], delivery }. The number can point to an order or a group; for a group status is aggregated (it can be partially_refunded) and items[] lists the lines (orderId, orderNumber, status, productName, variant, quantity, serverName, amount). A wrong or missing key is 404 ORDER_NOT_FOUND. In a general shop nick is a masked e-mail. Orders created since 3.0 have a 10-character statusKey — it comes back from checkout and voucher redemption and in the return URL. The old GET /orders/:orderId/status works only for pre-3.0 orders.

Collecting digital content

When delivery.ready in the status is true, fetch the content: GET /orders/by-number/:orderNumber/delivery?key=<statusKey> (20/min/IP, no-store). The response is { orderNumber, items[] }; a line has kind (license_keys, download, text), state (pending, awaiting_stock, delivered, revoked), keys[], pendingUnits, text and download { url, fileName, expiresAt, maxDownloads, remaining, expired }. Render text as plain text, never HTML. awaiting_stock with pendingUnits > 0 means the key pool ran dry — keys also follow by e-mail. Each opening of download.url (GET /downloads/:token) uses one download. An unpaid order is 409 ORDER_NOT_PAID, a refund or dispute 410 DELIVERY_REVOKED. Seller-side setup: Digital content delivery.

Widgets and privacy

In the shop settings, the owner can turn off public data (recent purchases, top spenders, monthly goal, online players). A disabled widget returns an empty list for everyone — the site should then hide the section.

Cache and limits

  • Catalog data is cached on the CDN for a short time — a price change in the panel shows up on the site after a moment.
  • Checkout and vouchers have a per-IP request limit. See Errors and limits.

TypeScript SDK

A convenient layer over this API.

API with a key

Managing the shop from a server.