Skip to main content

Base URL & store identification

When you call the API through the store domain, you receive only that store’s data — no identifier to send. From a client without a domain (mobile/server), use the publishable key.

Envelope

Every JSON response uses the same envelope:

Errors

On errors error_code carries a stable machine-readable code and data is usually null. The frontend should switch on error_code, not display error (English, for debugging only).
  • Some refusals put the details needed to explain them in data: for example checkout.min_order_not_met carries min_order_total, subtotal, and currency.
  • Validation (422): error_code is validation.failed and the response also has detail, the list of invalid fields (the field is the last element of loc).
  • Rate limit (429): the response is {"detail": "..."}, without the envelope.
HTTP statuses follow standard semantics (200, 201, 400, 401, 403, 404, 409, 422, 429, 502).

Pagination

Lists accept page and page_size and return meta:

Internationalization

Many content endpoints accept ?lang=it|en|sq (or the Accept-Language header) and return fields already resolved in the requested language, falling back to the store’s default language.

Images

Image paths are relative (/uploads/products/xyz.webp): prepend the store’s origin → https://<domain>/uploads/.... In production they are served via a CDN/signed redirect, so use the URL exactly as returned.

Multi-tenancy in brief

Each store is an isolated tenant. The publishable key and domain determine the tenant for storefront calls; the staff token’s tenant_id claim determines it for the Admin API. There is no way, with one store’s credentials, to see another store’s data.