
# Errors

Errors use conventional HTTP statuses and always return the same object:

```json
{
  "error": {
    "type": "invalid_request_error",
    "code": "parameter_missing",
    "message": "Missing required parameter: price.",
    "param": "price",
    "doc_url": "https://api.kibanda.africa/docs/errors#parameter_missing"
  }
}
```

Branch on `type` and `code` (stable); show `message` to people (it may change). `param` names the offending field when there is one.

## Types

| Type | Status | Retry? |
|---|---|---|
| `invalid_request_error` | 400 | No — fix the request. |
| `authentication_error` | 401 | No — check the key. |
| `permission_error` | 403 | No. |
| `not_found_error` | 404 | No. |
| `conflict_error` | 409 | No — the object's state doesn't allow it. |
| `idempotency_error` | 400 / 409 | 409: yes, shortly. 400: no — use a new key. |
| `rate_limit_error` | 429 | Yes, with backoff. |
| `api_error` | 500 | Yes, with the same `Idempotency-Key`. |

## Codes

### parameter_missing
A required field wasn't sent. `param` names it.

### parameter_invalid_string
### parameter_invalid_integer
### parameter_invalid_boolean
### parameter_invalid_number
### parameter_invalid_array
### parameter_invalid_object
A field has the wrong type or is out of range. Money is an **integer in cents**: send `25000`, not `250.00` or `"250"`.

### parameter_invalid_metadata
`metadata` must be an object of up to 50 keys (≤ 40 characters) with string values (≤ 500 characters).

### parameter_invalid_cursor
`starting_after` must be the `id` of an object from the previous page.

### parameter_unknown
The field can't be set here. Order status, for example, changes through actions such as `POST /v1/orders/{id}/cancel`.

### invalid_json
The body isn't a JSON object.

### phone_invalid
Phones may be `+254712345678`, `254712345678` or `0712 345 678`; other countries in E.164 (`+256…`).

### email_invalid
### url_invalid
Webhook URLs must be `https://`.

### currency_unsupported
Only `KES` for now.

### event_type_unknown
See the [event types](https://kibanda.africa/docs/events#types).

### limit_reached
Too many API keys (20) or webhook endpoints (16).

### resource_missing
No object with that id in this shop (or it belongs to another shop).

### external_id_taken
Another object already has that `external_id`. To sync a catalog, use [`POST /v1/products/batch`](https://kibanda.africa/docs/products#batch-upsert), which upserts by `external_id`.

### customer_exists
A customer with that phone exists; the message includes their id. Pass `"upsert": true` to update them instead.

### order_not_cancellable
The order is paid, completed, already cancelled, or a payment is in progress.

### idempotency_key_reused
The key was used with a different request. Each distinct request needs its own key.

### idempotency_key_invalid
Keys can be at most 255 characters.

### idempotency_request_in_progress
The first request with this key hasn't finished. Retry in a moment.

### unauthenticated
### api_key_invalid
### api_key_wrong_environment
### session_required
See [Authentication](https://kibanda.africa/docs/authentication).

### route_not_found
No such endpoint. Paths start with `/v1/`.

### internal_error
Our fault, and it's been reported. Retrying with the same `Idempotency-Key` is safe.
