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

# Errors & Status Codes

> All error responses returned by the export endpoints

On success, every export endpoint returns the standard envelope `{ code, message, body, errors }` — `code` mirrors the HTTP status, `body` carries the payload, and `errors` is an empty array.

Error responses use a **different, smaller envelope**. They are returned as:

```json theme={null}
{
  "success": false,
  "message": "<human-readable reason>",
  "requestId": "<correlation id>"
}
```

Include the `requestId` whenever you contact support — it lets us locate the exact request in our logs.

<Note>
  The export endpoints do **not** perform dedicated input validation that returns `400`. A malformed `cursor` is not rejected with a `400`; it surfaces as a `500` (see [Invalid cursor](#invalid-cursor) below). Malformed `since`/`until` values are likewise not separately validated. Treat the cursor as opaque and send ISO-8601 timestamps to avoid these cases.
</Note>

## Status code overview

| Code  | When                                                                                | Retry?                                                     |
| ----- | ----------------------------------------------------------------------------------- | ---------------------------------------------------------- |
| `200` | Page returned (may be empty `rows`)                                                 | n/a                                                        |
| `401` | `Authorization` header missing or not `Bearer …`                                    | No — attach a token                                        |
| `401` | JWT invalid or expired                                                              | Yes, after re-auth                                         |
| `401` | Lender record not found or inactive in the main DB                                  | No — contact support                                       |
| `403` | `lenderPublicId` in the URL does not match `lenderId` in the JWT                    | No                                                         |
| `404` | Unknown section code (e.g. `/S9/D01`)                                               | No                                                         |
| `404` | Unknown dataset code (e.g. `/S1/D99`)                                               | No                                                         |
| `404` | Dataset listed in the catalog but `available: false` (reserved)                     | No — revisit later                                         |
| `500` | Lender `database_name` missing on the `LenderAccount` record                        | No — contact support                                       |
| `500` | Invalid / corrupted cursor                                                          | No — fix client                                            |
| `500` | Other internal server error                                                         | Yes, after backoff                                         |
| `504` | Gateway timeout — query exceeded the proxy limit (large high-volume `via` datasets) | Yes — narrow with a time window, lower `limit`, then retry |

## Error reference

<AccordionGroup>
  <Accordion title="401 — Missing Authorization header">
    **Trigger:** The `Authorization` header is absent or does not start with `Bearer `.

    ```json theme={null}
    {
      "success": false,
      "message": "Access denied. No token provided.",
      "requestId": "req_8f2a1c9e4b7d"
    }
    ```

    **Recovery:** Attach a valid Bearer token obtained from the [Lender Login](/api-reference/authentication/lender-login) endpoint.
  </Accordion>

  <Accordion title="401 — Invalid or expired JWT">
    **Trigger:** The token fails signature verification or has expired. Both cases are reported identically.

    ```json theme={null}
    {
      "success": false,
      "message": "Access denied. Invalid token.",
      "requestId": "req_3d5b8a0f1e62"
    }
    ```

    **Recovery:** Obtain a fresh token using the [Refresh Token](/api-reference/authentication/refresh-token) endpoint, or re-authenticate via [Lender Login](/api-reference/authentication/lender-login).
  </Accordion>

  <Accordion title="401 — Lender not found or inactive">
    **Trigger:** The token is well-formed and matches the URL, but the lender record cannot be found in the main database or is not active.

    ```json theme={null}
    {
      "success": false,
      "message": "Lender not found or inactive",
      "requestId": "req_a1c4e7d09b32"
    }
    ```

    **Recovery:** This usually indicates an account state issue rather than a client bug. Capture the `requestId` and contact support.
  </Accordion>

  <Accordion title="403 — Lender mismatch">
    **Trigger:** The `lenderPublicId` in the URL path does not equal the `lenderId` encoded in the JWT. This strict check (`requireLenderMatch`) runs on every export request.

    ```json theme={null}
    {
      "success": false,
      "message": "Lender ID mismatch",
      "requestId": "req_6b2f9d3a7c14"
    }
    ```

    **Recovery:** Re-authenticate with the correct lender and use the matching `lenderPublicId` in the path.
  </Accordion>

  <Accordion title="404 — Unknown section">
    **Trigger:** The `sectionCode` in the path is not one of `S1`–`S5` (e.g. `/exports/S9/D01`).

    ```json theme={null}
    {
      "success": false,
      "message": "Unknown section",
      "requestId": "req_c8e1a5f2b903"
    }
    ```

    **Recovery:** Call the [catalog endpoint](/api-reference/exports/endpoints/catalog) to discover valid section codes.
  </Accordion>

  <Accordion title="404 — Unknown dataset">
    **Trigger:** The section exists but the `datasetCode` does not exist within it (e.g. `/exports/S1/D99`).

    ```json theme={null}
    {
      "success": false,
      "message": "Unknown dataset",
      "requestId": "req_47d9b0c3e1a8"
    }
    ```

    **Recovery:** Call the [catalog endpoint](/api-reference/exports/endpoints/catalog) to discover valid dataset codes for each section.
  </Accordion>

  <Accordion title="404 — Dataset unavailable">
    **Trigger:** The dataset exists in the catalog but ships with `available: false` (reserved — currently `D04`, `D06`, `D10`, `D11`, `D13`, `D24`). The message names the dataset code.

    ```json theme={null}
    {
      "success": false,
      "message": "Dataset D04 is listed in the catalog but not available for export at this time.",
      "requestId": "req_92a4c7e0d3b1"
    }
    ```

    **Recovery:** The dataset has not been activated yet. Check the `available` flag in the [catalog](/api-reference/exports/endpoints/catalog) and contact support to schedule activation.
  </Accordion>

  <Accordion title="500 — Database not configured">
    **Trigger:** The lender record was found but has no `database_name`, so the tenant connection cannot be resolved.

    ```json theme={null}
    {
      "success": false,
      "message": "Lender database not configured",
      "requestId": "req_0e3b8d6a2f59"
    }
    ```

    **Recovery:** This is a server-side configuration issue. Capture the `requestId` and contact support.
  </Accordion>

  <Accordion title="500 — Invalid cursor" id="invalid-cursor">
    **Trigger:** The `cursor` query value is malformed or corrupted and cannot be decoded. Because cursor decoding is not surfaced as a validation error, it is returned as a generic internal error rather than a `400`.

    ```json theme={null}
    {
      "success": false,
      "message": "Internal server error",
      "requestId": "req_5a9c2e7b4d80"
    }
    ```

    **Recovery:** Never modify a cursor. Drop the bad cursor and restart from the last known-good `nextCursor`, or from the beginning of the dataset.
  </Accordion>

  <Accordion title="500 — Generic internal error">
    **Trigger:** Any other unexpected server-side failure.

    ```json theme={null}
    {
      "success": false,
      "message": "Internal server error",
      "requestId": "req_e1b7d4a9c062"
    }
    ```

    **Recovery:** Retry after a short backoff. If it persists, capture the request URL, the response body, and the time, then contact support.
  </Accordion>

  <Accordion title="504 — Gateway timeout">
    **Trigger:** The query took longer than the API gateway's timeout to return. This happens on the **highest-volume `via` (TIER 2) datasets** — most notably [`D23` Manual Communication Logs](/api-reference/exports/datasets/d23-manual-communication-logs) (tens of millions of rows) — when a page is requested **without a time window**, so the scan/sort spans the entire collection.

    Because the timeout is raised by the gateway (not the application), the response is **not** the standard JSON error envelope — it's a plain gateway `504` with no `requestId`.

    **Recovery:**

    * Always bound large `via` pulls with a `since` (and optionally `until`) window — pull in slices (e.g. month-by-month) rather than one unbounded scan.
    * Lower the `limit` (e.g. `200`–`500`) so each page does less work.
    * Retry the same windowed request after a short backoff.
    * `?includeTotal=true` on a `via` dataset also requires a time window (it returns `totalNote: "window_required"` otherwise); add `since`/`until` before requesting a total.

    If a **windowed**, small-`limit` request still times out, capture the full request URL and time, then contact support.
  </Accordion>
</AccordionGroup>

## Common debugging hints

* **Unexpected `401`?** Your token most likely expired. Refresh it via `/admin/auth/{lender}/refresh-token` and retry.
* **`403`?** The JWT was issued for a different lender than the one in the URL path. Re-authenticate with the correct lender subdomain.
* **`404` on a dataset that appears in the catalog?** Check its `available` flag. If `false`, the dataset has not been activated for your tenant yet — contact support to schedule it.
* **Unexpected `500`?** Capture the request URL, the response body (including `requestId`), and the time, then contact support.
* **`504` on a large dataset (e.g. `D23`)?** The query is scanning too much. Add a `since`/`until` window and pull in smaller time slices, and consider lowering `limit`. See the [504 — Gateway timeout](#error-reference) guidance above.

***

<Snippet file="snippets/support-info.mdx" />
