Skip to content

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 ​

ScopeHow to triggerFields returned
PublicNo token, or invalid tokenOnly public-safe fields
CustomerValid customer JWTPublic fields + customer-specific fields
BackendValid admin JWTAll 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