> ## Documentation Index
> Fetch the complete documentation index at: https://muveya.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Scopes

> API key scopes for /v1, OAuth scopes for MCP, their matching member permissions, and least-privilege examples.

A scope is a permission granted to an API key when it is created. Every `/v1` operation lists the scopes it requires, and the server checks them on every request.

## How scopes work

* **Colon form.** API scopes are written `area:read` (for example `inventory:read`). Team member permissions use a dot form (`inventory.read`); the server translates one into the other with a fixed table, shown below.
* **All required scopes must be present.** If an operation requires a scope the key does not hold, the answer is `403` with the code `api_keys.scope_missing`. The response does not say which scope is missing.
* **No wildcard.** There is no "all" scope and no platform key. A key without scopes cannot exist.
* **Nothing is implied.** `catalog.cost:read` is never granted by `catalog:read`; a key that needs costs must carry both.
* **Read only.** Every scope is a read scope. The only write on `/v1`, `POST /v1/analytics/exports`, is covered by `analytics:read`.
* **Fixed for the life of the key.** Scopes cannot be added to or removed from an existing key. Request a new key with the scopes you need and revoke the old one (see [Rotate a key](/docs/en/api-reference/authentication#rotate-a-key)).
* **`GET /v1/me` needs no scope.** Use it to see the scopes of a key.

## The scopes

| Scope | Operations it opens | Maps to member permission | Notes |
| - | - | - | - |
| `clinics:read` | `GET /v1/clinics`, `GET /v1/warehouses` | `clinics.read` | Locations and warehouses with name, kind and status. There is no member permission with this name in **Team**; it exists only for keys. |
| `catalog:read` | `GET /v1/catalog/items`, `GET /v1/catalog/items/{itemId}`, `GET /v1/catalog/categories` | `catalog.read` (**Read the catalog**) | Catalog items of every status, without cost. |
| `catalog.cost:read` | No operation by itself | `catalog.cost.read` (**View supply costs**) | Adds `cost`, `currency`, `costStatus` and `costMeasurement` to catalog items, and `unitCost` and `currency` to order lines. Combine it with `catalog:read` or `orders:read`. |
| `inventory:read` | `GET /v1/inventory/balances`, `GET /v1/inventory/boxes/{boxId}`, `GET /v1/inventory/boxes/{boxId}/balance`, `GET /v1/inventory/boxes/{boxId}/movements` | `inventory.read` (**View inventory**) | Quantities, box details and ledger movements. No money. |
| `orders:read` | `GET /v1/orders`, `GET /v1/orders/{orderId}` | `orders.read.all` (**View all orders**) | Every order of the dental clinic. Order `value` and `patientRef` are never included. |
| `fulfillment:read` | `GET /v1/fulfillments`, `GET /v1/fulfillments/{orderId}` | `fulfillment.read` (**View fulfillment**) | Delivery records and custody history. |
| `analytics:read` | Every `GET /v1/analytics/...` operation, `POST /v1/analytics/exports` and `GET /v1/analytics/exports/{exportId}` | `reports.read` (**View reports**) | Aggregated counts, quantities and durations. |

### How analytics reads other data

To compute its figures, an analytics operation reads orders, stock and deliveries on the server with read access limited to that computation. It never exposes a cost, an order value or a patient reference, and it does not open the other operations to the key: a key with only `analytics:read` still receives `403` on `GET /v1/orders`.

## What no scope grants

| Data or action | Why a key never gets it |
| - | - |
| Order totals (`value`, `approvalPlan.evaluatedValue`) | They require the member permission `orders.value.read` (**View order values**), which no API scope maps to. |
| Patient references (`patientRef`) | They require `orders.patient_ref.read` (**View external patient references**), which no API scope maps to. |
| Creating or changing orders, stock, catalog, members or keys | `/v1` has no such operations. Use the console. |
| Approving, picking, dispatching, confirming delivery or receipt | These are acts of a person. A key is not a team member. |

## OAuth scopes on MCP

The MCP endpoint `/mcp` uses OAuth, not the API key used by `/v1`. A tool runs only when the Connected App received the scope and the signed-in member still has the matching permission. Otherwise it returns `common.forbidden`.

| MCP tool or resource | OAuth scope |
| - | - |
| `clinics.list`, `inventory.check` | `inventory:read` |
| `catalog.search` | `catalog:read`, plus `catalog.cost:read` for cost fields |
| `orders.get` | `orders:read` |
| `analytics.consumption`, `management.briefing`, `management.compare_clinics` | `analytics:read` |
| `approvals.list_pending`, `management.pending_decisions`, `fulfillment.get_pick_list` | Unavailable in the current read-only OAuth scope set. |
| Reference resources | Any active OAuth connection. |
| `muveya://tenant/approval-policy-summary` | Unavailable in the current read-only OAuth scope set. |

See [MCP tools](/docs/en/mcp/tools) and [MCP resources](/docs/en/mcp/resources).

## A key is not a team member

The mapped permission is what the server checks, but a key differs from a person who holds the same permission:

* A key reads **every location and warehouse** of its dental clinic. The location and warehouse access you set for members in **Team** does not apply to it.
* A key never sees order values or patient references, even though an owner can grant those permissions to a person.
* A key depends on the member it was created for: see [The key depends on its member and its dental clinic](/docs/en/api-reference/authentication#the-key-depends-on-its-member-and-its-dental-clinic).

## Least-privilege recipes

Ask only for the scopes the integration uses. Each extra scope widens what a leaked key would expose.

| Integration | Scopes |
| - | - |
| Stock dashboard or BI of stock levels | `clinics:read`, `catalog:read`, `inventory:read` |
| Purchasing or ERP price sync | `catalog:read`, `catalog.cost:read` |
| Order follow-up in an ERP | `orders:read`, `fulfillment:read`, plus `clinics:read` to name locations and warehouses |
| Order follow-up with line costs | `orders:read`, `catalog.cost:read` |
| Management reporting and weekly CSV | `analytics:read` |
| Read-only AI assistant over MCP | `catalog:read`, `inventory:read`, `orders:read`, `analytics:read` |
| Uptime check of the integration | One scope you already use; `GET /v1/me` itself needs none |

<Tip>
  Use a separate key for each integration, even when two integrations need the same scopes. You can then revoke one without touching the other, and each has its own [rate limit](/docs/en/api-reference/rate-limits) budget.
</Tip>

## Related pages

* [Authentication](/docs/en/api-reference/authentication)
* [Roles and permissions](/docs/en/account/roles-and-permissions)
* [Catalog costs](/docs/en/catalog/costs)
* [Errors](/docs/en/api-reference/errors)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.