UtilitayDevelopers
Get an API key
Reference

Errors, limits and paging

One error envelope everywhere. Every response, success or failure, carries X-Request-Id; quote it when you write to us.

{
  "error": "a sentence for a person",
  "code": "for_your_code_to_branch_on"
}

Error codes

StatusCodeMeaningWhat to do
400bad_requestA status that is not one, or ids that are not uuids.Read error; the sentence names the field.
400validation_errorA field is missing or the wrong shape: a decline with no reason, a code with letters in it.Fix the request; do not retry as-is.
400missing_answerSomething the move needs is missing, such as a reschedule that does not say the new time in the request's precision.Send what the sentence names.
400not_on_offerThe time, person or place asked for is not one the menu offers.Choose one the menu offers.
401unauthorizedNo bearer key.Send Authorization: Bearer utl_live_…
401invalid_api_keyKey not recognised.Check for truncation; the checksum catches typos.
401api_key_revokedKey was revoked in Account.Create a new key.
401api_key_expiredKey passed its expiry.Roll the key.
403insufficient_scopeKey lacks the scope the route needs.Create a key with the scope named.
403wrong_productKey belongs to another product.Use a Menu key on Menu paths.
403org_suspendedOrganisation is suspended. Reads still work; writes are refused.Settle the account in Utilitay Account.
403subscription_suspendedThis instance's subscription is suspended. Reads still work.Pay the open invoice in Utilitay Account.
404not_foundNo such request in this instance — or the key does not reach the instance.Check the id, the instance slug and the key's reach.
405method_not_allowedThe path exists; the method does not. Reads are GET, every move is POST.Use the method the reference shows.
409already_decidedThe request has moved on: someone answered it first, or it expired, was cancelled or closed.Read it again; do not retry.
409time_takenThe time or person is no longer free.Choose another time, or decline.
413too_largeBody over 1 MB.Send less.
429rate_limitedOver 10/s per key or 30/s per instance.Wait Retry-After seconds, then retry.
502upstream_errorThe gateway could not get an answer from Menu.Retry with backoff. A move that did land answers 409 already_decided the second time.
503unavailableBriefly down.Retry with backoff.
Rate limits

10 requests/s per key. 30 requests/s per instance. Over the limit you get 429 with Retry-After. There are no X-RateLimit-* headers. Bodies over 1 MB are refused with 413.

Pagination

?limit (default 50, max 200), ?offset on the lists that page. List responses are bare JSON arrays: no envelope, no cursor, no total. Stop when a page comes back shorter than limit.

Idempotency

Menu takes no Idempotency-Key. Approve, decline and cancel happen once: retried after they landed, they answer 409 already_decided. A code checked twice is wrong the second time, and counts as a wrong try. Before retrying a reschedule or a reassign, read the request: its history says whether the first one landed.