Errors
How 0fra reports errors and what each code means.
Every error response uses this shape:
{
"error": {
"code": "merchant_not_ready",
"message": "merchant wallet not bound for chain",
"request_id": "..."
}
}request_id is the same value 0fra logs on its side — quote it when contacting support.
Codes
| Code | HTTP | Meaning | What to do |
|---|---|---|---|
invalid_request | 400 | Body validation failed | Inspect details; fix shape |
unauthorized | 401 | Missing / wrong API key or expired session | Re-authenticate |
signature_invalid | 401 | Webhook HMAC mismatch, or merchant attestation invalid | Recheck secret + raw body bytes |
rate_limited | 429 | Too many requests in window | Backoff + retry |
order_state_conflict | 409 | Operation not allowed in current state | Read state via GET first |
duplicate_idempotency_key | 409 | Same Idempotency-Key reused with a different body | Use a fresh key |
insufficient_reserve | 422 | Refund exceeded merchant reserve and platform absorb is disabled | Wait for reserve to grow, or override |
chain_reorg_pending | 423 | Chain hasn't met confirmation depth yet | Retry in N seconds |
settlement_not_ready | 423 | Settlement batch awaiting confirmation | Retry |
merchant_not_ready | 422 | Merchant exists but isn't active or has no wallet bound | Onboard the merchant |
fee_config_invalid | 422 | Platform's fee config or service config missing for this chain | Contact support |
not_found | 404 | Resource doesn't exist or doesn't belong to your platform | — |
internal_error | 500 | We screwed up | Retry; capture request_id and tell us |
Retry strategy
For 5xx and 429:
delay = min(2 ** attempt + jitter, 60s)For 4xx (other than 429): don't retry — fix the request.
For 423 (chain_reorg_pending / settlement_not_ready): retry in 5–30 s.
Logging
We log every API request server-side with the request_id. If something looks wrong:
- Capture the
request_idfrom your error response - Email support@0fra.dev with that id + your platform name
- We can pull the full server-side trace