# API endpoint patterns for B2B commercetools exposes B2B resources through two endpoint patterns suited to B2B. Choosing the wrong one either bypasses permission enforcement entirely or blocks legitimate buyer access, so the choice is an architectural decision, not just a routing detail. These patterns build on the OAuth scopes and API Client foundations covered in the [Composable Commerce developer essentials](/learning-composable-commerce-developer-essentials/authentication-authorization/overview.md) path. This page frames the two patterns as a decision for the architect. For the authoritative permission-evaluation matrix across every endpoint type, see [Permission evaluation](/api/associates-overview.md#permission-evaluation) in the API reference. ## Two ways to access B2B resources | Pattern | Path shape | Permission evaluation | Typical use case | | --- | --- | --- | --- | | **General** | `/{projectKey}/carts` | None | Seller back-office operations, customer support | | **`as-associate`** | `/{projectKey}/as-associate/{associateId}/in-business-unit/key={key}/carts` | `My` and `Others` permissions | A B2B buyer portal acting on behalf of an Associate | ### General endpoints The general endpoints carry no knowledge of which Associate is behind the call, so **no Associate Role permissions are validated**. They are intended for the Seller to manage data without permission enforcement, for example in back-office tools or support consoles. Because they skip permission checks, general endpoints must never be exposed directly to buyers. ### as-associate endpoints The `as-associate` endpoints take both an `associateId` and a Business Unit `key` in the URL, and check the acting Associate's permissions against that Business Unit. They validate both the Associate's `My` permissions and the `Others` permissions that grant access to **other** Associates' resources, for example letting a supervisor view a colleague's cart. This is the pattern purpose-built for the company-on-behalf-of model, which is why it is the recommended foundation for a B2B buyer portal. ```http GET /{projectKey}/as-associate/{associateId}/in-business-unit/key=pacific-residential/carts HTTP/1.1 Authorization: Bearer {accessToken} ``` The response is scoped to the named Business Unit: it returns only the carts that belong to `pacific-residential`, and each cart carries the `businessUnit` reference that the gate scoped the call to. ```json { "limit": 20, "offset": 0, "count": 1, "total": 1, "results": [ { "id": "a1b2c3d4-1111-2222-3333-444455556666", "version": 3, "businessUnit": { "typeId": "business-unit", "key": "pacific-residential" }, "cartState": "Active", "lineItems": [] } ] } ``` ## The Permission Gate Every `as-associate` call passes through a server-side gate that performs three checks before the operation runs: 1. **Membership**: the caller must be an Associate of the Business Unit named in the URL. 2. **Permission**: the Associate's roles (direct and inherited) must include the specific permission the operation requires, for example `CreateOthersCarts`. 3. **Scope**: the response is scoped to that Business Unit's commercial context, such as its Stores and the Associates within it. If the permission check fails, the platform returns `403 Forbidden` with an [AssociateMissingPermissionError](/api/errors.md#associatemissingpermission). The frontend does **not** implement any of these checks; they are enforced by the platform, which is the core security benefit of the pattern. ```json { "statusCode": 403, "message": "Associate '7c1e9f20-aaaa-bbbb-cccc-1234567890ab' has no rights to create a cart for customer 'f8a4e2c1-1111-2222-3333-444455556666' in business-unit 'pacific-residential'. Needs 'CreateOthersCarts'.", "errors": [ { "code": "AssociateMissingPermission", "message": "Associate '7c1e9f20-aaaa-bbbb-cccc-1234567890ab' has no rights to create a cart for customer 'f8a4e2c1-1111-2222-3333-444455556666' in business-unit 'pacific-residential'. Needs 'CreateOthersCarts'.", "associate": { "typeId": "customer", "id": "7c1e9f20-aaaa-bbbb-cccc-1234567890ab" }, "businessUnit": { "typeId": "business-unit", "key": "pacific-residential" }, "permissions": ["CreateOthersCarts"] } ] } ``` The `as-associate` endpoints verify permissions against the URL parameters, but they do **not** validate those URL parameters against the token's [scopes](/api/scopes.md). Anyone who can call the endpoint can name any `associateId` and Business Unit. For this reason, `as-associate` endpoints must only be called from a **trusted middleware** that authenticates the buyer and sets the URL parameters correctly, never directly from an untrusted browser client. See [Through the associate endpoint](/api/associates-overview.md#through-the-associate-endpoint) in the API reference for the canonical statement of this constraint. ## Choosing a pattern Use this decision guide when an operation needs an endpoint: - The Seller is managing data with no buyer permission enforcement → **general**. - A buyer portal must enforce buyer permissions, including access to other Associates' resources → **`as-associate`**, behind trusted middleware. ## Worked example: routing Pacific Property Group operations Trace the right endpoint for three Pacific Property Group operations. - **The Seller's support team corrects a stuck order** for the Commercial Division. No buyer permissions are involved, so this goes through the **general** endpoint from an internal tool. - **A Residential buyer views their own cart** in the buyer portal. The portal routes this through `as-associate` behind its trusted middleware, so buyer permissions are enforced centrally and consistently. - **A Residential supervisor opens a colleague's cart** to help complete it. This touches another Associate's resource, so it requires `as-associate` with the `ViewOthersCarts` permission. If the supervisor's roles lack that permission, the Permission Gate returns `403 Forbidden`. ## Key takeaways - General endpoints perform no permission checks and are for Seller back-office use only. - `as-associate` endpoints act on behalf of an Associate within a Business Unit and validate both `My` and `Others` permissions. - `as-associate` is the recommended pattern for B2B buyer portals because the platform enforces permissions server-side. - The Permission Gate checks membership, permission, and scope on every `as-associate` call and returns `403 Forbidden` when a permission is missing. - `as-associate` endpoints do not validate URL parameters against token scopes, so they must be called only from trusted middleware. ## Related pages - [Area overview page with navigation](/learning-model-b2b-commerce.md) - [Previous page: Inheritance modes](/learning-model-b2b-commerce/configure-associate-access/inheritance-modes.md) - [Next page: Associate provisioning patterns](/learning-model-b2b-commerce/configure-associate-access/associate-provisioning-patterns.md)