Skip to content

Tenants & context

litecommerce is multi-tenant from the ground up. A tenant is one merchant's store — its catalog, inventory, orders, staff, and settings. Every row in the database is tenant-scoped, and every API guard enforces that scoping on public, merchant, and platform routes alike.

How context is resolved

Tenant context is usually carried in the x-organization-slug header — the slug of the store you're acting on. It's required on tenant-resolving public requests and merchant requests.

x-organization-slug: your-store
  • Public reads need only this header. A server-side guard resolves the organization from the slug (404 if no such store, 400 if the header is missing) and scopes every query to it — so a storefront reads its own catalog with no privileged credentials in the browser.
  • Token-only public routes resolve tenant context from their opaque token target instead of the slug header. For example, POST /public/checkout/sessions/:token/payment-session does not send x-organization-slug.
  • Merchant requests send the header and an Authorization: Bearer Supabase JWT. After the token is validated, a membership check confirms the authenticated user actually belongs to the org named by the slug before any read or write proceeds.

Because the slug only ever resolves to one organization and every query is scoped to its id, a request can't reach across tenants — there's no parameter that widens the scope. A mismatched slug + session returns an authorization error rather than leaking another tenant's data.

  • Auth & roles — who can do what within a tenant
  • API keys — the planned server-to-server auth path (staff JWT today)