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

# Errors

> Every error is an RFC 9457 problem object with a stable code. Every code, what it means and how to fix it.

Errors answer with `Content-Type: application/problem+json` and the same shape everywhere. Over MCP, the same object comes back as a tool result with `isError: true`.

```json theme={null}
{
  "type": "https://api.brelio.app/problems/operation-forbidden",
  "title": "Forbidden",
  "status": 403,
  "code": "OPERATION_FORBIDDEN",
  "detail": "The credential does not grant patients.administrative.read.",
  "request_id": "4cbc47b2-a8f9-40e4-b0b9-d8d16c099888",
  "params": { "permission": "patients.administrative.read" },
  "hint": "Give the credential the patients.administrative.read permission, or call with one that has it."
}
```

| Field | Meaning |
| - | - |
| `code` | Stable identifier. **Branch on this**, never on `detail` or `title`. |
| `status` | The HTTP status, repeated. |
| `detail` | What happened, in English, for logs and developers. It can change. |
| `hint` | What to do about it, when there is something to do. |
| `params` | Machine-readable details: the missing permission, the invalid fields, the id. Never a payload. Always present. |
| `request_id` | Also in the `x-request-id` header. Quote it when you ask Brelio for help. |
| `retryAfterSeconds` | On `429` and `503`: seconds to wait. Also in `Retry-After`. |

Brelio's web app shows these codes in Spanish to the clinic, so the same error reads the same everywhere.

## Invalid input

`422 OPERATION_INPUT_INVALID` lists each problem by path and code, never echoing the values (they may be patient data):

```json theme={null}
{
  "status": 422,
  "code": "OPERATION_INPUT_INVALID",
  "detail": "The input does not match the operation.",
  "params": {
    "issues": [
      { "path": "patientId", "code": "invalid_format" },
      { "path": "start", "code": "invalid_type" }
    ]
  }
}
```

## Retry or not

| Status | Retry? |
| - | - |
| `400`, `401`, `402`, `403`, `404`, `422` | No. Fix the request, the credential or the clinic's settings first. |
| `409` | Not as is. Read the record again (version conflicts), wait (idempotency in progress) or change the request. |
| `429`, `503` | Yes, after `Retry-After` seconds, with the same `Idempotency-Key`. |
| `500` | Yes, with backoff and the same `Idempotency-Key`. |

## Every code

These are the codes the platform and its operations raise today. An operation can also pass through a code from Brelio's own rules (for example a plan limit), always in the same shape, with a `detail` that explains it: treat an unknown code by its `status`.

### Authentication and access

