Key-authenticated, server-to-server access to the same gamma-exposure metrics the dashboard shows — a live snapshot per ticker, and hourly history for research.
Two endpoints, both read-only:
The base URL is https://gexstream.com. All responses are JSON. Only tickers in the tracked screener universe are served — anything else is a 404.
Get your key from the app: sign in, open the account menu, choose api, and create a key in the API Access section. The key is shown exactly once — store it in a secrets manager, not in code.
Send your key in the X-API-Key header on every request. Keys are never accepted as query parameters — they must not appear in URLs or server logs. A User-Agent header is required; requests without one are rejected with 400.
The latest computed metrics for one ticker. Values refresh on a rolling cache and may be up to 5 minutes old — polling faster than that returns the same data.
Example response (Quant; Flow responses omit the dex/vex/cex/oi objects entirely):
{
"ticker": "SPY",
"asof": "2026-07-30T15:42:11Z",
"spot": 585.42,
"gex": { "net": 1.24e9, "ratio": 1.85, "zero_gamma": 580.0,
"max_strike": 590.0, "min_strike": 570.0 },
"vgex": { "net": 4.1e8, "ratio": 1.32, "zero_vgamma": 582.0,
"max_strike": 590.0, "min_strike": 575.0 },
"flow": { "ratio": 0.92, "net": -1.4e6 },
"iv": { "call": 0.142, "put": 0.163, "skew": -0.021 },
"dex": { "net": 2.2e9, "ratio": 1.10, "zero_delta": 578.0,
"max_strike": 585.0, "min_strike": 560.0 },
"vex": { "net": -3.0e8, "ratio": 0.85, "zero_vanna": 583.0,
"max_strike": 600.0, "min_strike": 570.0 },
"cex": { "net": 1.1e8, "ratio": 1.05, "zero_charm": 581.0,
"max_strike": 585.0, "min_strike": 575.0 },
"oi": { "total": 1.8e7, "ratio": 1.22, "max_strike": 600.0,
"min_strike": 550.0, "pct_chg": 1.4 }
}
Hourly history for one ticker. One query parameter: days, which must be 30, 60, or 90 (default 90). Any other value is a 400.
Example response (Quant; Flow rows carry gex/vgex/flow/iv/volume plus spot, and omit the dex/vex/cex/oi objects entirely — the same family split as the snapshot):
GET /api/v1/history/SPY?days=30
{
"ticker": "SPY",
"resolution": "1h",
"days": 30,
"rows": [
{
"t": "2026-07-01T14:00:00Z",
"spot": 578.10,
"gex": { "net": 9.8e8, "ratio": 1.61, "zero_gamma": 574.0,
"max_strike": 580.0, "min_strike": 565.0 },
"vgex": { ... },
"flow": { "ratio": 1.05, "net": 2.1e6 },
"iv": { "call": 0.151, "put": 0.170, "skew": -0.019 },
"volume": { "calls": 812345, "puts": 640321 },
"dex": { ... }, "vex": { ... }, "cex": { ... },
"oi": { "total": 1.7e7, "ratio": 1.18,
"max_strike": 600.0, "min_strike": 550.0 }
},
...
]
}
Metrics are grouped into family objects. Your tier decides which families you receive — a family you are not entitled to is absent, never zeroed. For what each metric means and how it is computed, see the metrics documentation.
| Family | Fields | Tier |
|---|---|---|
| gex | net, ratio, zero_gamma, max_strike, min_strike | Flow, Quant |
| vgex | net, ratio, zero_vgamma, max_strike, min_strike | Flow, Quant |
| flow | ratio, net | Flow, Quant |
| iv | call, put, skew | Flow, Quant |
| volume | calls, puts (history rows only) | Flow, Quant (history) |
| dex | net, ratio, zero_delta, max_strike, min_strike | Quant |
| vex | net, ratio, zero_vanna, max_strike, min_strike | Quant |
| cex | net, ratio, zero_charm, max_strike, min_strike | Quant |
| oi | total, ratio, max_strike, min_strike, pct_chg (snapshot only) | Quant |
spot and asof/t appear at the top level for all tiers.
| Limit | Flow | Quant |
|---|---|---|
| Snapshot requests / day | 800 | 3,000 |
| History requests / day | 15 | 50 |
| Distinct tickers / day | 2 | 4 |
| Request pacing | 1 request/second per key, burst of 3 | |
| Concurrency | 1 in-flight request per key | |
| Clients | 1 at a time (IP-bound; 10-minute idle release) | |
Every 200 (and daily-quota 429) carries your remaining budget:
Every failure returns a JSON envelope with an error message, plus retry_after_seconds on 409 and resets_at on daily-quota 429s. Checks run in a fixed order — the table below is that precedence, top to bottom (e.g. a bad method on a bound-elsewhere key is a 405, not a 409):
| Status | Message | Meaning |
|---|---|---|
| 405 | method not allowed | Only GET is supported. |
| 400 | User-Agent header required | Identify your client. |
| 429 | rate limit exceeded | Per-IP burst limit, evaluated before authentication. Retry-After: 1. |
| 401 | invalid or revoked API key | Missing, unknown, rotated-away, or revoked key. |
| 409 | key in use from another client | Another address holds the binding. Carries retry_after_seconds; release the binding from the account modal to move sooner. |
| 429 | rate limit exceeded | A request is already in flight on this key, or per-key pacing (1/s, burst 3) exceeded. Retry-After: 1. |
| 403 | API access requires a Flow or Quant subscription / API access requires a paid Flow or Quant subscription | Tier gate, identical on both endpoints. The second form means the subscription is not currently paid — a trial, for example. |
| 400 | invalid days parameter | History only: days must be 30, 60, or 90. |
| 404 | unknown ticker | Not in the tracked universe. |
| 429 | daily request quota exceeded / daily ticker limit exceeded | Daily budgets spent. Carries resets_at (midnight ET) and the quota headers. |
| 503 | service temporarily unavailable | Transient backend condition (including just after a restart). Retry with backoff. |
Accepted when you create a key; the full Terms and Conditions (Section 14) govern. In summary: