General
Errors
Every failure returns the same shape with a stable string code. Branch on the code; the message is for whoever reads the log.
{
"error": {
"code": "insufficient_scope",
"message": "This key is not granted mail.send.",
"details": [ { "field": "required_scope", "value": "mail.send" } ],
"request_id": "req_..."
}
}
Codes are permanent
A published code is never renamed, never reused for a different condition, and never removed within a major version. New codes may be added, so treat an unrecognised one as its HTTP status.
Authentication
The key was missing, malformed, or is not one of ours.
| Code | Status | What it means |
|---|---|---|
missing_credential |
401 | No Authorization header was sent. |
wrong_credential_type |
401 | Something other than a veruapis key was presented, such as a VeruSuite session token or personal API token. Those do not work here. |
invalid_token |
401 | The key does not exist or its secret does not match. |
token_expired |
401 | The key passed its expiry date. Create a new one. |
token_revoked |
401 | The key was revoked. |
grant_revoked |
401 | The authorization behind the key was withdrawn: the person who created it signed out everywhere, changed their password, or was removed. Retrying will not help; a new key is needed. |
tenant_inactive |
401 | The workspace is suspended. |
Permissions
The key is valid but is not allowed to do this.
| Code | Status | What it means |
|---|---|---|
insufficient_scope |
403 | The key was not granted a permission this endpoint requires. The missing one is named in details. |
admin_scope_required |
403 | The endpoint needs a workspace admin permission, which only an administrator can put on a key. |
plan_required |
403 | The workspace's plan does not include this app. A new key will not help; the plan has to change. |
resource_forbidden |
403 | The person the key acts as has no access to this particular item. |
Request problems
| Code | Status | What it means |
|---|---|---|
malformed_request |
400 | The body is not valid JSON. |
unknown_parameter |
400 | An unrecognised query parameter was sent. Unknown parameters are rejected rather than ignored, so a typo in a filter cannot silently return the wrong data. |
invalid_parameter |
400 | A parameter was present but unusable. |
invalid_id |
400 | An identifier had the wrong prefix. The expected one is named in details. |
invalid_cursor |
400 | The pagination cursor could not be decoded. |
idempotency_key_required |
400 | A write was sent without an Idempotency-Key header. |
validation_error |
422 | The request was well formed but semantically invalid. Field-level problems are in details. |
payload_too_large |
413 | The body exceeded the documented maximum. |
Conflicts
| Code | Status | What it means |
|---|---|---|
idempotency_key_reuse |
409 | The same idempotency key was reused with a different body. |
idempotency_key_in_flight |
409 | An earlier request with this key has not finished. Retry shortly. |
version_conflict |
409 | If-Match did not match the current version. |
state_conflict |
409 | The item is in a state that forbids this operation. |
already_exists |
409 | Something with that name or address already exists. |
cursor_expired |
410 | The pagination position is no longer valid. Start the listing again. |
Limits
Two different problems with two different fixes: a burst, and a plan allowance.
| Code | Status | What it means |
|---|---|---|
rate_limited |
429 | Too many requests too quickly. Back off using the RateLimit headers. |
upstream_rate_limited |
429 | A backend refused. The RateLimit headers do not describe this limit. |
quota_exceeded |
429 | The plan's request allowance is spent. Waiting for the reset or upgrading are the only fixes. |
Failures
A 500 is always our fault. Anything else names the service that failed, so you can tell your own users what is happening.
| Code | Status | What it means |
|---|---|---|
internal_error |
500 | Something went wrong on our side. The request id identifies it in our logs. |
upstream_error |
502 | A backend returned something unusable. |
upstream_unavailable |
503 | A backend is unreachable. The backend is named in the response. |
upstream_timeout |
504 | A backend took too long. |