All docs

Errors and error codes

The one shape every failure arrives in, the type for each status, and the codes to branch on rather than the message.

Updated 8 October 2026 About 5 minutes View as Markdown

Every failure arrives in one shape, whichever part of the API it came from, so a client has one thing to parse.

response
{
  "error": {
    "type": "invalid_request",
    "code": "naive_datetime",
    "message": "Send a time with an offset, like 2026-06-10T10:00:00+02:00.",
    "param": "starts_at"
  }
}

All four keys are always there. type is the broad class, and decides whether to try again. code is the specific reason, and is what to branch on. message is written for a person and may be reworded at any time, so never branch on it. param names the field that was wrong, or is null.

Types

Status Type
400 invalid_request
401 authentication_error
403 permission_error
404 not_found
405 invalid_request
406 invalid_request
409 conflict
415 invalid_request
422 invalid_request
429 rate_limit
5xx api_error

rate_limit and api_error are worth trying again: the first after the seconds in Retry-After, the second after a short wait. Send a retried write with the same Idempotency-Key, so it is answered rather than acted on twice. The SDK's isRetryable() says which is which.

Codes about the request as a whole

Code Means
not_authenticated No key was sent: no Authorization header, or one that is not Bearer
invalid_key The key is malformed, revoked, or not a key at all
secret_key_required The call needs a secret key and was made with a publishable one
live_key_required A test key asked for something only a live key may do: publishing, unpublishing or restoring a page, or moving one that is on the website; changing bookings setup customers are offered, the opening hours or the live rules. Also a test key's checkout reaching an account that takes real money, which a working platform never lets happen
origin_not_allowed A publishable key was used from a website not on its list
subscription_inactive The account's plan has ended, so the API answers nothing
quota_exhausted The month's allowance of requests is used up
throttled Too many calls in a short time
idempotency_key_required A write that needs an Idempotency-Key was sent without one
idempotency_conflict A request with the same key is still being worked on
idempotency_key_reused The same key was sent with a different request

Codes about one field

When one field is wrong, param names it and code says how: required, invalid, blank, null or max_length, and each part of the API adds its own, such as naive_datetime when a time was sent without an offset. A code about the request as a whole, such as slot_unavailable, has a param of null.

Codes each part adds

Each part answers with codes of its own, about what it does, in the same shape. A part the project has not switched on answers none of them.

Content

Code Means
browser_reads_not_allowed The project keeps its content off the browser, so pages are read from your server with a secret key
limit_reached The website holds as many pages or section types, or a section type as many fields, as it may. Remove one to add another
page_is_live The page is on the website. Unpublish it first, then delete it
section_type_in_use A page holds a section of this type. Take it off every page first, then remove it

Bookings

Code Means
slot_unavailable The time is not free: taken a moment before, or outside the hours, the notice or the grid. Free times can be up to a minute old, so stop offering this one rather than asking again straight away
naive_datetime A time was sent without an offset
unknown_service No bookable service has that id
unknown_staff Nobody bookable has that id, or they do not do that service
phone_required The business asks for a phone number, and none was sent
too_many_bookings This customer already holds as many bookings that day as the business allows
invalid_date A date is not written YYYY-MM-DD, or the window ends before it starts
window_too_wide Free times were asked for over more days than one request covers
return_url_not_allowed A publishable key named a return address that is not one of its websites, or not https for a live key
booking_not_active The booking no longer holds its time: cancelled, expired or over
cancel_by_phone The business takes cancellations by phone, not online
too_late_to_cancel The cancellation window has passed, so the customer contacts the business
reschedule_not_allowed The business does not let customers move their own booking
limit_reached The website holds as many services, people, opening hours rows or dated closures as it may. Remove one to add another

Payments

Code Means
payments_not_connected No payment account is connected in this key's mode, so nothing can be charged. The ordinary state of a project that has not connected one yet
invalid_currency The currency is not one a project can be priced in, the same list its settings screen offers: counted in hundredths, like CHF or EUR
invalid_filter A filter on the list is not one the API can read, such as an id that is not one
too_much_metadata A checkout carried more metadata keys than it takes

Inbox

Code Means
bot_check_failed The website asks for Cloudflare's bot check and the token was missing, spent or refused. Ask the visitor to complete the check again, which makes a new token
daily_limit_reached The website has received as many messages today as one website may. Nothing was kept, and it starts again at midnight on the website's clock
invalid_folder A folder other than inbox, archived or spam was asked for

Not found means not yours, too

A thing that does not exist, one that belongs to another project, and a part the project has not switched on all answer the same 404, with the code not_found. The API is not a way to find out what another account holds.