> ## 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.

# Errors

> The problem document every failed request returns, every error code a /v1 or /mcp caller can receive, and what to do about each one.

Every failed `/v1` request returns an [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457) problem document with the content type `application/problem+json`. Every problem carries a stable `code`: branch on it, never on the human text.

## The problem document

```json theme={null}
{
  "type": "https://docs.muveya.com/errors/orders.not_found",
  "title": "Order not found",
  "status": 404,
  "detail": "The requested order does not exist in this workspace.",
  "instance": "/v1/orders/66d0a1f0c0ffee0000000599",
  "code": "orders.not_found",
  "requestId": "3c9f1e7a-5b2d-4a8e-9f60-7d1c2b3a4e5f"
}
```

The document always has exactly these seven fields, and no others.

| Field | What it is |
| - | - |
| `type` | An identifier of the problem type, built as `https://docs.muveya.com/errors/` followed by the `code`. It is an identifier, not a page you need to open. |
| `title` | A short summary of the problem type, in the language of your `Accept-Language` header (`en`, `es` or `pt`; English otherwise). |
| `status` | The HTTP status code, repeated in the body. |
| `detail` | A human explanation, in the same language as `title`. **Not a contract**: the wording can change. |
| `instance` | The path of the request, without the query string. |
| `code` | The stable identifier of the problem. English, the same in every language. **This is what your code branches on.** |
| `requestId` | The id of the request. It matches the `x-request-id` response header. Include it when you write to [team@muveya.com](mailto:team@muveya.com). |

<Tip>
  Handle errors in two levels: first the `code` values your integration knows, then the HTTP `status` as a fallback for any code it does not know yet. New codes can appear inside `/v1` (see [Versioning](/docs/en/api-reference/versioning)).
</Tip>

Unexpected failures always become a `500` with the code `common.internal_error`. Internal details, stack traces and database messages never appear in a response.

## Codes a `/v1` caller can receive

