Free key-levels API
A free JSON API for GEX key levels (call wall, put wall, zero gamma, HVL, regime) — SPX / SPY / QQQ with no key, ES / NQ futures prices with a free key — plus gamma / vanna nodes, intraday history for the last 5 trading days and daily node stats for the last 20, for scripts and AI tools.
Three free JSON endpoints give you the same GEX key levels the site shows, in a shape scripts and AI tools can read directly.
SPX,SPY,QQQ: no key, no login, CORS open.ES,NQ(futures prices): need a free key — see "API key" below.- 30-minute delay for every ticker.
API key
- Sign up for free and log in.
- Open Settings → Data API and copy your key from "Free data API key".
- Send it in any one of these ways:
- Header
Authorization: Bearer <your key> - Header
X-API-Key: <your key> - URL parameter
?key=<your key>
- Header
| No key | With key | |
|---|---|---|
| SPX / SPY / QQQ | ✓ | ✓ |
| ES / NQ futures prices | — | ✓ |
| Calls per minute | 20 (per IP) | 60 (per key) |
Treat the key like a password and don't post it publicly.
Model-derived levels for information and education only. Not investment advice and not a trade signal.
Latest levels
GET https://hermesgex.com/api/v1/public/levels?ticker=SPX
GET https://hermesgex.com/api/v1/public/levels?ticker=ES (key required)Example response (numbers are illustrative):
{
"ok": true,
"ticker": "ES",
"price_scale": "futures",
"asof": "2026-10-28T15:31:39.000Z",
"delayed": true,
"delay_sec": 1800,
"session_date": "2026-10-28",
"age_sec": 1812,
"market": "open",
"stale": false,
"spot": 7781.2,
"regime": "long",
"basis": "vol",
"levels": {
"call_wall": 7816.5,
"zero_gamma": 7776.6,
"put_wall": 7771.4,
"hvl": 7776.6
}
}| Field | Meaning |
|---|---|
price_scale | futures for ES / NQ, underlying for the rest |
asof | Time of the snapshot (UTC) |
delay_sec | How far behind real time the data is (1800 = 30 minutes) |
session_date | US Eastern trading day the snapshot belongs to |
age_sec | Seconds between asof and when the response was generated |
market | pre_market, open or closed at response time |
stale | true if the market is open but no new snapshot arrived for longer than expected — treat the levels as outdated |
regime | long = price above HVL / zero gamma (moves tend to be damped), short = below (moves tend to extend), null = pre-market |
basis | vol = intraday levels from volume. oi = pre-market: walls from open interest, and zero_gamma / hvl / regime are null until volume prints |
levels.* | Call wall (resistance above), zero gamma (regime flip), put wall (support below), HVL |
nodes | Open-interest gamma node scores, see the next section; null when temporarily unavailable |
Node scores (nodes)
The same response also carries the largest open-interest gamma nodes within 4% of spot (expiries up to 90 days, summed by strike), with the same 30-minute delay. It is the same calculation as King, Floor, Ceiling and King lifecycle in the app.
"nodes": {
"asof": "2026-10-28T15:31:00.000Z",
"session_date": "2026-10-28",
"contested": false,
"king": {
"price": 7800,
"lifecycle": "tested",
"touches": 2,
"since": "2026-10-28T13:30:00.000Z",
"since_truncated": true,
"strength_vs_peak_pct": 94
},
"patterns": ["rising_floors"],
"list": [
{
"price": 7800,
"role": "king",
"strength_pct": 100,
"gamma_sign": "positive",
"side": "above",
"distance_pct": 0.24,
"confluence": [],
"lifecycle": "tested",
"touches": 2
},
{
"price": 7771.4,
"role": "floor",
"strength_pct": 62,
"gamma_sign": "positive",
"side": "below",
"distance_pct": -0.12,
"confluence": ["put_wall"],
"lifecycle": "fresh",
"touches": 0
}
]
}| Field | Meaning |
|---|---|
list[].role | king = largest node; gatekeeper = between spot and the King and at least 25% of its size; floor = largest below spot; ceiling = largest above spot; null = ranked but no role |
list[].strength_pct | Node size, King = 100 |
list[].gamma_sign | positive = positive-gamma node, price tends to pin or bounce here; negative = negative-gamma node, price tends to accelerate through |
list[].distance_pct | Distance from spot in percent, positive = above |
list[].confluence | Key levels within 0.15%: call_wall, put_wall, zero_gamma, hvl |
list[].lifecycle / list[].touches | For nodes with a role: lifecycle since this strike took that role (same values as king.lifecycle; for Floor / Ceiling / Gatekeeper, delivered means price broke or cleared it) and how many times price touched it; null when there is no role |
king.lifecycle | fresh = not reached yet; tested = touched but not crossed; rejected = touched, then price moved 0.3%+ back away on the same side without crossing; delivered = crossed; decaying = down 30%+ from its peak today |
king.since_truncated | true = it was already the King at the open, so it appeared earlier |
contested | true = the second node is within 10% of the King, so a single King is unreliable |
patterns | Intraday patterns: rising_floors, rolling_ceilings, ladder_up (King stepping up), ladder_down (King stepping down), rug (support below pulled), reverse_rug (resistance above pulled), rug_setup (positive node above, negative gamma below), reverse_rug_setup (positive node below, negative gamma above), pos_cloud (several adjacent positive nodes, price tends to chop), no_structure (alternating nodes, none dominant), snapback_up / snapback_down (price pushed through a positive node and came back) |
Before the open there is no node data for the day yet, so nodes shows the last frame of the previous session and session_date says which.
Data only updates every few minutes, so polling more than once a minute gains nothing.
Optional parameters
| Parameter | Values |
|---|---|
max_strikes | How many entries nodes.list (and vanna_nodes.list) returns, 1–20, default 5 |
include | vanna: adds a vanna_nodes block, see below |
tickers | Several tickers in one call, comma-separated, see below |
Several tickers in one call
GET https://hermesgex.com/api/v1/public/levels?tickers=SPX,SPY,QQQReturns a results array in request order; each entry is exactly the single-ticker response. If one ticker fails, its entry is ok: false with ticker, code and message, and the others still return. Up to 5 tickers per call; each ticker counts as one call toward the rate limit.
Vanna nodes (include=vanna)
GET https://hermesgex.com/api/v1/public/levels?ticker=SPX&include=vannaAt the same instant as nodes (same 30-minute delay): the largest open-interest vanna nodes within 4% of spot (expiries up to 90 days, summed by strike), plus the sign combination of GEX and VEX near spot.
"vanna_nodes": {
"asof": "2026-10-28T15:30:12.000Z",
"contested": false,
"alignment": {
"state": "pin",
"gex_sign": "positive",
"vex_sign": "positive",
"co_flips": [
{ "price": 5795, "low": 5790, "high": 5800, "short_side": "below" }
]
},
"list": [
{
"price": 5800,
"role": "king",
"strength_pct": 100,
"vanna_sign": "positive",
"side": "above",
"distance_pct": 0.21
}
]
}| Field | Meaning |
|---|---|
list[].strength_pct | Node size, largest vanna node = 100 (independent of the gamma King in nodes) |
list[].vanna_sign | positive = dealers tend to buy as volatility falls; negative = they tend to sell as volatility falls |
alignment.state | Sign of each sum within 0.5% of spot: pin both positive (price tends to pin), trend both negative (both hedges amplify moves), cap GEX positive and VEX negative (rallies stall in calm, a range break tends to keep going), panic GEX negative and VEX positive (panic lows tend to snap back hard), gex_led / vex_led only one side is meaningful, flat neither is |
alignment.co_flips | Prices where GEX and VEX flip sign in the same direction at the same place (up to 2); short_side is the side where both turn negative, so a move through it gets amplified by both hedges |
vanna_nodes is null when vanna data is temporarily unavailable; alignment is null when there is no GEX frame for the same instant.
Intraday history
GET https://hermesgex.com/api/v1/public/levels/history?ticker=SPX&date=2026-10-27&interval=15m| Parameter | Values |
|---|---|
ticker | SPX, SPY, QQQ; also ES, NQ with a key |
date | US Eastern trading day YYYY-MM-DD, within the last 5 trading days. Defaults to today |
interval | 15m (default), 30m |
Returns 08:30–16:15 ET bars. Each bar has the price open / high / low / close and the levels at the end of that bar (call_wall, put_wall, zero_gamma, hvl, regime, basis). Bar time t is the bar start in UTC.
Top-level fields worth checking:
complete:trueonce the whole day is past the 30-minute delay. Complete days never change.missing_minutes: minutes between 09:30 and the close with no stored data. Non-zero means gaps — keep that in mind before drawing conclusions.
For longer history or finer bars, use replay in the HuntingFlow terminal.
Daily stats
GET https://hermesgex.com/api/v1/public/levels/daily?tickers=SPX,QQQ&from=2026-10-20&to=2026-10-30| Parameter | Values |
|---|---|
tickers | One or more tickers, comma-separated (up to 5); ES, NQ with a key |
from | First US Eastern trading day YYYY-MM-DD, within the last 20 trading days. Defaults to 5 trading days before to |
to | Last trading day. Defaults to today |
One row per ticker per trading day, summarizing the open-interest gamma nodes over the regular session (09:30–16:00 ET), with the same 30-minute delay:
{
"date": "2026-10-28",
"complete": true,
"frames": 390,
"first_at": "2026-10-28T13:30:00.000Z",
"last_at": "2026-10-28T19:59:00.000Z",
"spot_open": 5781.2,
"spot_high": 5810.4,
"spot_low": 5770.1,
"spot_close": 5802.3,
"range_pct": 0.7,
"king_open": 5800,
"king_close": 5800,
"king_changes": 1,
"king_dominant": { "price": 5800, "share_pct": 81.3 },
"contested_pct": 6.4,
"close_nodes": [
{ "price": 5800, "role": "king", "strength_pct": 100, "gamma_sign": "positive" }
]
}| Field | Meaning |
|---|---|
complete | The session has closed and is past the delay, so the row won't change; today's row is false |
frames | Minutes included |
range_pct | (high − low) / open, in percent |
king_open / king_close | The King in the first minute and the last minute before the close |
king_changes | How many times the King moved to another strike (only counting Kings that held 5+ minutes, so ties flipping back and forth don't count) |
king_dominant | The strike that was King the longest, and its share of the day |
contested_pct | Share of minutes where the second node was within 10% of the King; higher means a less clear structure that day |
close_nodes | The 5 largest nodes in the last minute before the close, strength_pct with that King = 100 |
Trading days without data are left out of days.
Errors
Errors return ok: false with a code and message.
| code | Meaning |
|---|---|
TICKER_NOT_PUBLIC | Ticker not supported |
KEY_REQUIRED | ES / NQ need a free key |
INVALID_KEY | Key not valid — copy it again from settings |
NO_DATA | No data for that ticker / date |
NOT_YET | Today's data is not past the 30-minute delay yet |
NOT_TRADING_DAY | Weekend or US market holiday |
OUT_OF_RANGE / BAD_DATE / BAD_RANGE / BAD_INTERVAL | Bad date or interval |
BAD_MAX_STRIKES / BAD_INCLUDE | Bad max_strikes or include |
TOO_MANY_TICKERS | More than 5 tickers in one call |
NO_CONVERSION | ES / NQ futures conversion temporarily unavailable — retry later |
RATE_LIMITED | Too many requests; wait Retry-After seconds |
Examples
Python:
import requests
KEY = "hgx_pub_..." # copy from Settings → Data API
r = requests.get(
"https://hermesgex.com/api/v1/public/levels",
params={"ticker": "ES"},
headers={"Authorization": f"Bearer {KEY}"},
timeout=10,
).json()
if r["ok"] and not r["stale"]:
print(r["basis"], r["levels"])AI assistants: assistants that support MCP can add the connection https://hermesgex.com/api/mcp?key=<your key> (settings shows the full URL with your key; choose no authentication) and get three tools, get_key_levels (optional max_strikes and include_vanna), get_level_history and get_daily_node_stats, returning exactly the same data as the endpoints above. See Let your AI assistant read GEX key levels for the steps. Otherwise, give the assistant this page's URL and ask it to call the endpoints above. The basis, stale and regime fields are designed so it can tell pre-market, outdated and normal data apart without guessing.
Next
Frequently asked questions
Do I need an API key?
Not for SPX / SPY / QQQ. ES / NQ futures prices need a free key — sign up and copy it from Settings → Data API. With a key you get 60 calls per minute, 20 without.
Are ES and NQ given in futures prices?
Yes. With a key, ticker=ES and ticker=NQ return every level already converted to the futures price, so you can draw them straight onto an ES / NQ chart.
Can I get real-time levels?
Not from this API. Real-time levels are in the HuntingFlow terminal and the desktop plugins.
Hermēs Documentation