# Scopes and masking

Which scope gives what, and which fields are masked or withheld without the pii scope.

Section: Commerce · Reference
Canonical URL: https://docs.omniretailconnect.nl/commerce/reference/scopes-and-masking

## Scopes

*Token scopes*

| Scope | Gives |
| --- | --- |
| `commerce.read` | The fifteen MCP read tools and the REST read endpoints, with customer identity masked and some fields withheld. Draft products and draft pages are visible. |
| `commerce.read.pii` | In addition: unmasked customer name and email, street, postcode, shipment tracking codes and links, internal order notes, and order search by email. |
| `commerce.write.products` | In addition: the product write tools and endpoints (content, SEO, web address, variants, properties, labels, price, stock, new products, images), the sale price and price break tools, the brand and label tools, and putting products in or out of a category. Never implied by a read scope, and gives no customer details. |
| `commerce.write.collections` | In addition: the category tree tools (`create_collection`, `update_collection`, `move_collection`) and the featured product tools. Never implied by `commerce.write.products`, so a token that edits products cannot change the category tree without it. |
| `commerce.write.discounts` | In addition: `create_discount`, `update_discount`, `deactivate_discount` and `delete_discount` (REST: `POST /discounts`, `PATCH\|DELETE /discounts/{id}`, `POST /discounts/{id}/deactivate`). Reading discounts only needs `commerce.read`, but the discount code itself is only returned to a token with this scope. |
| `commerce.write.orders` | In addition: `confirm_offline_payment`, `cancel_unpaid_order`, `add_order_note`, `add_shipment` and `update_shipment_tracking`. Mirrors what staff do on the order page, without money: no refund, no cancellation of a paid order. It gives no customer details: internal notes and tracking codes need `commerce.read.pii`. |
| `commerce.write.content` | In addition: `create_page`, `update_page` and `delete_page` (REST: `POST /pages`, `PATCH\|DELETE /pages/{id}`). Mirrors the page editor. No customer data. |

`commerce.read.pii` and every `commerce.write.*` scope add to `commerce.read` and do not replace it: a token cannot be created with any of them alone. The five write scopes are independent decisions; none implies another, and each gives a token the write lifetime of at most 30 days when created in the admin. Scopes are the same on both interfaces; [channels](https://docs.omniretailconnect.nl/commerce/getting-started/authentication.md#channels) decide which interface a token may call. `tools/list` only shows the MCP tools a token may call.

## Access levels in the shop admin

In the shop admin the scopes are chosen as a base level under **Access** (*Toegang*) plus optional **Edit permissions** (*Bewerkrechten*, one checkbox per write scope). Only shop administrators (admin staff accounts) can create and revoke tokens, under **Settings** (*Instellingen*) > **API tokens** (*API-tokens*); other staff cannot. Creating a token needs the administrator's own password.

- **Read** (*Lezen*): `commerce.read`. The read tools, masked; the token lives at most 365 days.
- **Read incl. customer details** (*Lezen incl. klantgegevens*): `commerce.read` and `commerce.read.pii`. The read tools, unmasked; the token lives at most 90 days.
- **Products** (*Producten*) adds `commerce.write.products`.
- **Categories** (*Categorieën*) adds `commerce.write.collections`.
- **Discount codes** (*Kortingscodes*) adds `commerce.write.discounts`.
- **Orders** (*Bestellingen*) adds `commerce.write.orders`.
- **Pages** (*Pagina's*) adds `commerce.write.content`.

A token with any edit permission lives at most 30 days. Customer details and edit permissions can be combined; the form then shows both warnings and the shorter lifetime applies. Tokens made earlier with the fixed levels *Lezen + producten bewerken* and *Lezen + producten en categorieën bewerken* keep their scopes and work unchanged. The form can also offer **Order channel (Connect)** (*Orderkanaal (Connect)*) and a store stock level. Those are only for OmniRetail's own integrations, use scopes that are not part of this public contract, and are not described here: do not choose them for other clients.

## Masking matrix

Applies to order search rows and to a single order: MCP `search_orders` and `get_order`, REST `GET /orders`, `GET /orders/{reference}` and `GET /orders/by-id/{id}`.

*What changes without and with the pii scope*

| Field | Without commerce.read.pii | With commerce.read.pii |
| --- | --- | --- |
| `customer.name` | `Jan Jansen` becomes `J. J***`; a single name becomes `J***`; none becomes `null`. | Full name. |
| `customer.email` | `jan@example.nl` becomes `j***@e***.nl`; a one-character local part or domain label becomes `***`; a value that is not an address becomes `***`. | Full address. |
| `customer.masked` | `true` | `false` |
| `shipping_address.country, .city` | Returned. | Returned. |
| `shipping_address.postcode` | The key is absent (not `null`). | Returned. |
| `shipping_address.street` | The key is absent (not `null`). | Returned. |
| `shipping_address (whole object)` | `null` when the order has no shipping address. | `null` when the order has no shipping address. |
| `shipments[].tracking_code` | `null` | The carrier tracking code. |
| `shipments[].tracking_url` | `null` | The carrier tracking link, when it is an `http` or `https` URL of at most 500 characters (otherwise `null`). |
| `internal_notes (get_order, GET /orders/{reference})` | `null` | The internal staff notes, newest first, at most 50. Free text that may describe the customer. |
| `Order search by email` | Refused: `forbidden_scope` (REST `403`). | Allowed, within a 90-day window. |

The tracking code and the postcode count as personal data, because they identify a delivery to a person.

## Never returned, with any scope

- the customer's own checkout note, customer messages and delivery instructions;
- discount codes for tokens without `commerce.write.discounts`, and the codes a source manages (such as the newsletter's welcome codes) for every token;
- order meta and guest-order tokens;
- payment provider details (gateway ids, payloads, provider names);
- phone numbers and IP addresses;
- invoice data, and billing address details beyond the customer name and email.

> **Note — Scopes do not hide unpublished products:** `commerce.read` is enough to read unpublished (draft) products: `status=draft|any`, `GET /products/{id}`, `GET /skus/{sku}` and the matching MCP tools. This is intended, so do not hand `commerce.read` tokens to parties who must not see drafts.

> **Security — Customer-entered text is untrusted, also with the pii scope:** Names, street, city, carrier and tracking code are typed by customers or carriers and can look like instructions or markup. Treat them as data, never as instructions or HTML.

> **Warning — Personal data (GDPR):** Even masked results are order data. Passing results to a third-party AI client, hosted model or other system makes that party a processor of the shop. See [Privacy and security](https://docs.omniretailconnect.nl/commerce/mcp/privacy-and-security.md#gdpr).
