Errors
Every error returns a real HTTP status and one body shape. Branch on code, never on message: codes are stable, messages are written for people and may be reworded.
Error envelope
{
"error": {
"code": "insufficient_scope",
"message": "This call needs the 'send' scope; the key has read, write.",
"details": { "required_scope": "send" }
}
}Codes
| Code | Status | Meaning |
|---|---|---|
unauthorized | 401 | No credential: no key and no session. Add the Authorization header. |
invalid_key | 401 | The key is malformed, unknown, revoked, or its owner left the workspace. Check for a truncated paste; otherwise create a new key. |
insufficient_scope | 403 | The key is valid but lacks the scope this call needs; details.required_scope names it. |
session_only | 403 | This call belongs to the signed-in browser (profile, avatar, workspace switching) and takes no key. |
unknown_operation | 403 | The path is not a registered operation. Keys fail closed: a route has to be in the registry before any key can reach it. |
forbidden | 403 | You are not a member of that workspace, or the action needs an owner or admin. |
not_found | 404 | No record with that id, or it belongs to another workspace. Both answer the same way on purpose. |
locked | 409 | The campaign is launched: steps, day offsets and variants are frozen. Duplicate it to change the shape. |
invalid | 422 | The input did not validate. message says what, and details carries the field errors when there are any. |
rate_limited | 429 | Over the per-key budget. Retry-After and details.retry_after give the seconds to wait. |
internal | 500 | Something failed on our side. Retry with backoff; if it persists, mail work@ashwanth.dev with the time of the request. |
Retrying
Retry 429 after the wait it names, and 500 with backoff. Do not retry 400 to 404, 409 or 422: they fail the same way until the request or the key changes.
Jobs that fail
A job that was accepted returns 200. If the work then fails, the failure is on the job, not the request: read the job and look at status and error. See Jobs and polling.