# Errors

> border.bot API error format, every error code with its HTTP status, and which errors to retry.

Source: https://border.bot/docs/errors
Last updated: 2026-10-09

> Documentation index: https://border.bot/llms.txt. Every page is Markdown at its URL + `.md`.


Errors return JSON with a stable, machine-readable `code`, a message written for people, and sometimes `details`:

```json
{
  "error": {
    "code": "insufficient_credits",
    "message": "This workspace needs 5 credits and has 2.",
    "details": { "required": 5, "balance": 2 }
  }
}
```

Every response carries an `X-Request-Id`. Quote it when you contact support, or find the request with `GET /v1/requests?requestId=…`.

## Codes

| Code | HTTP | Meaning |
| --- | --- | --- |
| `invalid_input` | 400 | The request failed validation. The message names the field to fix. |
| `unauthorized` | 401 | The API key is missing, malformed or revoked. |
| `insufficient_credits` | 402 | The workspace balance is too low for this action. Top up in the dashboard. |
| `forbidden` | 403 | The key is valid but not allowed to perform this action (a key without the scope the endpoint needs: details.reason is missing_scope). |
| `not_found` | 404 | The resource or path doesn’t exist. |
| `conflict` | 409 | A request with the same idempotency key is still running, or the change clashes with existing data. Wait and retry. |
| `org_suspended` | 403 | The workspace is suspended. Contact support. |
| `payload_too_large` | 413 | The request body is over 10 MB. Link to a photo instead of sending it inline, or split a bulk run. |
| `version_retired` | 410 | The API version in the path has passed its sunset date. Move to the version the message names. |
| `action_disabled` | 403 | This action is temporarily switched off. Try again later. |
| `unsupported_country` | 422 | The destination isn’t covered for this action yet. The message says what is supported. |
| `rate_limited` | 429 | Too many requests in a short period. Back off and retry. |
| `upstream_error` | 502 | The engine couldn’t complete the request. Credits were refunded; retry. |
| `upstream_timeout` | 504 | The engine took too long. Credits were refunded; retry. |
| `internal` | 500 | Something went wrong on our side. Credits were refunded. |

## What to retry

- `429`, `502` and `504`: retry with backoff and the same `Idempotency-Key`. Credits for a failed call are already refunded.
- `409 conflict` on a repeated idempotency key: the first request is still running, so wait and retry.
- Everything else: fix the request first. `invalid_input` names the field in its message and lists up to ten problems in `details.issues`.
