Skip to content
Keptslot
Start free

Errors

Every error uses one envelope. The status code says what class of problem it is. The type field says which problem it is, and type is the field to branch on. Do not match on message — the text is written for a person and it changes.

{
"error": {
"type": "validation_failed",
"message": "The request was not valid.",
"param": "starts_at"
}
}

param is present only on a 422 that names one field. Every other key in the body is described under 402 below.

type is stable. A new type can appear, so treat an unknown type as the class its status code names.

Status type What happened
401 unauthorized The key is missing, or it is not valid.
402 plan_limit_exceeded A plan cap stopped the request.
403 secret_key_required The route needs a secret key. You sent a publishable key.
403 origin_not_allowed The Origin header is not on the allowed list of this publishable key.
403 forbidden The credential is valid. The action is not permitted.
404 not_found No such record, or the record is not on this workspace.
409 slot_unavailable Somebody took that time first.
409 conflict That resource already exists.
409 booking_not_pending The booking is not awaiting confirmation.
409 no_show_not_applicable Only a past confirmed booking can be marked as a no-show.
422 validation_failed The request is malformed. param names the field.
422 verification_failed The 6-digit code was refused.
422 too_late_to_cancel The cancellation window is closed.
422 outside_working_hours The time is outside the working hours of that calendar.
422 idempotency_mismatch The Idempotency-Key was used before, with a different body.
429 rate_limited Too many requests. See the rate limits guide.
500 internal_error A fault on our side.
503 transient_failure Two writes contended. Retry the request.

Retry a 503 and a 429. Do not retry a 4xx: the same request gets the same answer.

A 402 means a plan cap stopped the request. The fields in the body depend on the key you used.

Key The body contains
Publishable (pk_) type, message
Secret (sk_) type, message, dimension
Account (ak_) type, message, dimension, limit, used

This is deliberate. A publishable key runs in a browser, where a stranger can read the response. Such a caller must not learn the plan state of the business.

A secret key gets the dimension and no numbers. Caps are counted at the account, and a secret key reaches one workspace. The numbers tell a key issued for one workspace about its siblings.

dimension is one of three wire values:

Value The cap
bookings Bookings in the current billing period.
staff Active calendars. The dashboard calls these “calendars”.
workspaces Active workspaces on the account.

used can be absent, and an absent used is not 0.

The booking cap reports no count, so used is absent on a bookings refusal. The cap also refuses when usage is above it, which happens after a plan downgrade. The cap is therefore not a substitute for the count. An account at 900 bookings can read “100 of 100” if you make that substitution.

dimension can also be absent. A 402 with no dimension names no cap, so there is nothing to count against and no number to show. Show the message and stop.

{
"error": {
"type": "plan_limit_exceeded",
"message": "This plan limit has been reached.",
"dimension": "staff",
"limit": 5,
"used": 5
}
}

secret_key_required and origin_not_allowed both come from a publishable key, and they need different fixes.

secret_key_required means the route is a server route. Send a secret key from your server.

origin_not_allowed means the browser sent an Origin header that this key does not list. Add the origin to the key, or use the hosted booking page.

CAUTION: The origin list is not a security boundary. GET /v1/public/workspaces/{slug} gives the publishable key to anybody who holds the slug, by design. The list stops a third party from embedding your key in their own site. It does not stop a script.

A 404 also covers “this record belongs to another workspace”. We do not answer 403 there, because a 403 confirms that the record exists.

verification_failed collapses four causes: a wrong code, an expired hold, too many attempts, and an unknown booking. They are not told apart on purpose. A response that told them apart is an oracle for a 6-digit code.