> This page is for Cloud Call Center.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.hams.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.hams.ai/_mcp/server.

# Errors

> Every failure has the same body, so branch on the code and quote the support id.

Every error response has the same shape, for every endpoint:

```json
{
  "detail": "No outbound route matches that number",
  "code": "unprocessable",
  "support_id": "b2c4d6e8"
}
```

| Field        | Meaning                                                                              |
| ------------ | ------------------------------------------------------------------------------------ |
| `detail`     | A message for a person who reads your logs. It can change at any time                |
| `code`       | A stable key for a program. Branch on this field                                     |
| `support_id` | A short id that the server also writes to its log. Quote it when you contact support |
| `errors`     | A list of field errors. It is present only for validation failures                   |

A validation failure adds a list of field errors:

```json
{
  "detail": "Validation failed",
  "code": "validation_error",
  "support_id": "7f3a9c21",
  "errors": [
    { "field": "to", "message": "Field required", "type": "missing" }
  ]
}
```

`field` is the dotted path into the request body. You can map it to a form field. `type` is a stable
kind of error. You can use it as a localization key.

## Codes

| `code`                | Status | Meaning                                                                                                                                     |
| --------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `validation_error`    | 422    | The request body or query failed validation. The body has `errors`                                                                          |
| `bad_request`         | 400    | The request is malformed                                                                                                                    |
| `unauthorized`        | 401    | The key is missing, revoked, expired, or not a developer key                                                                                |
| `forbidden`           | 403    | The key is valid but does not have the scope that the endpoint needs                                                                        |
| `not_found`           | 404    | The resource does not exist in this account                                                                                                 |
| `duplicate_value`     | 422    | The request breaks a uniqueness rule, for example a webhook name that is already in use                                                     |
| `conflict`            | 409    | The resource exists but is not ready, for example a recording that the system has not finished merging, or a transcript that is in progress |
| `unprocessable`       | 422    | The request is well formed but the system cannot carry it out, for example a number that no route matches                                   |
| `rate_limited`        | 429    | The request exceeded a limit. `Retry-After` gives the time when the window ends                                                             |
| `service_unavailable` | 503    | A required service is not available, for example no call server can take a call. Try again later                                            |
| `internal_error`      | 500    | A failure on the Hams side. `detail` is generic on purpose. Quote the `support_id`                                                          |

Hams adds new codes without a new API version. Treat a code that you do not know as a generic failure.

## A 404 never means forbidden

A resource that belongs to another account returns the same `404` and the same generic message as a
resource that does not exist. The API does not show whether an id is valid in another account. A `404`
on an id that you received always means that the id is not in your account.

A transcript that does not exist also returns `404`. This includes a transcript that failed. See
[Call history and recordings](/cloud-call-center/api/call-history-and-recordings).

## A 401 and the dashboard endpoints

A developer key works only under `/api/developer/v1`. If you send a key to any other path, the
API rejects the request as not authenticated. This includes the paths that the dashboard uses. A dashboard session
also does not open the developer endpoints. The 2 credentials do not overlap.

## A 429 and the limits

By default, each key can make 10 requests each second across the API. The limit for a key is a fixed window. It
resets at the window boundary. Calls that you place also have a limit for each account each second.
That limit counts the requests in a window that moves with time. It does not count the requests that it refuses. Both limits
answer `429` with the standard body and a `Retry-After` header.

Wait until the time in the header. Then try again.

## A 503 means try again

A `503` with the code `service_unavailable` on a call placement means that no call server can take
the call now. The system did not place
the call. Try again with a longer delay each time. The key and the request are correct.

## Related

* [Quickstart](/cloud-call-center/api/quickstart)
* [Outbound calls](/cloud-call-center/api/outbound-calls)
* [Webhooks](/cloud-call-center/api/webhooks)