Errors
Hannu returns RFC 9457 problem+json — a stable code, a safe detail, and a request_id — so your agent can branch on the exact reason.
Every error is an RFC 9457 application/problem+json document. It names the exact control that failed with a stable machine code, so your agent can branch reliably instead of parsing prose.
The shape
{
"type": "https://docs.hannu.africa/errors/insufficient_escrow_balance",
"title": "Wallet balance is below the amount this task would lock",
"status": 402,
"code": "insufficient_escrow_balance",
"detail": { "required": "303750", "available": "120000" },
"request_id": "req_9c1"
}code— the stable identifier to branch on. It never changes for a given condition.title— the human-readable message for this occurrence. Read it for display, not for branching.status— the HTTP status.detail— a structured object of condition-specific fields (here,requiredandavailable), present only when the error carries specifics. Never contains PII or internal state. Read the numbers you need from it; read the human message fromtitle.request_id— quote this to support to trace any request.
Branch on code, not status
Several conditions share a status (three different 403s, for example). Always switch on code.
Handling patterns
rate_limited(429) — back off and retry after theRetry-Afterheader.idempotency_conflict(409) — you reused a key with a different body; use a fresh key.insufficient_escrow_balance(402) — fund the wallet, then retry.internal(500) — safe to retry; quote therequest_idif it persists.
The full catalogue
Every code, its status, and its meaning is on the Errors reference.