code is a stable machine-readable string — switch on it in your code. message is human-readable and may change wording over time, do not parse it.
HTTP status code mapping
| HTTP | Meaning |
|---|---|
| 200 | Success — success: true, payload in data |
| 400 | Validation error — request shape or parameter invalid |
| 401 | Missing or invalid X-Api-Key |
| 403 | Key valid but lacks permission for this resource (typically wrong partner) |
| 404 | Slug or resource not found |
| 409 | Idempotency conflict (webhooks only) |
| 429 | Rate limit exceeded — see Retry-After header |
| 5xx | Internal error — safe to retry with exponential backoff |
Error codes
Authentication & rate-limiting
| Code | HTTP | When | Remediation |
|---|---|---|---|
missing_api_key | 401 | X-Api-Key header absent | Add header |
invalid_api_key | 401 | Header present but key not recognized | Check key, regenerate in Portal |
revoked_api_key | 401 | Key was revoked | Issue a new key |
rate_limited | 429 | Per-key request budget exceeded | Honor Retry-After, then retry |
Product / slug
| Code | HTTP | When | Remediation |
|---|---|---|---|
not_found | 404 | Slug does not exist | Check spelling against GET /products |
not_owned | 403 | Slug exists but belongs to a different partner | Use a slug returned by your own GET /products |
engine_not_deployed | 409 | Product is still in pending_deploy status | Wait for status to flip to active (typically under 5 min); webhook product.deployed fires when ready |
product_paused | 503 | Product status is paused | Don’t surface a deposit CTA; poll /health for resume |
product_deprecated | 410 | Product is deprecated — withdrawals only | Hide deposit, allow redeem |
Position / address
| Code | HTTP | When | Remediation |
|---|---|---|---|
invalid_address | 400 | Address is not a 42-char 0x-prefixed hex string | Validate before submitting |
chain_not_supported | 400 | Address is checksum-mismatched or product chain doesn’t support address format | Use the chain_id from the product response |
Yield calc / fee stats
| Code | HTTP | When | Remediation |
|---|---|---|---|
invalid_amount | 400 | amount non-numeric, ≤ 0, or above 2^256 | Validate before sending |
range_too_large | 400 | start_date/end_date span > 365 days | Split into multiple requests |
invalid_days | 400 | days not one of 7, 30, 180 | Use a supported value |
Webhooks (inbound — partner → Barker)
| Code | HTTP | When | Remediation |
|---|---|---|---|
signature_mismatch | 401 | HMAC verification failed | Check the inbound secret; ensure you signed the raw body |
missing_idempotency_key | 400 | Idempotency-Key header absent | Add header |
unknown_event | 400 | event_type not in the allowlist | See Webhooks → event types |
idempotency_replay | 200 | Same key seen before — returned with duplicate: true | No action; this is a successful no-op |
Server-side
| Code | HTTP | When | Remediation |
|---|---|---|---|
internal_error | 500 | Unexpected server error | Retry with exponential backoff (start at 1s, max 5 attempts) |
chain_rpc_unavailable | 503 | Upstream RPC down — affects /position, /health | Show cached value if available; surface “live data temporarily unavailable”; retry after 30s |
Retry policy
| Status | Should you retry? | Strategy |
|---|---|---|
| 4xx (except 429) | No — request is invalid, retrying won’t help | Surface to user / fix code |
| 429 | Yes | Honor Retry-After; if absent, exponential backoff starting at 2s |
| 5xx | Yes | Exponential backoff: 1s, 2s, 4s, 8s, 16s; cap at 5 attempts |
GET endpoints are idempotent and safe to retry. The inbound webhook endpoint is idempotent via the Idempotency-Key header.
What’s next
- Rate limits — per-key budgets and
Retry-Aftersemantics - Webhooks — inbound and outbound event handling