Skip to main content

Headless API

The Headless API module opens the shop's data over REST, so the storefront does not have to be the ECMS9 theme: a Next.js or Nuxt site, a mobile app, a kiosk or another company's system can read the catalog, fill a cart, place orders and show a customer their order history.

Everything is configured in Modules → Headless API.

Where it starts

The base address is https://your-shop/api/v1. Two paths are worth opening in a browser right away:

  • /api/v1/meta — shop name, locales, currency, API version and which optional features this shop exposes;
  • /api/v1/docs/ui — the full endpoint list; /api/v1/docs is the same thing as an OpenAPI file you can feed to Postman, Insomnia or a code generator.
Older integrations keep working

Paths without /v1 (/api/products, /api/cart, …) answer exactly as before, with the same fields. Nothing has to be rewritten when the module is updated.

What the API can do

AreaEndpoints
Catalogproducts with variants, gallery, stock, rating and parcel dimensions; categories; filters; search; banners; related products and promotions
Cartread, add, change quantity, remove, clear
Checkoutdelivery methods, payment methods, the shop's custom fields, placing the order
Customerregistration, login, profile, order list and order details with the waybill number; bonus balance (when the system_bonus module is installed)
Guest ordersorder status by order number + phone, and the waybill/tracking of such an order — for shops where most orders are placed without an account
Shop contentdelivery and payment terms, contacts, published info pages and a relevance search across them — the same answers the on-site AI chat quotes
DeliveryNova Poshta city and branch lookup, so a headless checkout can offer the same pickers the storefront has

Access tokens

By default the API answers anyone, exactly like the storefront pages it mirrors. Two switches tighten that:

  • Require a token for reading — the catalog is closed; only clients with a token see it;
  • Require a token for writing — cart, checkout and login require a token with the write right.

Create tokens in the same screen. Each token has a name and scopes: read-only by default, plus write (cart, checkout, login) and chat — the scope the on-site chat widget uses; it allows order status lookup by phone and a "talk to a human" handoff, and nothing else, so a token that ends up in the browser cannot become a write key. The token is shown once, at creation — the shop stores only its fingerprint. Give each integration its own token: you can then see how many requests it made, switch it off, or delete it without touching the others.

A token travels in a header:

Authorization: Bearer hk_xxxxxxxxxxxxxxxx

If something in front of the shop already uses Authorization (HTTP basic auth, for example), send X-Api-Key: hk_… instead — both are accepted.

Customers

POST /api/v1/auth/login returns a customer token (hc_…) that identifies the shopper in later requests — no cookies, which browsers block across domains anyway. The token's lifetime is a setting (30 days by default), and /auth/logout revokes it immediately.

The cart for an external front end

A cart normally lives in the PHP session, which a site on another domain cannot keep. So the API also has a server-side cart: the first write with use_key=1 returns a cart_key, and the client sends it back in the X-Cart-Key header. Checkout accepts the same key, so the order is created from exactly what the customer collected.

Guardrails

  • Request limit — per token, or per IP address for anonymous callers (120 per minute by default; 0 turns it off). A client that exceeds it gets HTTP 429 and the time to wait.
  • CORS — list the domains of your front ends. Empty means "same domain only", which is what a shop without an external storefront wants.
  • Stock numbers — you may expose exact stock, or only the "in stock" flag.
Check it in one command

php spark headless:selftest calls every endpoint of the shop and prints the result line by line — the fastest way to see that the API works on this site after switching the module on.