The three tiers
Design principles
Opaque tokens, server-side lookup — not JWTs
Opaque tokens, server-side lookup — not JWTs
Tokens are random opaque strings stored as
argon2id hashes in
Postgres. Verification is a hash + lookup, not signature
verification. This buys instant revocation, server-controlled
payload, and smaller wire size — at the cost of a database
round-trip per request. Easy trade-off at our scale.Idempotency on every mutation
Idempotency on every mutation
Every mutating endpoint requires an
Idempotency-Key header (any
UUID is fine). Replays of the same key within 24 hours return the
cached response, so retries — whether from a flaky network or an
AI agent’s retry loop — are always safe.Multi-tenant by construction
Multi-tenant by construction
Every query is filtered by
site_id, drawn from the token’s
metadata. No endpoint can return cross-tenant data — there’s no
code path that elides the filter.Tokens never logged
Tokens never logged
Token values appear in server-side logs zero times — only
token_id
references after hash-lookup. Origin/UA/IP are logged for audit;
the token itself never is.Choosing the right token
Storefront token
Calling Stella from your server (Next.js route, Cloudflare Worker,
Express handler). Lives in your secrets manager.
Customer token
Acting as a logged-in shopper. Returned by
POST /customer/login.
Stored in browser session/cookie.Agent token
An AI agent shopping on a customer’s behalf. Minted via OAuth
Device Authorization (RFC 8628) consent flow.
Headers cheat sheet
X-Stella-Token) is always present for
storefront-surface calls, even when a customer or agent token is also
attached. The merchant-tier token identifies the tenant; the
customer/agent token identifies the caller within that tenant.