# Error Handling

## Error envelope

All errors use the same JSON shape:

{
  "error": {
    "code": "NOT_FOUND",
    "message": "payment 01927b3e-... not found"
  }
}

## Error codes

Code
HTTP
Description

NOT_FOUND
404
Resource does not exist

INVALID_REQUEST
400
Malformed body or invalid parameter

UNAUTHORIZED
401
Missing or invalid API key

FORBIDDEN
403
Valid key but insufficient scope

MISSING_SCOPE
403
Key lacks the required scope

CONFLICT
409
Duplicate idempotency key with different payload

RATE_LIMITED
429
Too many requests

INSUFFICIENT_FUNDS
400
Ledger balance too low

IDEMPOTENCY_MISMATCH
400
Same key, different payload

INTERNAL
500
Server error — safe to retry

## Retry guidance

HTTP status
Retry?

400
No — fix the request

401
No — check your API key

403
No — check scopes

404
No — resource missing

409
No — inspect the conflict

429
Yes — use Retry-After header

500
Yes — exponential backoff

502 / 503 / 504
Yes — exponential backoff

## Idempotency conflicts

If you get IDEMPOTENCY_MISMATCH (409), the key was already used with a different payload. Generate a new key for the new request — the original request may or may not have succeeded.