Errors
All errors come back as JSON with a consistent envelope. Status codes follow normal HTTP conventions; the body always carries a human-readable message.
Envelope
{
"error": {
"message": "Owner role required"
}
}
Validation errors include an issues field with the flattened output from Zod,
so you can map each issue back to the field that caused it:
{
"error": {
"message": "Validation failed",
"issues": {
"fieldErrors": {
"name": ["String must contain at least 1 character(s)"]
}
}
}
}
Status codes
400— invalid body, invalid path parameter, or assume-role failure.401— missing or invalidAuthorizationheader.403— authenticated, but the caller doesn't have the required role.404— resource not found, or the caller is not a member of the org they're targeting.409— the request conflicts with current state. This includes hitting the concurrently active boxes per seat ceiling: starting or launching another box is refused until you stop one, or until the org moves to the API plan, where that ceiling is raised or removed. See Rate limits & fair use.410— invite has expired.429— you've hit a rate limit; check theRetry-Afterheader and wait that many seconds before retrying. The body uses the same envelope shown above ({ "error": { "message": ... } }).500— unexpected server error. We log these; report persistent occurrences.
CORS preflight
Browser clients see CORS responses for cross-origin requests. The allow-list lives in the API stack; if your origin isn't in it the preflight will fail before your request body is ever inspected.