| `code` | Status | Returned by | Meaning | What to do |
| - | - | - | - | - |
| `common.invalid_request` | 400 | Paginated lists, analytics, exports | The request cannot be processed. See [Invalid request causes](#invalid-request-causes). | Fix the parameter or body. Retrying the same request fails again. |
| `api_keys.invalid` | 401 | Every operation | The key is missing, malformed, unknown or revoked, its member is no longer active, or its dental clinic is suspended. One answer for all causes. | Check the `Authorization: Bearer` header, then check the key status with the member who requested it. See [Authentication](/docs/en/api-reference/authentication#authentication-failures). |
| `api_keys.scope_missing` | 403 | Every operation except `GET /v1/me` | The key is valid but lacks a scope the operation requires. | Compare `GET /v1/me` with [Scopes](/docs/en/api-reference/scopes) and request a key with the right scopes. |
| `common.forbidden` | 403 | Any operation, as a safety check | The operation is not allowed for this caller. On `/v1` it backs up the scope check, and a key that holds the scope of the operation does not reach it. | Check the key scopes. If they are right, write to [team@muveya.com](mailto:team@muveya.com) with the `requestId`. |
| `catalog.item_not_found` | 404 | `GET /v1/catalog/items/{itemId}` | No catalog item with that id in this dental clinic. | Check the id. Items of another dental clinic are never visible. |
| `inventory.box_not_found` | 404 | `GET /v1/inventory/boxes/{boxId}` and its `/balance` and `/movements` | No box with that id in this dental clinic. | Check the id (a box id, not the printed box code). |
| `orders.not_found` | 404 | `GET /v1/orders/{orderId}` | No order with that id in this dental clinic. | Check the id (an order id, not the order number). |
| `common.not_found` | 404 | `GET /v1/fulfillments/{orderId}`, `GET /v1/analytics/exports/{exportId}`, any path that does not exist | The resource does not exist in this dental clinic. For a fulfillment, the order may exist but has no delivery record yet (for example, it is still waiting for approval). For an export, the id is unknown or the export is older than 7 days. | Check the path and id. For a recent order, try again once it has been approved. For an old export, request a new one. |
| `common.too_many_requests` | 429 | Every operation | The key used its request budget for the current window. | Wait the seconds in `Retry-After`, then retry. See [Rate limits](/docs/en/api-reference/rate-limits). |
| `common.internal_error` | 500 | Any operation | An unexpected failure on the muveya side. | Retry a read later with a growing delay. If it persists, write to [team@muveya.com](mailto:team@muveya.com) with the `requestId`. |

### Invalid request causes

| Operation | What triggers `common.invalid_request` |
| - | - |
| `GET /v1/orders`, `GET /v1/fulfillments`, `GET /v1/inventory/balances` | `limit` that is not a whole number from 1 to 200; a `cursor` that cannot be read; a `status` that is not one of the documented values |
| `GET /v1/analytics/metrics/{metric}` | A metric name that is not in the documented list; a `from` or `to` that is not a date; `from` not earlier than `to` |
| `GET /v1/analytics/consumption-trend` | A `from` or `to` that is not a date; `from` not earlier than `to`; a window longer than 366 days; a `granularity` other than `day` or `week` |
| `GET /v1/analytics/briefing` | A `period` other than `daily` or `weekly` |
| `POST /v1/analytics/exports` | A body `period` other than `daily` or `weekly`; a body that is not valid JSON |

### Same answer, different reasons

Several answers deliberately cover more than one situation, so that the API never reveals what exists in another dental clinic:

* A record of another dental clinic and a record that does not exist return the same `404`.
* Every problem with a key returns the same `401`.

Do not build logic that tries to tell these cases apart.

## Errors on `/mcp`

The MCP endpoint `https://api.muveya.com/mcp` fails in three different ways.

**1. Before the MCP session starts.** A missing, expired or invalid OAuth access token returns `401` with a `WWW-Authenticate` link to protected resource metadata. An API key is not accepted.

**2. Inside a tool call.** A tool that fails still returns a normal JSON-RPC response. Its result has `isError: true` and its text is a problem document:

```json theme={null}
{
  "type": "https://docs.muveya.com/errors/common.forbidden",
  "title": "Forbidden",
  "status": 403,
  "detail": "The operation is not allowed.",
  "instance": "/mcp#approvals.list_pending",
  "code": "common.forbidden",
  "requestId": "0f4e2a6c-8d1b-4c3e-a5f7-9b2d4e6f8a0c"
}
```

| `code` | Status | When |
| - | - | - |
| `common.forbidden` | 403 | The key lacks the scope the tool needs, or the tool needs a member permission that a key never has (`approvals.list_pending`, `management.pending_decisions`, `fulfillment.get_pick_list`). |
| `orders.not_found` | 404 | `orders.get` with an id that does not exist in this dental clinic. |
| `common.invalid_request` | 400 | Arguments the server refuses after the schema check, such as a time window that `analytics.consumption` cannot use. |
| `common.internal_error` | 500 | An unexpected failure. |

* In a tool result, `instance` is `/mcp#` followed by the tool name.
* The `title` and `detail` of tool results are in English.
* The `requestId` identifies that MCP request. Keep it from the tool result when you report a problem.
* Arguments that do not match the tool's input schema, and unknown tool names, also come back as a result with `isError: true`, but with a plain text message instead of a problem document.

**3. Protocol errors.** These are JSON-RPC error objects, not problem documents:

| HTTP status | JSON-RPC `code` | When |
| - | - | - |
| `405` | `-32000` | A `GET` or `DELETE` request to `/mcp`. Only `POST` is accepted. |
| `406` | `-32000` | The `Accept` header does not include both `application/json` and `text/event-stream`. |
| `500` | `-32603` | The MCP transport failed unexpectedly. |
| `200` | `-32600` | Reading the resource `muveya://tenant/approval-policy-summary`, which a key may not read. The error `data.code` is `common.forbidden`. |

See [Connect an MCP client](/docs/en/mcp/connect) for a correct request.

## Failures that are not HTTP errors

An export that fails after it was accepted does not return an error status. Its job moves to `"status": "failed"` with a machine-readable `error` reason. See [Exports](/docs/en/api-reference/exports#when-an-export-fails).

## Related pages

* [Authentication](/docs/en/api-reference/authentication)
* [Rate limits](/docs/en/api-reference/rate-limits)
* [Pagination](/docs/en/api-reference/pagination)
* [Troubleshooting](/docs/en/help/troubleshooting)


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