Documentation
Errors
Errors are structured: { "success": false, "error": { "code": "ERR_…", "message": "…" } }. Branch on error.code, never on the human message — codes are stable, strings are not.
The full table
| HTTP | Code | Meaning and fix |
|---|---|---|
| 401 | ERR_UNAUTHORIZED | Missing, invalid or revoked token. Revoked keys fail with exactly this — mint a new key. |
| 403 | ERR_FORBIDDEN | Permission denied: a read-only key sent a write, or a key was used outside its database. |
| 403 | ERR_QUOTA_EXCEEDED | Plan limit reached (databases, keys or bytes). Clean up or expect the admin to raise the ceiling. |
| 404 | ERR_NOT_FOUND | Unknown or expired key / unknown database. Treat as a miss — same semantics as Redis nil. |
| 409 | ERR_CONFLICT | Rule collision — typically minting a second key for a database that already has one active. |
| 413 | ERR_PAYLOAD_TOO_LARGE | Value above the value-size quota. |
| 422 | ERR_VALIDATION | Strict body validation: wrong field, wrong type, unknown extra field. Fix the payload shape. |
| 429 | ERR_RATE_LIMITED | Too many requests. Read Retry-After, back off, retry with jitter. |
| 503 | ERR_SERVICE_UNAVAILABLE | Backing store unreachable. Retry with exponential backoff. |
Retrying without making it worse
- 429 / 503 are the retryable classes: honor
Retry-After, add jitter, cap retries. Everything else means "fix the request", not "send it again". - 404 is a miss, not an error to escalate: a key that hit its TTL answers 404 by design (see TTL policy).
- Writes are atomic over pipelines — a rejected batch leaves no partial state, so re-sending a failed batch is always safe.
- 429 flood guard: per-database in-flight caps reject instantly rather than queueing; keep small client connection pools instead of one giant unbounded fan-out.