HTTP API
The HTTP API exposes the same market data and paper-trading actions you see in the dashboard, scoped to your account and authenticated with a personal API key. Designed for scripts, backtests, and any client that doesn't want to go through OAuth (Claude / Cursor / Codex should use MCP instead — it's already wired).
Base URL
https://gex.junk.place/api/v1
Every endpoint below lives under that prefix. Everything is JSON over
HTTPS, no versioned media types — just plain Content-Type: application/json
on requests with a body.
Authentication
Send your API key in the standard Authorization: Bearer … header on
every request:
curl -H "Authorization: Bearer gex_live_…" \
https://gex.junk.place/api/v1/meKeys are issued from /account/api-keys. Each key
has a name (so you can tell them apart later), a list of scopes, and
shows up with its last-used time + IP. There is no expiry — rotate by
issuing a new key and revoking the old one. The plaintext token is shown
only once, at creation; the server stores its SHA-256 hash.
Errors
| Status | Error code | Meaning |
|---|---|---|
| 401 | missing_bearer | No Authorization header. |
| 401 | invalid_key | Token malformed, unknown, or revoked. |
| 403 | insufficient_scope | The key is valid but doesn't include this scope. |
| 400 | invalid_request | Body or query failed validation (details field). |
| 404 | not_found / various | Account / position / expiry doesn't exist for you. |
Scopes
A key carries an explicit list of scopes. Pick the minimum your script needs — there's no "all" scope and never will be.
analytics:read— public market data: expirations, snapshots, timeline.portfolio:read— your paper accounts, positions, history, transactions.portfolio:write— open and close positions in your paper accounts.
Scope checks are per-endpoint. A portfolio:read key gets 403 on
write endpoints — the spelling of the missing scope is in the response
body so you know exactly what to enable.
Endpoints
Identity
GET /api/v1/me
Scope: any. Returns the user that owns the key and which scopes it has. Useful as a smoke test after generating a key.
curl -H "Authorization: Bearer gex_live_…" \
https://gex.junk.place/api/v1/me{
"userId": "65f1e9c7…",
"keyId": "65f1e9d2…",
"scopes": ["analytics:read", "portfolio:read"]
}Analytics
GET /api/v1/expirations
Scope: analytics:read. Lists every (source, currency, expiry) triple
that has a recent snapshot. Use it to discover what's tradeable right
now — the dashboard's expiry dropdown is built from this exact call.
curl -H "Authorization: Bearer gex_live_…" \
https://gex.junk.place/api/v1/expirations[
{ "source": "deribit", "currency": "BTC", "expiry": "2026-05-30T08:00:00.000Z" },
{ "source": "deribit", "currency": "BTC", "expiry": "2026-06-27T08:00:00.000Z" }
]GET /api/v1/analytics/{source}/{currency}/{expiry}
Scope: analytics:read. Latest snapshot for one expiry: per-strike call
/ put OI, IVs, GEX, plus computed metrics (max-pain, gamma flip, walls).
{expiry} must be the ISO timestamp returned by /expirations.
curl -H "Authorization: Bearer gex_live_…" \
"https://gex.junk.place/api/v1/analytics/deribit/BTC/2026-05-30T08:00:00.000Z"GET /api/v1/timeline/{source}/{currency}/{expiry}?days=7
Scope: analytics:read. The same snapshot at every 5-minute tick for
the last days days (default 7, max 30). Drives the timeline chart at
the bottom of the dashboard.
Portfolio — read
GET /api/v1/portfolio/accounts
Scope: portfolio:read. Lists your paper accounts.
[
{
"accountId": "65f1ea3a…",
"name": "default",
"mode": "paper",
"isDefault": true,
"balances": { "btc": 0.98, "eth": 0, "usdc": 50000 },
"reservedCollateral": { "btc": 0.02, "eth": 0, "usdc": 0 },
"createdAt": "2026-04-01T12:00:00.000Z"
}
]GET /api/v1/portfolio/accounts/{id}
Scope: portfolio:read. Full account snapshot: balances, reserved
collateral, unrealized P&L, total equity, aggregated greeks per book,
and every open position with mark and P&L. The response shape is
identical to the one the web UI's Overview tab consumes.
GET /api/v1/portfolio/accounts/{id}/history?limit=50&before=…
Scope: portfolio:read. Closed trades, most recent first. before is
an ISO timestamp for cursor-style pagination on exitFilledAt.
GET /api/v1/portfolio/accounts/{id}/transactions?limit=100&before=…&includeFunding=false
Scope: portfolio:read. Every fill, settlement, swap, and (optionally)
funding accrual. Funding events are noisy — opt in via includeFunding=true
when you actually want them.
Portfolio — write
POST /api/v1/portfolio/accounts/{id}/positions
Scope: portfolio:write. Opens a position at the live mid mark. The
server reserves the required collateral and returns the filled position.
curl -X POST \
-H "Authorization: Bearer gex_live_…" \
-H "Content-Type: application/json" \
-d '{
"instrument": "BTC-30MAY26-110000-C",
"side": "long",
"qtyContracts": 0.5
}' \
"https://gex.junk.place/api/v1/portfolio/accounts/65f1ea3a…/positions"Body:
| Field | Type | Required | Notes |
|---|---|---|---|
instrument | string | yes | Deribit instrument name, e.g. BTC-PERPETUAL. |
side | "long" | "short" | yes | |
qtyContracts | number > 0 | yes | Contract units; fractional allowed. |
leverage | int 1–50 | no | Perps only; defaults to account setting. |
limitPriceCrypto | number > 0 | no | If set, queues a limit order instead of market. |
POST /api/v1/portfolio/accounts/{id}/positions/{posId}/close
Scope: portfolio:write. Closes (or partially closes) a position. Send
no body to fully close at mark; include qtyContracts to partial-close.
curl -X POST \
-H "Authorization: Bearer gex_live_…" \
-H "Content-Type: application/json" \
-d '{"qtyContracts": 0.25}' \
"https://gex.junk.place/api/v1/portfolio/accounts/65f1ea3a…/positions/65f1eb12…/close"Versioning
Everything lives under /api/v1. We won't break this prefix — additive
changes only (new fields, new endpoints). When (if) we ship breaking
changes they go under /api/v2, and /api/v1 stays alive long enough
for callers to migrate.
MCP alternative
If you're building an AI agent rather than a script, use MCP instead:
https://gex.junk.place/mcp over HTTP transport. MCP gives you 30+
tools with structured argument schemas, OAuth-based per-user auth, and
no need to hand-write JSON. See the paper-trading
walkthrough for the full setup.