Errors
Every error shares one envelope. This page is the status-code glossary for the whole API.
A failed request always returns the same envelope shape, with data: null and a human-readable error string.
JSON
{ "data": null, "error": "Unknown field: job_title"}Two responses add a meta object alongside error with machine-readable detail: the over-quota 402 (your current usage against your cap) and the compliance-pack 409 (which documents are still blocking readiness).
Status-code glossary
4004xx- Malformed body, an unknown field, or a field that failed its own validation. The message names which. Choosing a client brand for a campaign link (
brand_id) adds three codes:invalid_brand_id(not a UUID),brand_not_found(not one of your brands — the same answer whether it does not exist or belongs to another account) andbrand_archived. Changing a brand (PATCH /api/v1/application-form/brands/{id}) addsbrand_names_immutable(the body named a name field; create a new brand instead) andnothing_to_update; creating or changing one also returns the logo-rights, colour and name codeslogo_rights_not_confirmed,invalid_colour,primary_colour_low_contrast,client_name_required,client_name_too_long,agency_name_required(the account has no company name; the agency of every brand is always that name),agency_name_too_longandinvalid_multipart. Creating a brand with anagency_namefield returnsagency_name_not_settable. A logo change that loses a race with another one for the same brand returns409logo_changed_concurrently.invalid_brand_idbrand_not_foundbrand_archivedbrand_names_immutablenothing_to_update 4014xx- Authentication failed — see Authentication. A missing, malformed, unknown, revoked or expired key is always this 401, never a 403.
4034xx- Your key is valid but the request was refused: the key was created Read only (every write; the body also carries
code: "key_read_only"), your team role cannot write (every write — aviewer’s key, or an account that could not be read just then), your plan does not include ChurnGuard (every ChurnGuard endpoint), or a custom assistant name is not available (PATCH /settings/assistant). Tell them apart by theerrorstring.This API key is read-only. Create a full-access key to make changes.Your team role doesn't allow this. Ask your team's admin or owner.ChurnGuard is not included in your plan.A custom assistant name is not available on this account. 4024xx- A plan refusal. Creating a candidate: over your seat or message quota (the
metaobject carries the figures). Starting new outbound WhatsApp (template, start, restart, ChurnGuard send, and a manual reply when the plan has ended): the body carriescodeno_subscription(plan ended) orover_message_quota(this month’s messages used). Nothing was sent or written. A reply inside an open chat is never refused for the message limit. 5035xx- A read this request depends on could not be completed — retry. On a send endpoint,
code: "billing_unavailable"means we could not check your plan; nothing was sent. 4044xx- Unknown id, someone else’s resource, or the whole API switched off for this deployment (an EMPTY body on that last case). Only ever the answer to a lookup that succeeded and found nothing — if our own read of the candidate fails you get a 503, never a 404.
Not found 4094xx- A conflict — creating a client brand when the account already holds the most it may (
brand_limit_reached; archived brands count), a duplicate candidate, an in-flight Idempotency-Key, (the pack endpoint) documents not yet all accepted, or (publishing Candidate Match questions) a staleexpected_version_noor a proposal identical to the live quiz. 4134xx- A client-brand logo upload is over the size cap (2 MB for PNG and JPEG, 512 KB for SVG). It is refused before the body is parsed.
logo_too_large 4154xx- A client-brand logo is not a PNG, JPEG or SVG, an SVG contains a refused construct (script, external reference, entity), or the file cannot be decoded.
unsupported_logounsafe_svgundecodable_logo 4224xx- A well-formed request refused for its content. Publishing Candidate Match questions: sensitive wording, either a blocked phrase or a warned phrase without
acknowledge_sensitive: true. Nothing was written. 4294xx- Rate limit exceeded — see Rate limits. Respect the
Retry-Afterheader.Too many requests — please try again shortly. 5005xx- The write could not be completed or verified. Safe to retry (with the same Idempotency-Key on a create).
5025xx- An upstream fetch (storage or Twilio media) failed. Safe to retry.
5035xx- The service, or a record a read depends on, is temporarily unavailable. Never a confident empty/negative payload — retry shortly.
The two byte-response endpoints (document content, the compliance pack) still return this same JSON envelope on any error status — only a 200 returns raw bytes.