API reference
Error codes
2 min read
The API uses standard HTTP status codes. The body always carries { success: false, error: "...", details? }.
2xx — success
| Code | Meaning |
|------|---------|
| 200 | Read succeeded; body is the resource. |
| 201 | Resource created (e.g. bookmark added). Idempotent operations also return 201 even when no row was inserted. |
| 202 | Job accepted; poll the returned jobId for completion. |
4xx — client errors
| Code | Meaning | What to do |
|------|---------|------------|
| 400 | Validation failed | Look at details.fieldErrors; fix the input shape. |
| 401 | Unauthenticated | Sign in or pass Authorization: Bearer .... |
| 403 | Authenticated but not allowed | The action requires a higher tier (Pro/Team) or a different scope. |
| 404 | Not found, or you don't own it | We return 404 for owner-only resources you don't own — same response as missing resources to avoid leaking existence. |
| 409 | Conflict | E.g. trying to create a resource that already exists with a different shape. Rare. |
| 429 | Rate limit hit | Read Retry-After; wait; retry. See Rate limits. |
5xx — server errors
| Code | Meaning | What to do |
|------|---------|------------|
| 500 | Internal server error | Retry once; if it persists, file an issue with the request id from X-Request-Id. |
| 503 | Service temporarily unavailable | Often a Redis or DB blip. Exponential backoff up to 5 min, then file an issue. |
Validation error shape
POST /api/jobs with a malformed body:
HTTP/1.1 400 Bad Request
{
"success": false,
"error": "Invalid job payload",
"details": {
"formErrors": [],
"fieldErrors": {
"input.url": ["Invalid URL"]
}
}
}details.fieldErrors is keyed by the dotted path so you can route the error back to the right form field.
Idempotency
Mutating endpoints (POST /api/bookmarks/:slug, POST /api/library/:slug/reviews) are idempotent — repeating the same request with the same body produces the same final state. Safe to retry on network failure.