> ## Documentation Index
> Fetch the complete documentation index at: https://openphone-dev.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Errors

> Quo API errors name what went wrong, point at the field that caused it, and can include a trace id support uses to find your exact request.

Every error the API returns is built to help you answer three questions: what happened (`title`, `message`), where (`errors[].path`), and, when a `trace` is included, how to find this exact request again.

## The envelope

Every error, regardless of status code, uses the same shape:

```json theme={null}
{
  "title": "Bad Request",
  "message": "Validation failed for 1 field.",
  "docs": "https://quo.com/docs",
  "trace": "6897907457496870895",
  "errors": [
    {
      "path": "/query/limit",
      "message": "must be <= 50",
      "value": 200,
      "schema": { "type": "integer" }
    }
  ]
}
```

| Field     | Always present | Meaning                                                                                                                                                     |
| --------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `title`   | Yes            | The error class. Matches the HTTP status text (`Bad Request`, `Unauthorized`, and so on).                                                                   |
| `message` | Yes            | A human-readable summary, written for the person reading your logs rather than for end users.                                                               |
| `docs`    | Yes            | Where to read more. You're here.                                                                                                                            |
| `trace`   | No             | A unique id for this request. See [below](#the-trace-id).                                                                                                   |
| `errors`  | No             | Field-level detail for validation failures. Each entry names a `path`, what's wrong with it, the `value` you sent, and the `schema` it was checked against. |

Handle errors by HTTP status code first and `errors[].path` second. The `message` strings are for humans and may be reworded; the structure is the contract.

## Status codes

| Code  | When you'll see it                                                                                                                              | Retry?                       |
| ----- | ----------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------- |
| `200` | Success.                                                                                                                                        | —                            |
| `400` | The request is malformed: a missing required header, an unparseable body, a parameter outside its bounds. Check `errors[]` for the exact field. | Not until you've fixed it.   |
| `401` | The `Authorization` header is missing or doesn't contain a valid API key.                                                                       | Not until you've fixed it.   |
| `403` | Your key is valid but this action isn't allowed: insufficient permissions, or a workspace setting that isn't enabled.                           | Not until something changes. |
| `404` | The resource doesn't exist, or its id belongs to a different workspace than your key.                                                           | No.                          |
| `422` | The request is well-formed but semantically wrong. Every field parses, yet the combination can't be processed.                                  | Not until you've fixed it.   |
| `429` | You've exceeded [10 requests per second](/2026-03-30/rate-limits).                                                                              | Yes, with backoff.           |
| `500` | Something failed on our side. If the response includes a `trace` id, that's your fast path to an answer.                                        | Yes, with backoff.           |

A useful asymmetry to build into your integration: 4xx errors are yours, 5xx errors are ours. Retrying a `400` in a loop won't change the answer. It just spends your rate limit telling us the same thing.

## Reading a validation error

`errors[]` exists so that "fix the request" never requires guesswork. Each entry is one problem:

* **`path`** points to the offending part of the request.
* **`message`** says what's wrong with it, in one sentence.
* **`value`** echoes what you actually sent, so you can spot the gap between what your code meant and what it did.
* **`schema`** shows the constraint it was validated against.

Multiple invalid fields arrive as multiple entries in one response, so a single round trip shows everything that needs fixing.

## The trace id

When an error includes a `trace`, log it. When you contact [support+developers@quo.com](mailto:support+developers@quo.com) with a trace id, we can pull up the exact request: what arrived, how it was interpreted, what happened next. Without it, we're both starting from "can you describe what you sent?"

One line of logging now saves a day of email archaeology later.

## Retrying

For `429` and `5xx` responses, retry with exponential backoff and jitter: first retry after about a second, doubling thereafter, with a cap on attempts that fits how time-sensitive the work is. Read requests (`GET`) are always safe to retry. For writes, check the endpoint's reference page first — a retried `POST` can repeat its effect, so re-attempting something like a message send needs more care than re-running a read.
