On this page
Error Handling
Every error response from Artery is wrapped in a structured envelope and
tagged with an X-Request-Id header for log lookup.
Error envelope
json{
"error": {
"code": "unauthenticated",
"message": "Missing Authorization header",
"requestId": "req_5a6604f3-7c32-42da-ba70-3df3ca864cfc"
}
}| Field | Meaning |
|---|---|
error.code | Stable Artery enum (see table below) — branch on this, not on HTTP status |
error.message | Human-readable summary, safe to surface to end-users |
error.requestId | Per-request id, mirrored on the X-Request-Id response header |
error.provider | (Upstream errors only) Which adapter raised the error |
error.upstream.status | (Upstream errors only) HTTP status returned by the provider |
error.upstream.body | (Upstream errors only) Raw provider error body |
Error codes
| Code | HTTP | Meaning |
|---|---|---|
unauthenticated | 401 | No / malformed Bearer token |
forbidden_scope | 403 | Token lacks the required scope |
rate_limited | 429 | Artery quota exceeded — see rate limits |
validation_failed | 400 / 422 | Request shape invalid (Zod path errors in message) |
not_found | 404 | Unknown route or unknown resource id |
upstream_unauthorized | 401 / 403 | Provider rejected your provider credentials |
upstream_rate_limited | 429 | Provider rate-limited Artery (transient) |
upstream_unavailable | 502 / 503 / 504 | Provider 5xx or timeout |
internal_error | 500 | Artery bug — please file with requestId |
Request id propagation
Every response carries X-Request-Id:
bashcurl -i https://api.artery.questflow.ai/v1/polymarket/markets \
-H "Authorization: Bearer $TOKEN"
# → X-Request-Id: req_5a6604f3-7c32-42da-ba70-3df3ca864cfcIf you send your own X-Request-Id (any non-empty string ≤128 chars),
Artery echoes it back instead of minting a new one — useful for stitching
distributed traces.
bashcurl -i -H "X-Request-Id: my-trace-abc-123" https://api.artery.questflow.ai/health
# → X-Request-Id: my-trace-abc-123Provider-specific gotchas
Polymarket Cloudflare 403 — calling Polymarket without Artery's Chrome 131 UA returns 403 cf_chl_rc_iuam. Artery's transport layer handles this. If you bypass Artery, replicate the UA +
Origin + Referer headers yourself.
Kalshi 429 without Retry-After — Kalshi's token-bucket limiter returns 429 with no retry
hint. Artery retries with exponential backoff (100ms / 250ms / 500ms / 1s, jitter ±20%) up to 4
attempts before surfacing.
Hyperliquid cooldown error — placing > 1 order per 50ms returns
{ status: "err", response: "Cooldown" }. Artery does not retry
trade errors automatically — that's the caller's decision.
Retry policy (transport layer)
Artery's @artery/transport retries idempotent calls (GET) on
network errors and 5xx:
| Attempt | Delay |
|---|---|
| 1 | 0 ms |
| 2 | 100 ms ± 20% |
| 3 | 250 ms ± 20% |
| 4 | 500 ms ± 20% |
| 5 | 1000 ms ± 20% |
After attempt 5 the error surfaces with code: upstream_unavailable. POST
and DELETE are not retried — the caller decides idempotency.
See also
- Rate limits — quotas + 429 + Retry-After
- Authentication — scope rules