# Errors

> Status codes, error bodies and request limits.

Successful requests answer `200`, `201` when something was created, or `204` with no body when something was deleted. Anything else is an error with a JSON body naming it:

```json
{ "error": "meal_not_found", "message": "Meal not found" }
```

## Status codes

| Status | Error | Meaning |
| --- | --- | --- |
| `400` | `invalid_input` | The body or query doesn't match what the endpoint takes. `issues` says which fields. |
| `400` | `invalid_json` | The body isn't valid JSON. |
| `401` | `unauthorized`, `invalid_token` | The key is missing, revoked or expired. |
| `403` | `insufficient_scope` | The key's permission doesn't allow this request. |
| `403` | `consent_required` | You haven't yet agreed to how Splot handles health information. Open the app and confirm. |
| `404` | `meal_not_found`, `food_not_found` | It doesn't exist, or isn't yours. |
| `409` | `food_in_catalog` | A new food has a barcode the catalogue already knows. The body's `food` is the one to use. |
| `413` | | The body is over 128 KB. |
| `429` | `rate_limit_exceeded` | Too many requests. Wait for `Retry-After` seconds. |
| `500` | `internal_error` | Something went wrong on Splot's side. Try again later. |

## Invalid input

An `invalid_input` error lists each problem with the path to the field and what is wrong:

```json
{
  "error": "invalid_input",
  "issues": [
    { "code": "custom", "path": ["items", 0], "message": "Quantity and unit must be provided together" }
  ]
}
```

## Limits

Each key can make 120 requests a minute, and all your keys together 300. The count starts again at the top of every minute. Over the limit, requests answer `429` with a `Retry-After` header giving the seconds to wait.
