# Errors

> ChargeNow uses standard HTTP status codes and returns a consistent RFC 7807 problem body for every failure.

Every failure returns a standard HTTP status code and a consistent body, `application/problem+json` ([RFC 7807](https://www.rfc-editor.org/rfc/rfc7807)):

```json
{
  "title": "Unauthorized",
  "status": 401,
  "detail": "Authentication required.",
  "reason": "auth.missing_token",
  "meta": {}
}
```

| Field    | Description                                                                                                               |
| -------- | ------------------------------------------------------------------------------------------------------------------------- |
| `title`  | Short summary, matching the HTTP status phrase.                                                                           |
| `status` | HTTP status code.                                                                                                         |
| `detail` | Human-readable explanation, safe to show an end user.                                                                     |
| `reason` | Stable machine-readable code. **Handle errors on this**, not on `title` or `detail`, which are for humans and may change. |
| `meta`   | Extra context, such as which field failed validation. May be empty.                                                       |

## Status codes

| Status                      | When it occurs                                                                                                              |
| --------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| `400 Bad Request`           | Invalid body or parameters. `meta` carries field-level detail (below).                                                      |
| `401 Unauthorized`          | Authentication failed. See the `auth.*` `reason`.                                                                           |
| `403 Forbidden`             | The token lacks permission for this action.                                                                                 |
| `404 Not Found`             | The resource does not exist.                                                                                                |
| `409 Conflict`              | A conflict prevented the operation, e.g. an `Idempotency-Key` reused with a different body (`reason: idempotency.failure`). |
| `412 Precondition Failed`   | A required condition was not met, e.g. the charge point is not `Available`.                                                 |
| `429 Too Many Requests`     | Rate limit exceeded. Back off and retry.                                                                                    |
| `503 Service Unavailable`   | Temporary; retry after a short delay.                                                                                       |
| `504 Gateway Timeout`       | The request timed out; retry after a short delay.                                                                           |
| `500 Internal Server Error` | Something went wrong on our side.                                                                                           |

## Retrying

`503` and `504` responses carry a `Retry-After` header (seconds); use exponential backoff for repeated failures. An operation sent with an `Idempotency-Key` is safe to retry on a network error without creating a duplicate. Reusing a key with a *different* body returns `409` with `reason: idempotency.failure`: use the original result, or a new key for a distinct operation.

## Validation detail

On a `400`, `meta` pinpoints what was wrong, so you can show a precise message or fix the request in code:

```json
"meta": {
  "violations": [
    {
      "field": "chargePointId",
      "message": "Provide chargePointId to start a session",
      "validationRule": "mutually_exclusive"
    }
  ]
}
```

## Authentication errors

See [Authentication](/docs/charge-now/guides/authentication) for the full list of `auth.*` reason codes.
