Appearance
Response Scoping
The API uses scope-based field filtering to control what data is returned based on your authentication level. This means the same endpoint can return different fields depending on who is calling it.
Scopes
| Scope | How to trigger | Fields returned |
|---|---|---|
| Public | No token, or invalid token | Only public-safe fields |
| Customer | Valid customer JWT | Public fields + customer-specific fields |
| Backend | Valid admin JWT | All fields, including admin-only data |
How It Works
Resource transformers check the request scope and conditionally include fields. For example, a product resource might return:
- Public:
id,name,price,slug,image - Customer: All public fields +
wishlistStatus,purchaseHistory - Backend: All fields +
costPrice,adminNotes,supplierId
There is no error or indication when fields are omitted due to scope. The response simply contains fewer keys.
Relation Scoping
Relations can also be filtered by scope, but unlike field-level scoping above, this is opt-in per controller rather than a general platform behavior: it only takes effect where rest_policies.php declares a relations allow-list for that controller's policy. Today that's Customer and Line only. For any other endpoint, no allow-list is defined, so every relation the endpoint supports is available at every scope — only the resource's own fields (and the fields of an included relation) narrow by scope.
Where a controller does declare an allow-list, the policy maps each scope to its own list of allowed relation names, e.g.:
- Public might allow:
translations,categories,images - Customer might add:
reviews,variants - Backend gets all relations
If you request a relation via ?with= that isn't allowed for your scope, it is silently removed from the response. See the REST Middleware & RBAC guide for the mechanism and the current allow-lists.
This is per-endpoint enforcement, not a platform-wide guarantee. Relation loading recurses across entity boundaries, so an allow-list on one controller does not deny the underlying data everywhere: if a sibling endpoint serving the same related entity is also guest-readable and declares no allow-list, that data remains reachable by nesting through it, even though the first endpoint denies it directly.
Practical Implications
- Frontend storefront code (public/customer scope) will never accidentally receive admin-only data
- Admin panel code (backend scope) gets the full dataset
- You don't need separate endpoints for public vs admin views — the same endpoint adapts