# Errors

One error shape at every status, and the full code list from the server's own catalog.

Source: https://docs.leadarc.io/errors.html

## One shape, every time

```json
{
  "error": {
    "code": "insufficient_scope",
    "message": "This endpoint needs the leads:write scope.",
    "required_scope": "leads:write"
  }
}
```

Branch on `code`. [`message`](objects.html#message) is for humans reading logs and can change. Optional fields:

| Field | When it appears |
| --- | --- |
| `param` | A validation failure. Names the parameter or body field at fault. |
| `required_scope` | On `insufficient_scope`. Names the scope needed. |
| `retry_after` | On a 429. Seconds to wait, same as the `retry-after` header. |

Every field the error body can carry: `code`, `message`, `param`, `required_scope`, `retry_after`.

## Errors any endpoint can return

These happen before the handler runs, so any call can return them.

`missing_authorization` `malformed_key` `invalid_key` `key_revoked` `key_expired` `owner_deactivated` `test_keys_unsupported` `insufficient_scope` `rate_limited` `too_many_concurrent` `internal_error`

## All codes

21 codes, grouped by status.

### 400

| Code | Meaning |
| --- | --- |
| `invalid_request` | A parameter or body field is missing, the wrong type, or out of range. `param` names it. |
| `invalid_cursor` | This endpoint did not issue that `cursor`. Start again without it. |
| `invalid_id` | The id failed its signature check, or is the wrong kind for this slot. |
| `unsupported_filter` | A query parameter this endpoint does not accept, or a value outside its list. The message says what is allowed. |
| `unsupported_sort` | Only `order=asc\|desc` exists. |

### 401

| Code | Meaning |
| --- | --- |
| `missing_authorization` | No `Authorization` header. |
| `malformed_key` | The header is there but is not a `Bearer` key of the right shape. |
| `invalid_key` | No such key, or the secret is wrong. The same error for both, on purpose. |
| `key_revoked` | The key was revoked. Make a new one. |
| `key_expired` | The key is past its expiry date. |
| `owner_deactivated` | The person who owns this key was deactivated. |

### 403

| Code | Meaning |
| --- | --- |
| `insufficient_scope` | The key lacks the scope this endpoint needs. `required_scope` names it. |
| `workspace_forbidden` | Unknown workspace, or one this key cannot reach. The same error for both. |
| `test_keys_unsupported` | A `lak_test_` key was used. Test keys are rejected in v1. |

### 404

| Code | Meaning |
| --- | --- |
| `not_found` | No such object, or it belongs to another workspace. The same error for both, so an id cannot be used to probe. |

### 409

| Code | Meaning |
| --- | --- |
| `conflict` | The write would break a uniqueness rule. |

### 422

| Code | Meaning |
| --- | --- |
| `unprocessable` | Valid JSON, but it breaks a rule. For example a member who cannot be assigned here. |

### 429

| Code | Meaning |
| --- | --- |
| `rate_limited` | This minute's limit is used up. `retry_after` gives the seconds to wait. |
| `too_many_concurrent` | Too many requests in flight on this key. Use fewer workers. |

### 500

| Code | Meaning |
| --- | --- |
| `internal_error` | Our bug. The message carries no detail; the real error is in our logs. |

### 502

| Code | Meaning |
| --- | --- |
| `upstream_error` | EmailBison, Google or Microsoft failed on a call we made for you. |

## How to handle them

- **Any 401.** Stop. Retrying will not help. The key is missing, wrong, revoked, expired, or its owner is gone.
- **403 `insufficient_scope`.** Read `required_scope`, then check `scopes_withheld` on `/v1/me`.
- **403 `workspace_forbidden` and 404 `not_found`.** Both mean "not yours or not there". Do not try to tell them apart.
- **429.** Wait `retry_after` seconds. For `too_many_concurrent`, use fewer workers instead.
- **5xx.** Retry with backoff. Every write is safe to retry except creating a note or a task.

---

Base URL `https://api.leadarc.io/v1`. Generated from the API source.
