# Errors

Every error has the same shape:

```json
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "The given data was invalid.",
    "details": {
      "schedule": ["Schedule windows must not overlap (Mon 06:00 and Mon 06:30)."],
      "http.url": ["Only HTTPS URLs are allowed."]
    }
  }
}
```

Branch on `code` — it is stable. `message` is for people and may change. For validation errors `details` maps field paths (as in the request body, e.g. `http.headers.0.name`) to messages.

| HTTP | `code` | Meaning — what to do |
| --- | --- | --- |
| 401 | `UNAUTHENTICATED` | Missing, invalid, revoked or expired key. Send `Authorization: Bearer <key>`. |
| 403 | `FORBIDDEN_SCOPE` | The key lacks a scope (`details.required_scopes`). Use a key with it. |
| 403 | `PLAN_LIMIT_REACHED` | Active-monitor limit of the plan. Pause or delete a monitor first. |
| 404 | `MONITOR_NOT_FOUND` | No such monitor in this account (other accounts' monitors do not exist for you). |
| 404 | `NOT_FOUND` | Unknown endpoint. |
| 405 | `METHOD_NOT_ALLOWED` | Wrong HTTP method for the endpoint. |
| 409 | `MONITOR_ALREADY_EXISTS` | Another monitor of the account has this `external_id` — `details.monitor_id` tells which. Read or `PATCH` it instead. |
| 409 | `IDEMPOTENCY_IN_PROGRESS` | The same `Idempotency-Key` is being processed. Retry in a moment. |
| 409 | `UNSUPPORTED_FOR_MONITOR_TYPE` | E.g. `rotate-token` on an HTTP Check. |
| 415 | `UNSUPPORTED_MEDIA_TYPE` | Send JSON with `Content-Type: application/json`. |
| 422 | `VALIDATION_ERROR` | Fix the fields in `details`. Unknown fields are errors too. |
| 422 | `IDEMPOTENCY_KEY_REUSED` | The key was used with a different body. Use a new key. |
| 429 | `RATE_LIMITED` | Too many requests. Wait `Retry-After` seconds. |
| 500 | `INTERNAL_ERROR` | Our fault. Retry later; with an `Idempotency-Key`, retrying a create is safe. |

Validation messages are in English and describe the same rules as the dashboard wizard.
