# Errors

## Error format

```json
{
  "error": {
    "code": "rep_speaker_not_found",
    "message": "No transcript speaker matches the rep. Speakers found: \"Dana Whitfield\", \"S. Reid\". Send transcript.rep_speaker to say which one is the rep.",
    "request_id": "req_4f0c8d1e2a9b7c6d5e4f3a2b",
    "fields": [{ "field": "transcript.rep_speaker", "message": "Rep speaker not identified." }]
  }
}
```

Branch on `code`; it is stable. `message` is for people and may change.
`fields` appears on some `422`s. New codes may appear: handle an unknown code
by its HTTP status. Chambr saves nothing when it returns an error.

## Fix the request

| HTTP | `code` | When |
|---|---|---|
| 400 | `invalid_json` | The body is not valid JSON |
| 401 | `invalid_api_key` | `Authorization` header missing or malformed, or an unknown key |
| 404 | `not_found` | No call with this id in your account |
| 404 | `route_not_found` | Unknown `/v1` path |
| 409 | `external_id_conflict` | Same `(provider, external_id)`, different transcript. See [Idempotency](https://developers.staging.chambr.ai/idempotency.md) |
| 409 | `recording_already_used` | The `recording_id` belongs to another call |
| 413 | `payload_too_large` | Body over 1 MiB |
| 415 | `unsupported_media_type` | Body not sent as `application/json` |
| 422 | `validation_failed` | Schema errors; see `fields` |
| 422 | `unknown_field` | A field the API does not have; use `metadata` |
| 422 | `transcript_unlabeled` | No speaker labels |
| 422 | `transcript_too_long` | Over 2,000 turns or 400,000 characters |
| 422 | `rep_speaker_not_found` | `rep_speaker` is not a speaker label, or the transcript is too short to find the rep |
| 422 | `rep_speaker_ambiguous` | `rep_speaker` matches several labels |
| 422 | `rep_speaker_undetermined` | Chambr could not tell which speaker is the rep; send `rep_speaker` |
| 422 | `recording_not_found` | `recording_id` not uploaded, expired, malformed or another account's |
| 422 | `recording_too_large` | Recording over 200 MB |
| 422 | `recording_type_not_supported` | `content_type` not supported |

## Fix Chambr setup

| HTTP | `code` | When |
|---|---|---|
| 401 | `api_key_revoked` | The key was revoked |
| 401 | `api_key_owner_inactive` | The admin who created the key left; [rotate it](https://developers.staging.chambr.ai/authentication.md#rotate-a-key) |
| 403 | `insufficient_scope` | The key may not use this endpoint |
| 403 | `feature_not_enabled` | Real Call Scoring is not enabled |
| 403 | `account_suspended` | The Chambr account is suspended |
| 403 | `payment_required` | The account's first payment has not completed |
| 422 | `rep_not_found` | No Chambr user with that email; invite the rep, then retry |
| 422 | `rep_inactive` | The user was deactivated or removed |
| 422 | `rep_pending_activation` | The user has not signed in yet; retry after they do |
| 422 | `rep_no_team` | The user is on no team; add them to one, then retry |
| 422 | `rep_ambiguous` | The email maps to more than one user or team; contact support |
| 422 | `team_not_configured` | No `rep` sent and the key's team was deleted; create a new key |
| 422 | `scorecard_not_found` | `scorecard_id` is not a published scorecard of the rep's team |
| 422 | `scorecard_not_configured` | No `scorecard_id` and no scorecard rule for the team |
| 422 | `scorecard_rule_unavailable` | No `scorecard_id`, and the scorecard rule (or default) for this call type points to a scorecard that is no longer available. Chambr never swaps in another scorecard; send `scorecard_id` or fix the rule |

## Retry

| HTTP | `code` | When |
|---|---|---|
| 429 | `rate_limited` | Too many requests |
| 500 | `internal_error` | Unexpected error |
| 503 | `inference_unavailable` | Finding the rep's speaker failed or timed out |

See [Rate limits and retries](https://developers.staging.chambr.ai/rate-limits.md) for how.
