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

# Error Handling

> Understanding API error responses and how to handle them

The Max AI API uses standard HTTP status codes and returns structured JSON error responses. Every error includes a machine-readable `code`, a human-readable `message`, and a `trace_id` for debugging.

## Error Response Format

```json theme={null}
{
  "code": "not_found",
  "message": "Patient not found",
  "trace_id": "550e8400-e29b-41d4-a716-446655440000"
}
```

| Field      | Type   | Description                                                                  |
| ---------- | ------ | ---------------------------------------------------------------------------- |
| `code`     | string | Machine-readable error code (e.g., `unauthorized`, `forbidden`, `not_found`) |
| `message`  | string | Human-readable description of the error                                      |
| `trace_id` | string | Unique identifier for this request — include this when contacting support    |

## HTTP Status Codes

### Success

| Status   | Description                                         |
| -------- | --------------------------------------------------- |
| `200 OK` | Request succeeded. Response body contains the data. |

### Client Errors

| Status                  | Code                  | Description                                                                                                   |
| ----------------------- | --------------------- | ------------------------------------------------------------------------------------------------------------- |
| `400 Bad Request`       | `bad_request`         | The request is malformed or has invalid/missing parameters — see [400 details](#400--validation-errors) below |
| `401 Unauthorized`      | `unauthorized`        | Missing or invalid API key                                                                                    |
| `403 Forbidden`         | `forbidden`           | Valid API key but insufficient scope for this endpoint                                                        |
| `404 Not Found`         | `not_found`           | The requested resource doesn't exist or isn't accessible to your organization                                 |
| `429 Too Many Requests` | `rate_limit_exceeded` | You've exceeded the [rate limit](/guides/rate-limits). Check `Retry-After` or `X-RateLimit-Reset` headers.    |

### Server Errors

| Status                      | Code             | Description                                                             |
| --------------------------- | ---------------- | ----------------------------------------------------------------------- |
| `500 Internal Server Error` | `internal_error` | Something went wrong on our side. Retry the request or contact support. |

## Error Examples

### 400 — Validation Errors

The API returns `400 Bad Request` when a required parameter is missing or has an invalid format. The `message` field tells you exactly which parameter is wrong:

**Missing required parameter:**

```json theme={null}
{
  "code": "bad_request",
  "message": "'providerId' is required",
  "trace_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
```

**Invalid ID format:**

```json theme={null}
{
  "code": "bad_request",
  "message": "'id' must be a valid ID",
  "trace_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901"
}
```

<Note>
  In v3, resource IDs use a readable prefixed format (e.g., `pat_c56103bcd39c46d39f3138dd2b5e05f6`). The API accepts both prefixed IDs and raw UUIDs as path parameters. The `X-Organization-Id` header still requires a raw UUID.
</Note>

**Invalid header value:**

```json theme={null}
{
  "code": "bad_request",
  "message": "'X-Organization-Id' must be a valid UUID",
  "trace_id": "c3d4e5f6-a7b8-9012-cdef-234567890123"
}
```

Common causes:

* A required path or query parameter is missing from the request
* An ID parameter contains an invalid value (e.g., `not-a-uuid` instead of a prefixed ID like `pat_c56103bcd39c46d39f3138dd2b5e05f6` or a raw UUID like `550e8400-e29b-41d4-a716-446655440000`)
* The `X-Organization-Id` header is not a valid UUID

### 401 — Invalid API Key

The `message` field varies depending on the specific authentication failure (invalid key, revoked key, missing header, etc.).

```json theme={null}
{
  "code": "unauthorized",
  "message": "Invalid or expired API key",
  "trace_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
```

### 403 — Insufficient Scope

Returned when your API key is valid but lacks the required scope for the endpoint. The `message` tells you whether the key itself is missing the scope, or whether the scope is on the key but not granted by the organization's installation.

```json theme={null}
{
  "code": "forbidden",
  "message": "Insufficient scopes. Required one of: [read:patients]. The API key is missing the required scope. Key scopes: [read:providers].",
  "trace_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901"
}
```

### 404 — Resource Not Found

```bash theme={null}
curl -X GET "https://api.maxcare.ai/v3/patients/pat_d4f8e2a13b7c4e9fa6d21c5b8e3f7a90" \
  -H "Authorization: Bearer max_prd_ak_SBA...01S" \
  -H "X-Organization-Id: 7e2c8cfe-b7a9-4deb-986d-e7012589e72b"
```

```json theme={null}
{
  "code": "not_found",
  "message": "Patient not found",
  "trace_id": "c3d4e5f6-a7b8-9012-cdef-123456789012"
}
```

### 429 — Rate Limit Exceeded

```json theme={null}
{
  "code": "rate_limit_exceeded",
  "message": "Rate limit exceeded. Maximum 1000 requests per 60 seconds.",
  "trace_id": "d4e5f6a7-b8c9-0123-defg-234567890123"
}
```

The response includes headers to help you retry at the right time:

| Header                  | Example      | Description                           |
| ----------------------- | ------------ | ------------------------------------- |
| `X-RateLimit-Limit`     | `1000`       | Max requests per window               |
| `X-RateLimit-Remaining` | `0`          | No requests left                      |
| `X-RateLimit-Reset`     | `1774293714` | Unix timestamp when the window resets |
| `Retry-After`           | `60`         | Seconds to wait before retrying       |

See [Rate Limits](/guides/rate-limits) for retry strategies and best practices.

## Handling Errors in Code

<CodeGroup>
  ```javascript Node.js theme={null}
  async function getPatient(apiKey, orgId, patientId) {
    const response = await fetch(
      `https://api.maxcare.ai/v3/patients/${patientId}`,
      {
        headers: {
          "Authorization": `Bearer ${apiKey}`,
          "X-Organization-Id": orgId,
        },
      }
    );

    const json = await response.json();

    if (!response.ok) {
      switch (json.code) {
        case "unauthorized":
          throw new Error("API key is invalid. Check your credentials.");
        case "forbidden":
          throw new Error(`Missing scope: ${json.message}`);
        case "not_found":
          return null; // Patient doesn't exist
        case "rate_limit_exceeded":
          const resetAt = response.headers.get("X-RateLimit-Reset");
          const waitMs = resetAt ? parseInt(resetAt) * 1000 - Date.now() : 60_000;
          await new Promise((r) => setTimeout(r, Math.max(waitMs, 1000)));
          return getPatient(apiKey, orgId, patientId); // Retry once
        default:
          throw new Error(`API error (${json.code}): ${json.message}`);
      }
    }

    return json.data;
  }
  ```

  ```python Python theme={null}
  import time
  import requests

  def get_patient(api_key: str, org_id: str, patient_id: str):
      response = requests.get(
          f"https://api.maxcare.ai/v3/patients/{patient_id}",
          headers={
              "Authorization": f"Bearer {api_key}",
              "X-Organization-Id": org_id,
          },
      )

      data = response.json()

      if response.status_code == 401:
          raise Exception("API key is invalid. Check your credentials.")
      elif response.status_code == 403:
          raise Exception(f"Missing scope: {data['message']}")
      elif response.status_code == 404:
          return None  # Patient doesn't exist
      elif response.status_code == 429:
          reset_at = int(response.headers.get("X-RateLimit-Reset", 0))
          wait = max(reset_at - int(time.time()), 1)
          time.sleep(wait)
          return get_patient(api_key, org_id, patient_id)  # Retry once
      elif not response.ok:
          raise Exception(f"API error ({data['code']}): {data['message']}")

      return data["data"]
  ```
</CodeGroup>

## Debugging

If you encounter an unexpected error:

1. Check the `trace_id` in the error response
2. Verify your API key and Organization ID are correct
3. Confirm your app has the required [scopes](/guides/scopes) for the endpoint
4. Contact the Max AI team with the `trace_id` for further investigation
