ShopEazydevelopers
Authentication

Storefront keys

Publishable and secret keys, their scopes, and how a merchant issues and revokes them.

Every Storefront API request carries a per-store key as a Bearer token:

Authorization: Bearer sez_pub_...

A key belongs to one store. The merchant issues it in the console and can revoke it there. The API holds no user, workspace or role for a key: a key acts as the store.

Publishable and secret keys

PublishableSecret
Prefixsez_pub_sez_sk_
Where it can liveA browser, an app, a serverA server only
Default scopescatalog:read, checkout:write, members:read, members:write, orders:read, requests:writeEvery publishable scope, plus members:manage

A publishable key can read the catalogue and place orders, but it cannot read anyone's data on its own. The member and order endpoints also need a signed-in shopper. See Shoppers.

A secret key adds members:manage, which is merchant-side member review: list, approve, decline and revoke members. Never put a secret key in a browser. The client throws if you construct one there.

ShopEazy stores only a SHA-256 hash of a key. The raw key is shown once, when it is created.

Scopes

ScopeLets the key
catalog:readRead the store, products, services, kits, availability and policies
checkout:writeQuote, place orders, start payment and confirm payment
members:readRead the signed-in shopper's own membership
members:writeCreate a shopper session and apply for membership
orders:readRead the signed-in shopper's orders and bookings
requests:writeSend a contact-form enquiry
members:manageReview members. Secret keys only

A request that needs a scope the key lacks gets 403 insufficient_scope.

Scopes are frozen when a key is issued

Adding a scope to the defaults later does not grant it to keys that already exist. To get a new capability, issue a new key. This keeps keys least-privilege, but it also means a new capability is invisible to every current integration until someone issues a new key.

Issue a key

In the console, open Settings, then Channels, then API. Under New key, enter a label, choose Publishable or Secret, and select Create key. Copy the key straight away.

Issuing a key needs the Growth or Scale plan, or a live trial. See Plans.

Revoke a key

On the same page, select Revoke next to the key. The key stops working immediately and cannot be brought back. A revoked key answers 401 revoked_token.

ShopEazy records when each key was last used. The ShopEazy app can list a store's keys with their type, scopes and last use, but never the key itself.

The API channel switch

A merchant can switch the API channel off for a store at any time. While it is off, every key for that store is refused with 403 api_channel_off. Switching it back on restores them.

Plan

The Storefront API is included with Growth and Scale. On Starter, every key answers 403 plan_limit. The keys are kept, and upgrading restores access.

Browsers and CORS

A publishable key works from a browser only on websites the store allows. The merchant adds them in the ShopEazy console under Settings, Channels, API, Allowed websites. Each entry is an origin like https://www.example.co.za: no path and no wildcard. While you develop, http://localhost:3000 (any port) can be added. A store can list up to 20.

  • A browser call from a website that is not on the list is refused with 403 origin_not_allowed. The browser shows it as a CORS error, because the answer carries no Access-Control-Allow-Origin.
  • A listed website gets Access-Control-Allow-Origin with itself. Cookies are never allowed.
  • The preflight (OPTIONS) carries no key, so it is answered the same for every website. The call that follows is the one that is checked.
  • A call with no Origin header, from a server or curl, is not affected. Add the website, not the server.
  • A secret key never works in a browser. Keep it on your server.

Seeing a CORS error?

Ask the store owner to add your website under Allowed websites. To see the real error, repeat the call from curl with an Origin header.

A browser may send these headers: Authorization, Content-Type, X-Shopper-Token, X-Shopper-Session, X-Order-Token, Idempotency-Key and X-Request-Id. It may read X-Request-Id, Idempotent-Replay and the rate-limit headers.

Every request is checked against the store

After the key resolves, the store must pass these checks. They run on every operation.

CheckError
The store exists404 store_not_found
The store is not suspended403 store_suspended
The store has not closed403 store_closed
The API channel is on403 api_channel_off
The workspace is on a live plan403 store_inactive
The plan includes the API403 plan_limit

Treat store_suspended, store_closed and store_inactive as "shop closed" in your UI.

Key errors

StatusCodeMeaning
401missing_tokenNo Authorization: Bearer header was sent
401invalid_tokenThe key is not valid
401revoked_tokenThe key was revoked. Issue a new one
403insufficient_scopeThe key lacks the scope this call needs. Issue a new key

Read Errors for every code.

On this page