The Client API is the half of AppEngine that your customers' apps talk to — order history pages in a customer portal, "manage subscriptions" screens, the storefront's wishlist, the gig-worker app's job feed. It runs alongside the staff/operator API but uses a separate auth model and a separate URL prefix.
Two principal types, two URL trees
AppEngine separates the people who run an app (Users) from the people who use it (Customers). The URL prefix tells you which audience an endpoint serves:
| Prefix | Audience | Auth |
|---|---|---|
/profile/customer/* | Customer auth flows | Public |
/client-data/* | Customer's own profile and account | Customer JWT |
/client/community/* | Customer's social/community surface | Customer JWT |
/client/finance/* | Customer wallets and payouts | Customer JWT |
/client/events/* | Customer ticket purchase and check-in | Customer JWT |
/client/logistics/* | Customer order tracking and gig-worker portal | Customer JWT |
/client/affiliate/* | Affiliate partner portal | Customer JWT |
/client-app/* | Multi-tenant client app management | Staff JWT |
/storefront/* | Public commerce surface | Mostly public |
A customer-facing app uses the customer JWT obtained from POST /profile/customer/signin. The same orgid header rules apply — customer auth is org-scoped just like staff auth.
Auth pattern
Every authenticated client endpoint resolves the principal via @CurrentCustomerOrUser(). This decorator accepts either a customer JWT or a user JWT, but client endpoints that handle PII or money explicitly check that the principal is a customer (or that the user has impersonation rights).
const customerJwt = await fetch('/api/profile/customer/signin', {
method: 'POST',
headers: { 'Content-Type': 'application/json', orgid: ORG_ID },
body: JSON.stringify({ email, password }),
}).then(r => r.json()).then(d => d.token);
const orders = await fetch('/api/client-data/orders', {
headers: {
orgid: ORG_ID,
Authorization: `Bearer ${customerJwt}`,
},
}).then(r => r.json());
What the Client API does not do
- It does not expose write access to other customers' data — every read and write is implicitly scoped to the authenticated customer's
sk. - It does not include staff endpoints. If you need to manage someone else's order, that's the operator API (e.g.
POST /storefront/order/process/:orderNumber). - It does not bypass the catalog auth model. Public storefront browsing endpoints (
GET /storefront/products) are unauthenticated; "my orders" requires the customer JWT.
Pages in this section
- Customer account — profile, addresses, payment methods, dashboard
- Customer storefront — order history, wishlists, saved carts
- Customer community — social profile, feed, messaging
- Customer events — ticket purchase and check-in
- Customer logistics — order tracking and gig-worker job feed
- Customer finance and wallet — wallet balance, payouts, payment methods