Errors
An error is always JSON, in this shape:
{
"error": {
"code": "validation_failed",
"message": "The request is not valid.",
"request_id": "req_3f9a1c52d7e4b08a61",
"hint": "Fix the fields named in details and call again. Nothing was changed.",
"details": [ { "path": "period", "issue": "must be one of: 7d, 14d, 30d, 90d" } ]
}
}code is stable: we only ever add new codes, so you can branch on it. message is a fixed sentence for the code. hint is on every error and says the next thing to do: the call to make, the time to wait or the person to ask. request_id is also sent in the X-Request-Id header: quote it if you ask us for help. reason, fix, details, detail and retry_at appear when they help. For a field that takes a limited set, details lists the allowed values. When the platform refuses a contact operation, detail is the sentence the app shows a person for the same refusal, reason is a short stable word, and retry_at is the time the same call is allowed again, when known.
The body names no internals and never repeats a value you sent.
Codes
| Code | Status | Meaning |
|---|---|---|
unauthenticated | 401 | The key is missing, wrong, expired or revoked. |
forbidden | 403 | The key, or the person who made it, may not do this. |
agent_access_paused | 403 | A workspace administrator has paused all agent access. |
person_required | 403 | This needs a person to do it in the app: taking someone off the do-not-contact list, sending again a message that may already have gone out, settling a review as not sent. The hint names the place. |
not_found | 404 | There is nothing there, or you may not know whether there is. |
method_not_allowed | 405 | The address exists but not for this method. |
conflict | 409 | The request clashes with the current state. The reason says how, for example not_draft for a campaign that has already started. |
idempotency_in_progress | 409 | The same idempotency key is still being processed. |
idempotency_key_required | 400 | This operation needs an Idempotency-Key header. Few do: contact operations do not. |
payload_too_large | 413 | The body is bigger than the call allows. |
validation_failed | 422 | The request is not valid. details lists each field. |
idempotency_key_reused | 422 | The key was used before with a different body. |
rate_limited | 429 | Too many calls. Wait for Retry-After seconds. The reason daily_contact_budget or subject_daily_limit means a daily limit that a person set on the key was spent. |
internal | 500 | Something went wrong on our side. Retry with the same idempotency key. |
Retrying
Retry 429 and 500 and network failures, with a growing pause and the same Idempotency-Key. Do not retry 400, 401, 403, 404 or 422 without changing something first. Read the hint: for a 409 it often names the call that shows what is in the way, and retry_at says when to try again.