Errors
The error envelope, every code, and which are worth retrying.
Every failure has the same shape:
{
"error": {
"type": "not_found_error",
"code": "resource_not_found",
"message": "This site does not exist.",
"docs_url": "https://atelier201.com/docs/api/errors#resource_not_found"
},
"request_id": "req_01K9X7"
}Branch on code, never on message. Codes are contract; messages are
written for people and improve over time. Some errors add a details object
with what you need to act, such as the current revision after a write conflict.
Which to retry
| Status | Retry? |
|---|---|
| 429 | Yes, after Retry-After. |
| 5xx | Only for an idempotent request (GET, PUT, DELETE). A POST that fails with a 5xx may already have been applied. Re-read the resource first. |
| 4xx | No. The request is wrong and will be wrong again. |
Every code
authentication_required
authentication_error · HTTP 401
No credential was sent. Add an Authorization: Bearer header.
invalid_api_key
authentication_error · HTTP 401
The credential is not recognised. It may belong to a workspace that no longer exists.
api_key_expired
authentication_error · HTTP 401
The key passed its expiry date. Create a new one.
api_key_revoked
authentication_error · HTTP 401
Somebody revoked it. This is permanent.
insufficient_scope
permission_error · HTTP 403
The credential is valid but was not granted the scope this endpoint needs. The message names it. Re-issue the credential; the scope cannot be widened in place.
feature_not_available
permission_error · HTTP 403
The plan does not include this. Publishing a draft answers this: details.blockers holds plan_required, and action_url opens the site’s plan.
admin_required
permission_error · HTTP 403
The action is restricted to workspace admins: publishing, rolling back, taking a site offline, deleting a site and changing its domains.
invalid_request
invalid_request_error · HTTP 400
The body or the query did not validate. The message says which field.
unknown_field
invalid_request_error · HTTP 400
A field was sent that this endpoint does not accept. Inputs are strict on purpose: a silently ignored field is a bug you would find much later.
invalid_parameter
invalid_request_error · HTTP 400
A parameter was the wrong shape, usually a malformed id.
invalid_cursor
invalid_request_error · HTTP 400
The pagination cursor is not one we issued. Start the list again.
request_too_large
invalid_request_error · HTTP 413
The body exceeded the hard limit.
resource_not_found
not_found_error · HTTP 404
No such object in THIS workspace. A resource belonging to another workspace returns this too, deliberately: distinguishing them would let you discover which ids exist.
conflict
conflict_error · HTTP 409
The resource exists and the request is well formed, but its current state forbids the action. Unlike a 400, this may succeed later. Common causes:
- A write conflict. Someone changed a file since you read it.
details.reasonisrevision_conflict, anddetails.current_revisionis the revision to read, anddetails.pathslists each file with the hash you expected and the hash found. - A publish against a stale review, or a build that cannot go live. Review again, and read
details.blockers. - A plan limit, such as too many drafts or a domain beyond the plan. The message names the limit, and
action_urlthe page that lifts it.
result_not_ready
conflict_error · HTTP 409
The work has not finished, for example a site that is still being created. Wait a few seconds rather than retrying immediately.
idempotency_key_reused
conflict_error · HTTP 409
The Idempotency-Key you sent to an endpoint that accepts one was already used for a different request in this workspace. Nothing was done. Use a new key for new work; a repeat of the same request with the same key returns the first answer instead.
insufficient_credits
invalid_request_error · HTTP 402
Not enough credits. Stop and tell a human; retrying will not help.
request_too_large_for_plan
invalid_request_error · HTTP 422
The body is within the hard limit but above what this plan allows.
result_expired
not_found_error · HTTP 410
The result was deleted by the retention policy. It is not coming back.
rate_limited
rate_limit_error · HTTP 429
Too many requests. Wait for Retry-After before trying again. The same wait is in the body, as data: details.retry_after_seconds and details.retry_at (an ISO date), also in MCP tool errors and in the CLI’s JSON output.
internal_error
api_error · HTTP 500
Something failed on our side. Quote the request_id.
service_unavailable
api_error · HTTP 503
A dependency is down or in maintenance. Retry after a delay.