# Errors, limits and versions

## Errors

Every error has the same JSON body:

```json
{
  "error": "No service acme/shopp.",
  "code": "not_found",
  "hint": "List your services with GET /api/v1/services."
}
```

- `error`: what went wrong, in one sentence. It can change; do not test it.
- `code`: stable. Test this in scripts.
- `hint`: the next thing to try, often a call. `null` when there is none.

| `code` | HTTP | What to do |
| --- | --- | --- |
| `bad_request` | 400, 405 | Fix the request. `error` names the field: `body.template must be a string`. Unknown keys and unknown query parameters are errors too. |
| `unauthorized` | 401 | No token, or the token is not valid any more. Make a new one on the account page. |
| `forbidden` | 403 | The token works, but this is not yours (for example a repo without the GitHub App). |
| `not_found` | 404 | No such service, deployment, env var or route. Services of other organizations are "not found" too. |
| `conflict` | 409 | Not possible in the current state, for example cancel a deployment that is done. |
| `too_large` | 413 | The body is over 1 MB. |
| `rate_limited` | 429 | Too many requests. Wait the seconds in `Retry-After`. |
| `unavailable` | 502, 503 | dudbox or GitHub cannot answer right now. Try again in a minute. |
| `internal` | 500 | A bug on our side. Try again; if it stays, tell us. |

## Limits

- 300 requests a minute per token. A stream (events, `follow=true`) counts once while it is open.
- A body is at most 1 MB. An env value is at most 32 KB.
- `?wait=` on a deployment is at most 300 seconds.
- Lists give everything at once. A list that gets too long will get pages later, with a new optional query parameter; the answers you get today stay the same.

## Versions

This is version 1: `/api/v1`. What these docs show stays:

- A documented field keeps its name, its type and its meaning.
- New fields and new routes can come at any time. Ignore keys you do not know.
- New values can come in `trigger` and in other string fields that say "more may come". `status` and `code` change only in a new version.
- A change that would break a caller goes to `/api/v2`. `/api/v1` then keeps working, and this page says until when.

The dashboard uses its own private routes (`/api/dash`). Do not call them: they change without notice.
