Errors
Every error response uses the same envelope:
{
"error": {
"code": "validation_error",
"message": "Unsupported chainId 4242. Supported: 1135, 8453, 56",
"details": [
{ "path": "chainId", "message": "Expected number, received string" }
]
}
}
details is present on validation errors generated from Zod schemas; it
contains a list of field-level issues so you can render them inline in a
form.
Status code → code mapping
| HTTP | code | When |
|---|---|---|
| 400 | validation_error | Request body / query / params failed schema validation, OR the request reached an internal validator (e.g. unsupported chainId, malformed address). |
| 401 | unauthorized | Authorization: Bearer … missing, malformed, or rejected by Rift. |
| 403 | forbidden | Reserved — none of the current public endpoints use it. |
| 404 | not_found | Resource doesn't exist (e.g. event ID not on this chain). |
| 409 | conflict | Reserved. |
| 429 | rate_limited | Reserved. |
| 500 | internal_error | Unhandled server-side failure. Message is generic — see server logs for details. |
| 502 | upstream_error | Downstream RPC, pricing engine, or Rift API returned an error. message includes the upstream's reason. |
| 503 | service_unavailable | Downstream is unreachable (network failure, service down). |
Typical errors by endpoint
Reads
| Endpoint | Likely error | Why |
|---|---|---|
Any /v1/hedge/events/:chainId/:id | 404 not_found | ID doesn't exist |
Any :chainId path | 400 validation_error "Unsupported chainId X" | Chain ID isn't in the catalog |
| Any address-shaped path param | 400 validation_error | Doesn't match ^0x[0-9a-fA-F]{40}$ |
| Any bytes32 path param (proposalId, nonce) | 400 validation_error | Doesn't match ^0x[0-9a-fA-F]{64}$ |
Calldata builders
| Endpoint | Likely error | Why |
|---|---|---|
POST /v1/tx/erc20/approve | 400 validation_error "amount must be non-negative" | Negative amount |
POST /v1/tx/hedge/create-event | 400 validation_error | Missing required field, bad enum value, etc. |
POST /v1/tx/governance/diamond-cut | 400 validation_error "action must be 0/1/2" | Bad facet action enum |
Broadcast
| POST /v1/tx/broadcast | 400 validation_error | signedTx isn't 0x-hex |
| | 502 upstream_error "nonce too low" | RPC rejected the tx |
Pricing
| POST /v1/pricing/quote | 400 validation_error | Engine rejected (e.g. leverage > 100×, unsupported pair) |
| | 502 upstream_error | Engine errored internally |
| | 503 service_unavailable | Engine unreachable |
Recommended client handling
async function call(url: string, init?: RequestInit) {
const r = await fetch(url, init);
const body = await r.json();
if (!r.ok) {
const err = body.error;
// err.code is one of the documented codes above
// err.message is safe to surface in a UI
// err.details (if present) is field-level for form rendering
throw Object.assign(new Error(err.message), { code: err.code, status: r.status, details: err.details });
}
return body.data;
}
err.code is the value to switch on for retry / display logic — it's
guaranteed stable across versions, unlike the human message.