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

# Errors

> One error shape, meaningful status codes, and how to handle them

Every error is JSON with the same three parts: a human-readable `message`, a stable machine-readable `code`, and — for input problems — `errors` keyed by attribute:

```json theme={null}
{
  "message": "Validation failed.",
  "code": "validation_failed",
  "errors": {
    "start": ["The start field must match the format Y-m-d H:i:s."],
    "patient_id": ["Patient not found or deleted."]
  }
}
```

```json theme={null}
{ "message": "This group appointment is full.", "code": "group_full" }
```

| Status | When                                                                                                                                                                               | What to do                                                                                                         |
| ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| `401`  | No key, or an invalid, revoked or wrong-account key                                                                                                                                | Check the `Authorization: Bearer …` header; create a new key under **Developers → API Keys**                       |
| `403`  | The API key is read-only and the request writes; or a connector's team member is not permitted (connector disabled for the role, or the role lacks the permission for this action) | Use a read & write key, or ask an account owner to adjust the role under **Settings → Security → Roles**           |
| `404`  | No such resource, or no record with that id on this account                                                                                                                        | Nothing to retry — the record is gone or never existed here                                                        |
| `405`  | The resource does not support that operation (for example creating a `line_items` row)                                                                                             | See `write_operations` in `GET /schema/{resource}`                                                                 |
| `409`  | A business rule refused the change — appointment already processed, group full, invoice already paid; or an `Idempotency-Key` still in flight                                      | Show `message` to the user; the request will not succeed until the state changes (for idempotency, wait and retry) |
| `422`  | Invalid input — unknown attribute, wrong type or format, missing required field, or a referenced record that does not exist                                                        | Read `errors`; fix and resend                                                                                      |
| `429`  | Rate limit exceeded (600 requests per minute per integration)                                                                                                                      | Wait for the next minute and retry with backoff                                                                    |
| `500`  | Something went wrong on our side                                                                                                                                                   | Retry with backoff; contact support quoting the `X-Request-Id`                                                     |

## Error codes

Branch on the **status code**, the **`code`**, and the **attribute keys** in `errors`. `message` text is written for humans and may change; do not parse it. Codes are stable within the current version — new ones may be added, existing ones are not renamed.

| Code                                                                                                                           | Status    | Meaning                                                                                                                                                                                       |
| ------------------------------------------------------------------------------------------------------------------------------ | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `unauthenticated`                                                                                                              | 401       | No, invalid, expired or revoked key                                                                                                                                                           |
| `user_inactive`                                                                                                                | 401       | A connector's team member has been deactivated                                                                                                                                                |
| `key_read_only`                                                                                                                | 403       | The API key is read-only and the request writes                                                                                                                                               |
| `connector_not_permitted`                                                                                                      | 403       | The connector's team member no longer has **Connect AI apps** on their role                                                                                                                   |
| `permission_denied`                                                                                                            | 403       | The connector's team member's PracticeHub role does not allow this read, write or delete (the message names the permission), or the record is outside their own-patients / own-calendar scope |
| `not_found`                                                                                                                    | 404       | No such resource or record on this account                                                                                                                                                    |
| `unsupported_operation`                                                                                                        | 405       | The resource does not support that operation (`GET /schema/{resource}` → `write_operations`)                                                                                                  |
| `method_not_allowed`                                                                                                           | 405       | HTTP method not valid for that URL                                                                                                                                                            |
| `validation_failed`                                                                                                            | 422       | Input failed validation — see `errors`                                                                                                                                                        |
| `invalid_input`                                                                                                                | 422       | A domain check on the input failed — `errors` names the attribute                                                                                                                             |
| `patient_not_found`, `location_not_found`, `practitioner_not_found`, `appointment_type_not_found`, `referral_source_not_found` | 422       | The referenced record does not exist / is deleted on this account                                                                                                                             |
| `resource_unavailable`                                                                                                         | 422       | Resource missing, inactive, or not at that location                                                                                                                                           |
| `not_online_bookable`                                                                                                          | 422       | `GET /availability?visibility=online`: the location, appointment type or practitioner is not enabled for online booking (use `visibility=all` for the staff view)                             |
| `payment_method_unavailable`                                                                                                   | 422       | Payment method missing or inactive                                                                                                                                                            |
| `card_payment_not_allowed`                                                                                                     | 422       | Card methods can't be recorded through the API (no card is charged)                                                                                                                           |
| `referral_source_incomplete`                                                                                                   | 422       | `referral_source_id` and `referral_source_type` must be sent together                                                                                                                         |
| `file_type_not_allowed`, `patient_log_mismatch`                                                                                | 422       | File upload rules                                                                                                                                                                             |
| `idempotency_key_invalid`, `idempotency_key_reused`                                                                            | 422       | `Idempotency-Key` too long / reused with a different body                                                                                                                                     |
| `idempotency_key_in_flight`                                                                                                    | 409       | The same `Idempotency-Key` is still being processed — retry shortly                                                                                                                           |
| `appointment_rule`                                                                                                             | 409       | The scheduling service refused (already processed, cannot un-arrive, …)                                                                                                                       |
| `slot_unavailable`                                                                                                             | 409       | `POST /appointments`: the practitioner's diary is not free at that time — re-check [availability](/guides/booking) (or send `allow_clash: true` to overbook deliberately)                     |
| `group_full`                                                                                                                   | 409       | The group appointment has no places left                                                                                                                                                      |
| `billing_rule`                                                                                                                 | 409 / 422 | The billing service refused (over-allocation, already voided, …)                                                                                                                              |
| `file_store_failed`, `file_delete_failed`, `allocation_remove_failed`                                                          | 409       | The operation could not complete                                                                                                                                                              |
| `conflict`                                                                                                                     | 409       | Any other state conflict                                                                                                                                                                      |
| `rate_limited`                                                                                                                 | 429       | Rate limit exceeded — see `Retry-After`                                                                                                                                                       |

## Diagnosing

Every response includes an `X-Request-Id`. The same id appears against the request on the account's **Developers → API Logs** page — status, latency and the caller — and support can trace it from there.

## Rate limits

`X-RateLimit-Limit` and `X-RateLimit-Remaining` are on every response. Limits are per integration (per API key) — a burst from one integration does not affect another on the same account.
