API Reference
Errors
Standard error response format, HTTP status codes, and field-level validation errors.
Error envelope
All error responses use a consistent JSON envelope:
Error response
{
"type": "https://docs.anankelabs.net/errors/validation-failed",
"title": "Validation failed",
"status": 422,
"detail": "One or more fields failed validation.",
"traceId": "00-abc123...-01",
"errors": {
"recipientEmail": ["Must be a valid email address."],
"fields[0].key": ["Field key is required."]
}
}The envelope follows RFC 7807 (Problem Details for HTTP APIs). The traceId field maps to the OpenTelemetry trace for the request — include it in support requests.
HTTP status codes
| Status | Meaning | When returned |
|---|---|---|
200 | OK | Successful read or update. |
201 | Created | Resource successfully created. |
204 | No Content | Successful delete. |
400 | Bad Request | Malformed JSON, missing required fields. |
401 | Unauthorized | Missing or invalid API key. |
403 | Forbidden | Valid key but insufficient permissions. |
404 | Not Found | Resource does not exist or belongs to a different tenant. |
409 | Conflict | Duplicate resource (e.g., duplicate issuance check). |
422 | Unprocessable Entity | Field-level validation failures. |
429 | Too Many Requests | Rate limit exceeded. |
500 | Internal Server Error | Unexpected server failure. |
503 | Service Unavailable | Downstream dependency unavailable. |
Validation errors
When the API returns 422, the errors object contains field-level messages keyed by the JSON path of the invalid field:
Validation error example
{
"type": "https://docs.anankelabs.net/errors/validation-failed",
"title": "Validation failed",
"status": 422,
"errors": {
"recipientName": ["Must not be empty."],
"fields[0].value": ["Exceeds maximum length of 500 characters."],
"pdf": ["File size must not exceed 10 MB."]
}
}Display these in your UI next to the corresponding form fields. The SDK's AnankeError class exposes them via error.fieldErrors.
Error codes
Some errors include a machine-readable code field for programmatic handling:
| Code | Description |
|---|---|
DUPLICATE_ISSUANCE | An issuance with the same external ID or content hash already exists. |
TEMPLATE_ARCHIVED | The referenced template is archived and cannot be used for new issuances. |
LIFECYCLE_INVALID | The requested lifecycle transition is not valid from the current state. |
BULK_JOB_FAILED | The bulk job encountered unrecoverable errors during processing. |
VERIFICATION_NOT_FOUND | No document or Ananke TCode matches the submitted reference or hash. |
PDF_TOO_LARGE | The uploaded PDF exceeds the maximum allowed size. |
RATE_LIMITED | The request was rejected due to rate limiting. |
Retry guidance
| Status | Retry? | Strategy |
|---|---|---|
400, 401, 403, 404, 409, 422 | No | Fix the request. These are client errors that won't resolve on retry. |
429 | Yes | Wait for the duration in the Retry-After header, then retry. |
500 | Maybe | Retry once with exponential backoff. If it persists, contact support. |
503 | Yes | Retry with exponential backoff (1s → 2s → 4s, max 3 attempts). |
SDK automatic retry
import { AnankeClient } from "@ananke/sdk";
const client = new AnankeClient({
apiKey: process.env.ANANKE_API_KEY!,
// SDK retries 429 and 5xx automatically
// Default: 3 attempts with exponential backoff
});