Shoppers
Sign shoppers in, keep them signed in for 14 days, and read an order back as a guest.
A store key says which store is calling. A shopper credential says which customer. You need one for the operations that touch a customer's own data: their membership, their orders and bookings, applying for membership, and placing an order on a members-only store.
Shoppers sign in with Firebase Auth, in the store's own tenant. ShopEazy verifies the token. You own the sign-in screens.
Three credentials
| Credential | Header | Lasts | Use it for |
|---|---|---|---|
| Shopper session | X-Shopper-Session | 14 days | A server-rendered site. Keep it in your own httpOnly cookie |
| Shopper token | X-Shopper-Token | 1 hour | A browser that already has the Firebase client SDK open |
| Order token | X-Order-Token | 30 days | A guest reading back one order they placed |
Send a shopper session or a shopper token together with the store key. If you send both shopper credentials, the session is checked first.
Sign a shopper in
The store tells you which Firebase tenant its shoppers live in. Read it from GET /v1/store:
{ "data": { "auth": { "tenantId": "<tenant id>" } } }auth.tenantId is null for a store on the shared pool. It is not a secret.
Set the tenant on the browser's Firebase Auth before you sign the shopper in:
import { getAuth } from 'firebase/auth';
const auth = getAuth();
auth.tenantId = store.auth.tenantId; // before signInWith...A uid is only unique within one tenant, so a token from the wrong pool is refused. That is isolation working, not a bug.
Create a shopper session
Send a fresh Firebase ID token to ShopEazy. Your key needs the members:write scope.
curl https://api.shopeazy.co/v1/store/shopper/session \
-H "Authorization: Bearer sez_pub_..." \
-H "Content-Type: application/json" \
-d '{ "idToken": "<firebase id token>" }'{
"data": {
"sessionToken": "<session token>",
"expiresAt": 1793846400000,
"shopper": {
"uid": "shopper_123",
"email": "sipho@example.co.za",
"name": "Sipho Dlamini",
"phone": null
}
}
}The answer is 201. The session lasts 14 days. Put sessionToken in your own httpOnly cookie and send it as X-Shopper-Session on later calls. ShopEazy also saves the shopper's profile for the store, so your site does not have to.
The shopper's email must be verified. If it is not, the call is 403 email_unverified.
With the typed client:
import { shopperCookie, readShopperToken } from '@shopeazy/storefront-client/session';
const { sessionToken } = await shopeazy.shopper.createSession(idToken);
headers.set('Set-Cookie', shopperCookie(sessionToken, { maxAgeSeconds: 60 * 60 * 24 * 14 }));
// On a later request:
const token = readShopperToken(request.headers.get('cookie'));
const me = token ? await shopeazy.asShopperSession(token).me() : null;Use the session
curl https://api.shopeazy.co/v1/store/me \
-H "Authorization: Bearer sez_pub_..." \
-H "X-Shopper-Session: <session token>"{
"data": {
"shopper": { "uid": "shopper_123", "email": "sipho@example.co.za", "name": "Sipho Dlamini", "phone": null },
"membership": null,
"canCheckout": true
}
}You always get the caller's own record. canCheckout is true on an open store, or for an active member of a members-only store.
Sign out
curl -X DELETE https://api.shopeazy.co/v1/store/shopper/session \
-H "Authorization: Bearer sez_pub_..." \
-H "X-Shopper-Session: <session token>"This revokes the shopper's refresh tokens. It is best effort: an already invalid session is not an error. Clear your cookie either way.
Use a shopper token instead
A browser that already holds a Firebase ID token can send it directly as X-Shopper-Token. It lasts one hour, so a server-rendered page goes signed out every hour unless the browser refreshes it. For a server, prefer a session.
const me = await shopeazy.asShopper(idToken).me();Guests: the order token
A shopper does not have to sign in to buy. POST /v1/store/orders returns an accessToken for that one order. It is valid for 30 days and is bound to that order in that store.
To read the order back, or to confirm payment, send it as X-Order-Token:
curl https://api.shopeazy.co/v1/store/orders/order_789 \
-H "Authorization: Bearer sez_pub_..." \
-H "X-Order-Token: <order access token>"The shopper who placed the order may use their shopper credential instead. If you send neither, the call is 401 order_access_required. A credential for a different order, or an expired token, is 404 not_found: the same answer as an order that does not exist.
Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | shopper_required | The call needs a signed-in shopper and none was sent |
| 401 | invalid_shopper_token | The session or token is not valid or has expired. Sign the shopper in again |
| 401 | order_access_required | No order token or shopper credential was sent for this order |
| 403 | email_unverified | The shopper has not verified their email |
| 403 | not_a_member | A members-only store, and this shopper is not an active member |
Coming soon
Email verification codes, password reset, an address book, a profile update and claiming guest orders for shoppers are coming soon. The API does not offer them yet.