Skip to content
Maple

Core concepts

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:

{
"_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 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 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.

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.
  • 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, so a retry after a timeout won’t double-apply.