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

# Errors

> Standard HTTP status codes with a JSON body carrying a stable machine-readable tag and a human-readable message.

The Developer API uses conventional HTTP status codes and returns a JSON body on every error. The body carries a stable `_tag` you can switch on, a `message` meant for your logs, and a `feedback` line saying where to report the error if it does not tell you what to change:

```json
{
  "_tag": "DeveloperApiForbidden",
  "code": "insufficient_scope",
  "message": "Missing required scope: menus:write",
  "feedback": "If this error does not tell you what to change, or the API is wrong, report it with POST /v1/feedback and cite this response's x-request-id: https://docs.maple.inc/developer-api/concepts/feedback"
}
```

Branch on `_tag` (and `code` where present), never on the `message` text — messages may change, tags won’t.

## Status codes

| Status | Meaning                                                            | What to do                                                                 |
| ------ | ------------------------------------------------------------------ | -------------------------------------------------------------------------- |
| `400`  | The request is malformed or references invalid values              | Fix the request; don’t retry unchanged                                     |
| `401`  | Missing, malformed, or unrecognized credential, or an inactive app | Check the `Authorization` header and key                                   |
| `403`  | Valid credential, but not allowed (see `code` below)               | Adjust scopes or environment                                               |
| `404`  | The resource doesn’t exist or isn’t visible to your credential     | Verify the id and that you’re connected                                    |
| `409`  | The request conflicts with current state                           | Resolve the conflict (e.g. the location is already connected)              |
| `422`  | A business rule or unsupported capability prevents the operation   | Inspect `code` and `details`; change the request or location configuration |
| `429`  | A quota or rate limit was reached                                  | Wait for the response’s `retry_after` seconds before trying again          |
| `5xx`  | A problem on Maple’s side                                          | Retry with exponential backoff                                             |

`4xx` bodies are safe to surface to your own logs and dashboards. `5xx` responses should be retried with backoff — the [order decision](https://docs.maple.inc/developer-api/guides/receive-orders.md#step-5--decide-and-report-progress) and webhook replay endpoints are replay-safe, so retrying them is harmless.

If an error does not tell you what to change, or the API does something these docs say it should not, [send feedback](https://docs.maple.inc/developer-api/concepts/feedback.md) and cite the request’s `x-request-id`.

## Error tags

| `_tag`                      | Status | Notes                                                                                                                                                                                                                                                                                            |
| --------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `DeveloperApiBadRequest`    | 400    | Malformed request, or invalid values such as unknown event types. When path parameters, query parameters, headers or the body fail validation, `code` is `invalid_request` and the message names the field and what was expected. For menu publishing, the message lists every validation issue. |
| `DeveloperApiUnauthorized`  | 401    | The bearer credential is missing, malformed, expired, or belongs to an inactive app.                                                                                                                                                                                                             |
| `DeveloperApiForbidden`     | 403    | Carries a `code`: `insufficient_scope` or `wrong_environment`.                                                                                                                                                                                                                                   |
| `DeveloperApiNotFound`      | 404    | The resource doesn’t exist or your credential can’t see it.                                                                                                                                                                                                                                      |
| `DeveloperApiConflict`      | 409    | The request conflicts with current state, e.g. connecting a location another app already holds.                                                                                                                                                                                                  |
| `DeveloperApiInternalError` | 500    | Maple could not complete the request. Retry with backoff; if it persists, send feedback with the `x-request-id`.                                                                                                                                                                                 |

`DeveloperApiUnprocessable` is a `422` carrying `code`, `message`, and optional `details`. `DeveloperApiRateLimited` is a `429` carrying `retry_after` in seconds and the matching `Retry-After` HTTP header.

### Booking error codes

Booking mutation bodies reject unknown fields with `400`, including misspelled optional fields such as `expectedVersion` instead of `expected_version`. Idempotency keys must contain 1–255 characters.

- `400`: `invalid_slot_token`, `expired_slot_token`, `invalid_window`, `invalid_cursor`, `invalid_phone`, `location_required`, `change_required`, `invalid_blackout_dates`; configuration schema failures include validation paths.
- `409`: `stale_version` (`details.expected`/`actual`), `stale_blackout_dates`, `stale_configuration`, `idempotency_key_reused`, `overlapping_booking`, `slot_unavailable`, `hold_expired`, `hold_consumed`, `not_changeable`, `not_cancellable`, `illegal_transition` (`details.from_status`), `waitlist_closed`, `operation_in_progress` (`details.operation_id`, `details.retry_after`, `details.reason`).
- `422`: `bookings_not_enabled`, `party_size_out_of_bounds`, `outside_booking_window`, `large_party_inquiry_required`, `date_blocked`, `capability_unsupported`, `guest_contact_required`, `guest_messaging_unavailable`, `payment_instrument_required`, `configuration_missing`, `configuration_rejected`, `provider_rejected`.

For `operation_in_progress`, retry the original request with its original key. If `details.reason` is `replay_window_expired`, stop automatic retries and contact Maple with the operation ID. Never use a new key to work around an uncertain provider outcome. See [Take bookings](https://docs.maple.inc/developer-api/guides/take-bookings.md).

`provider_rejected` is final: the provider refused the request and nothing changed. For example, OpenTable may not allow a reservation to be changed or cancelled through Maple; the venue can still change it. Retrying gets the same answer.

When the provider says why it refused, you get the code a Maple-native location answers with in the same situation, not `provider_rejected`:

- a time too soon to book or move to: `422 outside_booking_window` with `details.reason: inside_min_lead`;
- a reservation that has started or is about to: `409 not_changeable` or `409 not_cancellable` with `details.reason: outside_policy_window`;
- a time that needs a card the provider can’t take through Maple: `422 payment_instrument_required`.

These are final too, and nothing changed.

### The `403` codes

A `DeveloperApiForbidden` always tells you *why*:

- `insufficient_scope` — the credential is valid but lacks a scope the endpoint requires. Check `GET /v1/me` against the [scopes table](https://docs.maple.inc/developer-api/concepts/authentication.md#scopes).
- `wrong_environment` — you used a test credential against live data or vice versa. The credential’s prefix fixes its environment.

## Handling errors well

- **Switch on `_tag`/`code`, log the `message`.** The tag is your control flow; the message is for humans debugging.
- **Don’t retry `4xx` unchanged.** They mean the request needs to change. The one nuance: a `409` may clear once the conflicting state is resolved.
- **Retry `5xx` with exponential backoff.** Add jitter to avoid retry storms.
- **Treat write retries as safe.** Order decisions and webhook replay are [replay-safe](https://docs.maple.inc/developer-api/concepts/idempotency.md), so a retry after a timeout won’t double-apply.
