Error Handling

The Madless API uses conventional HTTP status codes and returns all errors in the RFC 9457 Problem Details format. Every error response includes a machine-readable type, a human-readable title, the HTTP status code, and a detailed description of what went wrong.

Error Shape

Every error response uses application/problem+json as the content type. The instance field echoes the request path for easier debugging.

{
  "type": "https://docs.madless.com/errors#not_found",
  "title": "not found",
  "status": 404,
  "detail": "Concept cpt_abc123 not found.",
  "instance": "/api/v1/canvas/cpt_abc123"
}

Validation errors (400) include an additional errors array with one entry per failed field (detail, pointer, code) from Zod schema validation.

Error Types

The type field is a stable URL that names the error class and deep-links here, e.g. https://docs.madless.com/errors#validation_error. Branch on it — never on detail, which is human-readable prose and may change.

TypeStatus
validation_error400
unauthorized401
password_required401
ai_credits_exhausted402
ai_usd_budget_exhausted402
ai_platform_budget_exhausted402
ai_daily_usd_cap_exhausted402
forbidden403
password_incorrect403
not_found404
method_not_allowed405
conflict409
precondition_failed412
too_large413
unsupported_media_type415
unprocessable_entity422
rate_limited429
server_error500
not_implemented501
service_unavailable503
ai_budget_check_failed503

Common Status Codes

CodeMeaning
200OK
201Created
204No Content
400Bad Request
401Unauthorized
403Forbidden
404Not Found
409Conflict
422Unprocessable Entity
429Rate Limited
500Server Error

Rate Limiting

When you exceed the rate limit for an endpoint, the API returns 429 Too Many Requests. Every response includes headers to help you manage your request budget:

HeaderDescription
Retry-AfterSeconds to wait before retrying the request.
X-RateLimit-LimitMaximum number of requests allowed per window.
X-RateLimit-RemainingRequests remaining in the current window.
X-RateLimit-ResetUnix timestamp when the current window resets.

Idempotency

All write endpoints (POST, PUT, PATCH) support idempotent requests. Include an Idempotency-Key header with a unique identifier (a UUID works well). If the server has already processed a request with the same key, it returns the original response without executing the operation again.

curl -X POST 'https://acme.madless.com/api/v1/canvas' \
  -H 'Authorization: Bearer mad_sk_abc123...' \
  -H 'Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000' \
  -H 'Content-Type: application/json' \
  -d '{
    "title": "Compound Intelligence",
    "notes": "A knowledge graph that compounds over time."
  }'

Keys expire after 24 hours. Using the same key with a different request body returns 409 Conflict.

Retry with backoff

For 429 and 5xx errors, use exponential backoff with jitter. Always respect the Retry-After header when present. Do not retry 4xxerrors other than 429 — they indicate a problem with the request itself that must be fixed before retrying.