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

# Errors

> Status codes, shapes, and how to fix them.

Errors use standard HTTP status codes with a JSON body.

<ResponseField name="400 Bad Request" type="Validation error">
  The body failed validation — e.g. missing `customerIds`, empty `items`, or an
  unresolvable postcode.

  ```json theme={null}
  { "statusCode": 400, "message": ["general.customerIds should not be empty"], "error": "Bad Request" }
  ```
</ResponseField>

<ResponseField name="401 Unauthorized" type="Auth failed">
  The `x-api-key` header is missing or invalid. Ensure you're sending the **full**
  key, not the `dzk_live_…` prefix shown in the portal.

  ```json theme={null}
  { "message": "Invalid API key" }
  ```
</ResponseField>

<ResponseField name="403 Forbidden" type="Customer not in your org">
  One or more `customerIds` don't belong to your organisation. The whole request
  is rejected — no partial results.

  ```json theme={null}
  { "statusCode": 403, "message": "One or more customers do not belong to this organisation", "error": "Forbidden" }
  ```
</ResponseField>

<ResponseField name="404 Not Found" type="Unknown quote id">
  `GET /v1/org/quote/getQuote/{quoteId}` — no quote with that id.

  ```json theme={null}
  { "statusCode": 404, "message": "Quote not found", "error": "Not Found" }
  ```
</ResponseField>

<ResponseField name="429 Too Many Requests" type="Rate limited">
  You exceeded your per-minute limit. Honour the `Retry-After` header.

  ```json theme={null}
  { "message": "Rate limit exceeded", "limit": 60, "retryAfterSeconds": 23 }
  ```

  See [Rate limits](/guides/rate-limits).
</ResponseField>

<Note>
  An **empty** `quotes` array is **not** an error — it means nothing matched (e.g.
  filters excluded everything, or no rate applies to the lane). Check
  `noQuoteMessage`.
</Note>
