> ## Documentation Index
> Fetch the complete documentation index at: https://docs.eat-now.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Errors and rate limits

> Diagnose failures and recover without creating duplicates.

## Error envelope

Business endpoint handlers return the following envelope. Validation example:

```json theme={null}
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request validation failed",
    "request_id": "d68fef44-5121-4a97-9d61-a3b4631d465f",
    "details": {
      "issues": [{ "path": "party_size", "message": "Invalid value" }]
    }
  }
}
```

`details` varies by error and may be absent. Keep `request_id`, endpoint, HTTP
status and time for support, without tokens or unnecessary customer data. Errors
before the handler, including `429`, may have another format and no
`request_id`. Inspect HTTP status before parsing the JSON envelope.

| HTTP  | Common code                                        | Meaning / action                                                    |
| ----- | -------------------------------------------------- | ------------------------------------------------------------------- |
| `400` | `VALIDATION_ERROR`                                 | Invalid JSON, type or field; inspect details.                       |
| `401` | `AUTHENTICATION_REQUIRED / INVALID_AUTHENTICATION` | Check full token, expiry, revocation and API feature.               |
| `403` | `INSUFFICIENT_SCOPE / RESTAURANT_SUSPENDED`        | Missing scope, or creation blocked for a suspended restaurant.      |
| `404` | `RESOURCE_NOT_FOUND`                               | Resource absent or outside the restaurant context.                  |
| `409` | `RESOURCE_CONFLICT`                                | Duplicate external\_id or POS service lock.                         |
| `422` | `VALIDATION_ERROR`                                 | Slot unavailable or another business rule rejects the request.      |
| `429` | `—`                                                | Rate limit; back off before retrying.                               |
| `500` | `INTERNAL_ERROR`                                   | Unexpected error; keep request\_id for support.                     |
| `502` | `INTERNAL_ERROR`                                   | Missed-call dispatch failure; inspect the response before retrying. |

A negative exact-slot check returns `200` with `data.available: false`. An
unbookable slot at creation returns `422`, not `409`. A missed-call report
processed with `201` and a `SKIPPED_*` outcome is not an error.

## Rate limits and retries

The partner route rule is configured for **600 requests per minute per client
IP**, not a per-key quota. When present, headers are `x-ratelimit-limit`,
`x-ratelimit-remaining` and `x-ratelimit-reset`; reset is a Unix timestamp in
**milliseconds**. These headers are not guaranteed on every response. On `429`,
reduce the request rate and back off before retrying.

Do not blindly repeat a write after a timeout or server error: it may already
have been stored. For reservations, search by `external_id` as described in the
[booking flow](/api-reference/booking-flow). For missed calls, reuse
`external_call_id` and inspect the endpoint's outcome semantics. Webhook
timeouts and retries have a
[separate contract](/api-reference/webhooks#delivery-and-retries).

For a failed missed call, an already stored row can make a retry with the same
`external_call_id` return `SKIPPED_DUPLICATE` without retrying WhatsApp
dispatch. Contact support to check that failure; do not change the identifier to
force a new send. `SENT` means the WhatsApp task was scheduled, not that the
customer received the message.
