# Error responses

> One shape, stable codes, and what to do about each.

Source: https://docs.dashfordevs.com/v1/error-handling/errors · Topic: Errors and rate limits · Updated: 2026-11-07

Errors are JSON with a machine-readable `error` and a human `message`:

```json
{ "error": "origin_not_allowed", "message": "Origin 'https://other.site' is not in the allowed origins list" }
```

Branch on `error` (and the status), never on `message`: messages may be reworded, codes never are within v1.

## Gateway errors

| Status | `error` | Meaning | What to do |
| --- | --- | --- | --- |
| 401 | `api_key_required` | No `X-API-Key` header. | Send the key. |
| 401 | `invalid_api_key_format` | The value is not a key. | Check for whitespace or a truncated value. |
| 401 | `invalid_api_key` | No such key. | It was deleted or regenerated. Use the current one. |
| 403 | `api_key_inactive` | The key is switched off. | Turn it on, or use another. |
| 403 | `organization_shutdown` | The organization is shut down. Includes `shutdown_at`. | Contact support. |
| 403 | `origin_not_allowed` | Live public key from an origin not on its list. | Add the host under Allowed origins (bare host, no https://). |
| 403 | `secret_key_required` | An admin route called with a public key. | Call it from your server with the secret key. |
| 405 | (empty body) | Wrong method for this path. | See the `Allow` header. |
| 429 | `Rate limit exceeded` | Too many requests this minute. | Wait `retry_after` seconds. |
| 501 | `not_implemented` | The route exists in v1 but is not built on the new platform yet. Includes `"available": false`. | Do not retry. |
| 503 | `not_available_yet` | The route is held back for this organization (for example, customer data for a HIPAA organization whose HIPAA path is not complete). Includes `"available": false` and a `reason`. | Do not retry. |

Service errors (a product not found, a validation problem) use the same shape, for example `404 {"error": "not_found", "message": "Product not found"}` or `400 {"error": "validation_error", "message": "name is required"}`.

## In the SDK

Every failure is a `DashApiError` with `status`, `code` (the `error` value, or `network_error`, `timeout`, `aborted`, `invalid_response`), `fields` (for validation errors), `requestId` and `retryable`. GET requests retry automatically on network errors, timeouts, 408, 425, 429, 502, 503 and 504, honoring `Retry-After`. Writes are never retried automatically.