| Code | Status | Meaning | Fix |
| - | - | - | - |
| `PLATFORM_UNAUTHENTICATED` | 401 | No bearer credential, or it is invalid, revoked or expired. | Send `Authorization: Bearer <credential>` with a valid key or token. |
| `PLATFORM_AUTH_UNAVAILABLE` | 503 | The credential could not be verified right now. | Retry after `Retry-After` (30 s). |
| `PLATFORM_ORGANIZATION_NOT_LINKED` | 403 | The credential belongs to an organization or person without access to Brelio. | Use a credential created in a Brelio clinic you belong to. |
| `PLATFORM_ORGANIZATION_AMBIGUOUS` | 403 | MCP only: you belong to several clinics and the connection names none. | Reconnect and choose the clinic. |
| `PLATFORM_PLAN_REQUIRED` | 402 | The clinic's plan does not include API access. | An owner adds it in **Configuración › Suscripción**. |
| `PLATFORM_PLAN_UNAVAILABLE` | 503 | API access could not be confirmed right now. | Retry after 30 s. |
| `OPERATION_FORBIDDEN` | 403 | The credential, or the person behind it, lacks the permission in `params.permission`. | Use a credential with that permission. See [permissions](https://docs.brelio.com/en/concepts/permissions.md). |
| `CENTER_CONTEXT_FORBIDDEN` | 403 | The `centerId` sent is not one of the caller's centers. | Send a center you can see, or omit it. |
| `DATA_AREA_OFF` | 403 | The clinic does not let integrations use the operation's data area (`params.area`). | An owner turns the area on in Brelio. See [data areas](https://docs.brelio.com/en/concepts/data-areas.md). |
| `DATA_AREA_UNKNOWN` | 403 | The operation has no data area, so no integration may run it. | Report it to Brelio. |
| `PATIENT_DATA_CONSENT_REQUIRED` | 403 | Patient data was not accepted for this credential. Over MCP, `params.consent_url` links to the acceptance page. | The person (or the owner, for organization keys and apps) accepts it in Brelio, then retry. |
| `PLATFORM_REVEAL_FORBIDDEN` | 403 | The operation returns a one-time secret, which MCP cannot hand to a person. | Call it over REST, or create the credential in Brelio. |

### Requests

| Code | Status | Meaning | Fix |
| - | - | - | - |
| `PLATFORM_ROUTE_NOT_FOUND` | 404 | No operation at this method and path. | Check `GET /v1/openapi.json`. |
| `MALFORMED_JSON_BODY` | 400 | The body is not a JSON object. | Send a JSON object with `Content-Type: application/json`. |
| `OPERATION_INPUT_INVALID` | 422 | The input does not match the operation; see `params.issues`. | Fix the listed fields. |
| `IDEMPOTENCY_KEY_REQUIRED` | 400 | A write without a valid `Idempotency-Key`. | Send a UUID. See [idempotency](https://docs.brelio.com/en/concepts/idempotency.md). |
| `OPERATION_IDEMPOTENCY_CONFLICT` | 409 | The key was used before with a different request. | Use a new key for a new change. |
| `OPERATION_IDEMPOTENCY_IN_PROGRESS` | 409 | The first request with this key is still running. | Wait and retry with the same key. |
| `RATE_LIMITED` | 429 | A [rate limit](https://docs.brelio.com/en/concepts/rate-limits.md) was reached. | Wait `Retry-After` seconds. |
| `PLATFORM_LIMITS_UNAVAILABLE` | 503 | The limiter did not answer; patient-data operations fail closed. | Retry after 5 s. |
| `PLATFORM_INTERNAL` | 500 | MCP only: an unexpected failure. Nothing about it is sent. | Retry later; quote `request_id`. |

A REST call that fails unexpectedly answers `500` with the `x-request-id` header.

### Versions

| Code | Status | Meaning | Fix |
| - | - | - | - |
| `VERSION_CONFLICT` | 409 | The patient or appointment changed since you read it. | Read it again and retry with its new `version`. See [concurrency](https://docs.brelio.com/en/concepts/concurrency.md). |

### Appointments and free slots

| Code | Status | Meaning | Fix |
| - | - | - | - |
| `APPOINTMENT_NOT_FOUND` | 404 | No appointment with that id that you can see. | Take ids from `GET /v1/agenda` or the create response. |
| `APPOINTMENT_REFERENCE_NOT_FOUND` | 404 | The patient, professional or service (`params.what`) does not exist or cannot be booked by you. Inactive patients cannot be booked. | Check the id with the matching list. |
| `APPOINTMENT_CENTER_REQUIRED` | 422 | The clinic has several centers and the appointment needs one. | Send `centerId`. |
| `APPOINTMENT_OVERLAP_DETECTED` | 409 | The time is no longer free for the professional. | Search free slots again and pick another. |
| `APPOINTMENT_PROFESSIONAL_UNAVAILABLE` | 422 | The professional does not work at that time. | Use a slot from `GET /v1/availability`. |
| `APPOINTMENT_RECURRING_UNSUPPORTED` | 422 | Recurring appointments cannot be changed through the API yet. | Change it in Brelio. |
| `APPOINTMENT_CANCEL_IN_BRELIO` | 409 | The appointment already has a session (checked in or later), so it is cancelled in Brelio. | Cancel it in Brelio. |
| `APPOINTMENT_RESCHEDULE_NOT_ALLOWED` | 409 | The appointment's state does not allow moving it. | Read it; only scheduled appointments move. |
| `APPOINTMENT_INVALID_STATE_TRANSITION` | 409 | The change is not allowed from the appointment's current status. | Read it and check its `status`. |
| `AVAILABILITY_CENTER_REQUIRED` | 422 | The clinic has several centers. | Send `centerId`. |
| `AVAILABILITY_REFERENCE_NOT_FOUND` | 404 | The patient, professional or service (`params.what`) is not one you can book here. | Check the id. |

### Patients

| Code | Status | Meaning | Fix |
| - | - | - | - |
| `PATIENT_NOT_FOUND` | 404 | No patient with that id that you can see. Archived patients are not found. | Search with `GET /v1/patients`. |
| `PATIENT_ACTION_NOT_ALLOWED` | 409 | The patient's state does not allow the change (`params.action`: `edit` or `archive`). | Read the patient; change it in Brelio if needed. |

### Credentials

| Code | Status | Meaning | Fix |
| - | - | - | - |
| `CREDENTIAL_NOT_FOUND` | 404 | No key, app or connection with that id in the clinic. | List them first. |
| `CREDENTIAL_SESSION_REQUIRED` | 403 | Creating credentials or revoking another one needs a person in Brelio. | Do it in Brelio; a credential may revoke only itself. |
| `CREDENTIAL_PERMISSION_NOT_HELD` | 403 | You tried to give permissions you do not hold (`params.permissions`). | Ask someone who holds them. |
| `PLATFORM_CREDENTIALS_UNAVAILABLE` | 503 | The identity provider did not answer. | Retry later. |
| `PLATFORM_CREDENTIALS_REFUSED` | 422 | The identity provider refused the request. | Check the names and permissions sent. |

### Data policy

| Code | Status | Meaning | Fix |
| - | - | - | - |
| `DATA_POLICY_VERSION_CONFLICT` | 409 | The area changed since you read it. | Read `GET /v1/platform-policy` and resend with its `version`. |
| `DATA_POLICY_UNCHANGED` | 409 | The area already has that state. | Nothing to do. |
| `DATA_POLICY_NEEDS_PERSON` | 403 | The change must be recorded as decided by a person. | Use a personal credential or Brelio. |
| `DATA_AREA_ENABLE_IN_BRELIO` | 403 | Integrations can only turn areas off. | An owner turns it on in Brelio. |
| `PATIENT_DATA_ACCEPT_IN_BRELIO` | 403 | Patient data is accepted by a person in Brelio. | Accept it in Brelio. |
| `PATIENT_DATA_CREDENTIAL_NOT_YOURS` | 403 | You can decide only for your own keys and connections. | Ask an owner. |
| `PATIENT_DATA_NOTHING_TO_REVOKE` | 409 | There is no acceptance to revoke. | Nothing to do. |
| `PATIENT_DATA_TERMS_NOT_ACCEPTED` | 422 | Turning a patient area on needs `acceptTerms: true` and the `termsVersion` read. | Send both. |
| `PATIENT_DATA_TERMS_OUTDATED` | 409 | The terms changed since they were shown. | Show the current terms and send their version. |
| `PATIENT_DATA_TERMS_PENDING` | 409 | The reviewed terms are not published yet. | Wait for them. |

### Webhooks

| Code | Status | Meaning | Fix |
| - | - | - | - |
| `WEBHOOK_NOT_FOUND` | 404 | No webhook with that id. | Check `GET /v1/webhooks`. |
| `WEBHOOK_VERSION_CONFLICT` | 409 | The webhook changed since you read it. | Read it again and retry with its `version`. |
| `WEBHOOK_EVENT_TYPE_UNKNOWN` | 422 | An event type in `eventTypes` does not exist. | Choose from `GET /v1/webhook-event-types`. |
| `WEBHOOK_DELIVERY_PENDING` | 409 | That delivery is already queued. | Wait; `GET /v1/webhooks/{id}` shows when it runs. |
| `WEBHOOK_TEST_RATE_LIMITED` | 429 | More than 5 tests in a minute for this webhook. | Wait a minute. |
| `WEBHOOK_NOTHING_TO_DO` | 404 | The webhook is gone or already disabled. | Nothing to do. |


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