> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tryverso.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Error handling

> Status codes, error messages, and what to do about them.

Every error is a JSON object with one `error` string. The strings are stable; matching on them is fine.

```json theme={null}
{ "error": "Connection not found" }
```

## Status codes

| Status | Meaning | Retry? |
| - | - | - |
| `400` | The request is malformed or misses a field | No, fix the request |
| `401` | Missing or invalid API key | No, check the key |
| `403` | Valid key, but not for this app or this connection | No |
| `404` | The user or connection does not exist for your app | No, check the id |
| `405` | Wrong HTTP method | No |
| `409` | The connection is `revoked` | No, connect the user again |
| `429` | More than 60 requests this minute | Yes, after `Retry-After` seconds |
| `500` | Verso-side failure | Yes, with exponential backoff |

## Messages by endpoint

### `GET /api/connections`, `GET /api/conversations`

| Status | Message |
| - | - |
| 400 | `Missing userRef parameter`, `Missing connectionId parameter` |
| 401 | `Missing Authorization header`, `Invalid API key` |
| 404 | `User not found`, `Connection not found` |
| 429 | `Rate limit exceeded` |
| 500 | `Failed to count conversations: …` |

`User not found` means no user with this `userRef` has opened a connect link for your app yet. `Connection not found` covers both unknown ids and connections of another app.

### `POST /api/ingest-export`

| Status | Message |
| - | - |
| 400 | `Missing appId`, `Missing connectionId`, `Invalid JSON body`, `Expected conversations array in raw payload` |
| 401 | `Missing or invalid Authorization header`, `Invalid API key` |
| 403 | `API key does not belong to this app`, `Connection does not belong to this app` |
| 404 | `Connection not found` |
| 409 | `Connection is revoked` |
| 500 | `Upsert failed: …` |

### `POST /api/purge`

| Status | Message |
| - | - |
| 400 | `Missing appId`, `Provide either userRef or connectionId`, `Invalid JSON body` |
| 401 | `Missing or invalid Authorization header`, `Invalid API key` |
| 403 | `API key does not belong to this app` |
| 404 | `User not found`, `Connection not found`, `Connection does not belong to this app` |

### Hosted pages (`/start`, `/manage`)

These are shown to the user, not returned to your backend.

| Status | Message | Cause |
| - | - | - |
| 400 | `Missing token parameter`, `Malformed token` | The URL was altered |
| 400 | `Token purpose must be 'connect' for /start`, `Token purpose must be 'manage' for this endpoint` | A manage link opened on `/start` or the reverse |
| 401 | `Invalid token: …` | Bad signature, wrong app secret, or expired link |
| 403 | `This link has already been used` | Single-use link opened twice |
| 404 | `App not found`, `User not found` | Unknown `appId`, or a manage link for a user who never connected |

## Retry guidance

* `429`: wait for `Retry-After` seconds, then retry. Spread bulk reads over time rather than bursting.
* `500`: retry with backoff (1 s, 2 s, 4 s, up to a minute). If it persists, write to [hello@tryverso.ai](mailto:hello@tryverso.ai) with the request and the time.
* Webhook deliveries are retried by Verso, not by you: answer 2xx quickly and process asynchronously.
