Errors

Every error is JSON with a single human-readable `error` field and a meaningful HTTP status. Status codes tell your code what to do; the message tells you what went wrong.

The API uses conventional HTTP semantics: 2xx means your request succeeded, 4xx means the request itself needs fixing (retrying the identical request will fail identically, except 429), and 5xx means something failed on our side and a retry is reasonable.

Error shape (always this)
{ "error": "Unknown symbol." }

Status codes

StatusWhenExample message
401Missing, invalid or revoked API keyInvalid or revoked API key.
403Valid key, but no active Developer planThe API requires an active Developer plan.
404Unknown symbol, unknown alert id, unknown ranking category, or (on densities) no data for that pair right nowUnknown symbol.
422A parameter failed validation: bad interval, metric outside the whitelist, symbol list too long, malformed alert conditionInvalid metric. Allowed: SCORE, VOL_RATIO, TR_RATIO, RET_ZSCORE
429Burst limit or daily quota exceeded (see Rate limits)Rate limit exceeded: 120 requests per minute.
5xxEngine or infrastructure fault on our side—

Validation messages are self-documenting

Where a parameter has a fixed set of legal values, the 422 message enumerates them. This is deliberate: your logs contain the fix, not just the failure. For example, asking rankings for a metric that belongs to a different category:

The error names every allowed value
curl "https://osiristrader.com/api/v1/rankings/volsurge?metric=NATR" \
  -H "Authorization: Bearer osk_YOUR_KEY"

HTTP/1.1 422 Unprocessable Content
{ "error": "Invalid metric. Allowed: SCORE, VOL_RATIO, TR_RATIO, RET_ZSCORE" }

Empty is not an error

Distinguish "request failed" from "nothing to report". A young listing may legitimately have no levels yet; a quiet pair may carry no density walls this second; a metric family may be absent for a symbol during its first minutes of trading. In these cases you get a 200 with an empty data: the request worked, the market state is simply empty. Only /v1/densities/{symbol} answers 404 for "no walls right now", because a wall snapshot for that pair genuinely does not exist at that moment.

Retry guidance

  • 429: wait exactly Retry-After seconds, then retry. Never tight-loop.
  • 5xx: retry with exponential backoff and jitter (e.g. 1 s, 2 s, 4 s… capped at 30 s). All v1 GET endpoints are idempotent and safe to retry; POST /v1/alerts is not idempotent, so on a 5xx there, list your alerts before re-creating to avoid duplicates.
  • 4xx other than 429: do not retry unchanged; fix the request. These are deterministic.
If you believe you are receiving a 5xx or an inconsistent payload repeatedly, include the full request path, your key's prefix only (never the whole key), the response body and a timestamp when contacting support; that tuple is enough for us to find the request in our logs.