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": "Unknown symbol." }Status codes
| Status | When | Example message |
|---|---|---|
401 | Missing, invalid or revoked API key | Invalid or revoked API key. |
403 | Valid key, but no active Developer plan | The API requires an active Developer plan. |
404 | Unknown symbol, unknown alert id, unknown ranking category, or (on densities) no data for that pair right now | Unknown symbol. |
422 | A parameter failed validation: bad interval, metric outside the whitelist, symbol list too long, malformed alert condition | Invalid metric. Allowed: SCORE, VOL_RATIO, TR_RATIO, RET_ZSCORE |
429 | Burst limit or daily quota exceeded (see Rate limits) | Rate limit exceeded: 120 requests per minute. |
5xx | Engine 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:
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 exactlyRetry-Afterseconds, 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/alertsis not idempotent, so on a 5xx there, list your alerts before re-creating to avoid duplicates.4xxother than 429: do not retry unchanged; fix the request. These are deterministic.
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.