Error Codes
Every Adjudon API response follows the same envelope shape. Failures
return a stable string code you can branch on; the human-readable
error field is for humans, the code is for machines. Tested
against API version v1.
The error envelope
{
"success": false,
"error": "Entry not found",
"code": "NOT_FOUND"
}
{
"success": true,
"data": { /* resource-shaped */ }
}
The error string may change for clarity; the code is a stable
machine identifier safe to branch on.
HTTP status families
| Status | Meaning | Notes |
|---|---|---|
2xx | Success | 201 = trace approved; 202 = trace flagged for review (held, not blocked) |
4xx | Client error | Authentication, validation, plan-gate, rate-limit |
5xx | Server error | Safe to retry with exponential backoff |
The trace-ingestion endpoint (POST /api/v1/traces) is the one place
where 2xx carries product semantics: 201 approved, 202 held for
review, and 403 ADJ_BLOCKED_BY_POLICY when blocked. See
Traces API.
Authentication errors (401 / 403)
| Code | HTTP | Cause |
|---|---|---|
NO_TOKEN | 401 | Authorization header missing |
INVALID_API_KEY_FORMAT | 401 | API key does not start with adj_live_ or adj_test_ |
INVALID_API_KEY | 401 | Key not found or revoked |
TOKEN_REVOKED | 401 | Session blacklisted (sign in again) |
SESSION_REVOKED | 401 | Explicit logout has invalidated the session |
TOKEN_VERIFICATION_FAILED | 401 | JWT signature failed |
UNAUTHORIZED_NO_USER | 401 | JWT valid but user record gone |
FORBIDDEN | 403 | Authenticated but lacks the role for this operation |
UPGRADE_REQUIRED | 403 | Feature requires a higher plan tier; response data carries currentPlan, requiredPlans, feature |
Validation and resource errors (400 / 404 / 409)
| Code | HTTP | Cause |
|---|---|---|
VALIDATION_ERROR | 400 | Request body or query failed schema validation |
INVALID_INPUT | 400 | A specific field is malformed |
INVALID_OPERATION | 400 | The operation is well-formed but illegal in the current state |
NOT_FOUND | 404 | The requested resource does not exist or is owned by another organization |
ALREADY_EXISTS | 409 | A duplicate would be created (e.g., re-inviting the same email) |
EXPIRED | 410 | The token, invitation, or transient resource has expired |
Rate-limit errors (429)
| Code | HTTP | Cause |
|---|---|---|
RATE_LIMIT_EXCEEDED | 429 | Per-key or per-agent rate limit hit; response data carries limit and windowSeconds |
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
{
"success": false,
"error": "Agent rate limit exceeded (60 requests per minute). Try again later.",
"code": "RATE_LIMIT_EXCEEDED",
"data": { "limit": 60, "windowSeconds": 60 }
}
import time, requests, os
def post_trace(payload, attempt=0):
r = requests.post(
"https://api.adjudon.com/api/v1/traces",
json=payload,
headers={"Authorization": f"Bearer {os.environ['ADJUDON_API_KEY']}"},
)
if r.status_code == 429 and attempt < 5:
time.sleep(2 ** attempt) # 1, 2, 4, 8, 16 seconds
return post_trace(payload, attempt + 1)
r.raise_for_status()
return r.json()
See Rate Limits for limits per plan tier.
Server errors (5xx)
| Code | HTTP | Cause |
|---|---|---|
INTERNAL_ERROR | 500 | Generic server fault; safe to retry |
CONFIG_ERROR | 500 | Server-side misconfiguration; not retryable until operator intervenes |
Resource-specific *_FAILED codes | 500 | Per-resource handler error (e.g., HASH_CHAIN_VERIFY_FAILED, INCIDENT_CREATE_FAILED); listed on each resource's reference page |
5xx responses are safe to retry with exponential backoff. Use the
SDK's built-in retry helper or the Python pattern shown above.
Resource-specific codes
Every D1 resource page lists its 4xx / 5xx codes inline (e.g.,
HASH_CHAIN_VERIFY_FAILED, ADJ_BLOCKED_BY_POLICY,
FRIA_TRANSITION_FAILED, INCIDENT_CREATE_FAILED). See
Hash Chain,
Traces,
FRIA,
Incidents.
Stability and honesty
- The
codefield is a stable contract: new codes may be added; existing codes are not renamed without a 90-day deprecation notice in the Changelog. Theerrorstring may change for clarity and is not part of the contract. - The envelope today is
{ success, error, code }. Arequest_idfield for triage correlation is on the Q3 2026 roadmap; until then, the time of failure plus thecodeis the triage handle. - Unknown codes are coerced to
INTERNAL_ERRORserver-side as a fail-open guard.
See also
- REST API Reference — the top-level index
- Rate Limits — per-plan limits and retry guidance
- Authentication — key formats and rotation