Error format
All errors return a JSON body witherror and message. Branch on error, a
stable slug; message is prose for humans and may change at any time, so never
parse it. Errors are never wrapped in the data / meta envelope used by
successful responses, on any endpoint, so response.json()["error"] is safe
everywhere. Some errors add hint fields that let a client or an agent correct itself:
HTTP status codes
Error codes
unauthorized (401)
- The
X-API-Keyheader is present - The key is correct (no copy-paste whitespace)
- The key hasn’t been revoked
- The key starts with
gex_sk_
unauthorized covers two cases: no credential was supplied, and a credential
was supplied but did not resolve to a user — the latter returns
"Could not resolve a user identity from the supplied credentials." Both share
one code deliberately, so you only need a single branch.subscription_required (403)
current_tier shows your current tier. Get API access.
market_not_in_plan (403)
SPX or QQQ,
and the TradFi plan on BTC. The Complete plan covers both.
Only endpoints taking a
<coin> path parameter can return this. The discovery
endpoints (/exchanges, /coins) list availability rather than market data,
and are never gated this way.
To fix it, add the market to your subscription, or request a symbol from a
market you already have.
invalid_exchange (400)
bybit, deribit, okx, derive, binance,
all / combined, or a subset like deribit+derive; valid_exchanges lists
what is currently available. See Markets and exchanges.
invalid_pair (400)
tradfi with a crypto coin.
invalid_expiration (400)
nearest_expirations holds up
to five ISO dates closest to the one you sent (the earliest five if the value is
not a date). Use TOTAL, or pick one from
nearest_expirations or /expirations.
invalid_param (400)
view must be full or levels
(valid_values), and range_pct must be in (0, 50] (max_value). On the history
endpoints it also covers an unparseable start, end, at, date or cursor,
start after end, a year outside 2020 to 2100, an unknown granularity or
file (valid_values), and ?compare= other than 1d, 7d, 30d or used
with a single expiration.
unsupported_coin (404)
{exchange}/{coin} endpoint, including history, before any
exchange check. Pick a symbol from the two lists, or call /coins.
no_data (404)
- The exchange doesn’t list options for this coin (e.g., OKX doesn’t have XRP)
- The expiration has already expired
market_unavailable (503)
rate_limit_exceeded (429)
rate_limit object repeats the figures from the X-RateLimit-* headers.
See Rate Limits for handling strategies.
History errors
The history endpoints add these slugs.history_not_available (400)
deribit+derive have no history. Use one venue or
combined. The same applies to ?compare= on /levels.
range_too_large (400)
/history/levels is longer than
the granularity allows: 15m up to 31 days, 1h up to 180 days, close
unlimited. Shorten the window or use a coarser granularity.
no_snapshot (404)
/history/snapshot found no capture within 15
minutes of at. Retry with one of nearest_timestamps (up to three, from the
TOTAL captures).
no_file (404)
files_unavailable (503)
method_not_allowed (405)
HEAD. The response has Allow: GET.
No file credit is spent.
history_files_limit_exceeded (429)
Retry-After header; read X-History-Files-Reset or
/me. See Rate limits.
Getting help
- Bug reports / unclear errors: admin@gammaflip.io
- Feature requests: open an issue on gammaflip-docs