Options Flow API: How to Access Unusual Options Data Programmatically
Options flow data is most powerful when it feeds into automated systems: alerting bots, portfolio monitors, quantitative screens. This page covers the data fields that matter, REST vs. WebSocket, and working integrations in Python, JavaScript, and cURL.
What an Options Flow API Does
An options flow API is a programmatic interface to unusual options activity data: the same prints that flow platforms surface in their dashboards, but delivered as structured JSON you can consume in code. Instead of watching a browser dashboard, your application receives flow data and acts on it: sends a Discord alert, logs to a database, evaluates a trading rule, or triggers a webhook.
The API layer sits on top of the same underlying pipeline: raw OPRA tape → filter for unusual prints → score and classify → deliver. What changes is the delivery mechanism: JSON over HTTP (REST) or a persistent connection that pushes prints as they arrive (WebSocket).
REST vs. WebSocket: Which to Use
The choice between REST and WebSocket depends on what you're building:
| Transport | Use when | Latency | Server load |
|---|---|---|---|
| WebSocket (stream) | Live tape, real-time alerts, intraday bots | Milliseconds | Low (one persistent connection) |
| REST (/flow/top) | Dashboard snapshots, periodic polling, morning scans | Seconds | Moderate (one request per poll) |
| REST (/flow/heatmap) | Sector analysis, batch reporting | Seconds | Low (occasional reads) |
| REST (/flow/historical) | Backtesting, post-session analysis | N/A | Low (infrequent) |
For a live Discord alert bot, use WebSocket. Polling a REST endpoint every second both misses prints between polls and creates server load for nothing. For a morning scanner that runs at open and reports the top signals, REST is simpler and sufficient.
The Data Fields That Matter
A quality options flow API response includes these fields at minimum. If a provider's response is missing more than two or three of these, the API is not suitable for serious flow research:
| Field | Why it matters | Red flag if missing |
|---|---|---|
| ticker | Symbol identifier | — |
| type | CALL or PUT | — |
| strike | Contract strike price | — |
| expiry / expiryDate | Contract expiration | — |
| dte | Days to expiry, high-signal for urgency (0DTE, weekly) | High |
| volume | Contracts traded this print | — |
| openInterest / oi | Existing book for this contract | High |
| volOI | volume / openInterest, the core unusualness metric | Critical |
| premium | Total dollar value of the trade | — |
| side | ASK / BID / MID, the aggressor direction flag | High |
| kind | SWEEP / BLOCK / SPLIT, the execution urgency flag | Critical |
| otmPct | Percent out-of-the-money; filters lottery tickets | Medium |
| spot | Underlying price at time of print | Medium |
| iv | Implied volatility | Medium |
| score | Composite unusualness score (0–100) | High if absent |
| bias | BULL / BEAR / NEUTRAL, a computed directional label | Useful for bots |
| sector | GICS sector classification of underlying | Useful for screening |
| timestamp | Unix ms or ISO 8601 print time | — |
Authentication
Most options flow APIs use API key authentication via an HTTP header. Two common patterns:
# Pattern 1 — x-api-key header (most common)
curl -H "x-api-key: YOUR_KEY" \
https://api.radarpulse.io/v1/flow/top
# Pattern 2 — Bearer token
curl -H "Authorization: Bearer YOUR_KEY" \
https://api.radarpulse.io/v1/flow/top
Never hardcode an API key in source code. Store it as an environment variable and load it at runtime:
# .env file (never commit to git)
RADARPULSE_API_KEY=frk_your_key_here
# Python: load with python-dotenv
import os
from dotenv import load_dotenv
load_dotenv()
API_KEY = os.environ["RADARPULSE_API_KEY"]
REST API: Fetching Top Flow
The most common REST endpoint is /flow/top, which returns the top-N highest-scoring unusual prints for the current (or a specified) session.
Python example
import os, requests
API_KEY = os.environ["RADARPULSE_API_KEY"]
BASE = "https://api.radarpulse.io/v1"
def get_top_flow(limit=25, min_score=70):
resp = requests.get(
f"{BASE}/flow/top",
headers={"x-api-key": API_KEY},
params={"limit": limit, "minScore": min_score},
timeout=10,
)
resp.raise_for_status()
return resp.json()["data"]
for print_ in get_top_flow():
print(
f"{print_['ticker']:6} {print_['type']:4} "
f"${print_['strike']} exp {print_['expiry']} "
f"vol/OI={print_['volOI']:.1f} "
f"prem=${print_['premium']:,.0f} "
f"score={print_['score']}"
)
JavaScript (Node.js) example
const API_KEY = process.env.RADARPULSE_API_KEY;
const BASE = "https://api.radarpulse.io/v1";
async function getTopFlow({ limit = 25, minScore = 70 } = {}) {
const url = new URL(`${BASE}/flow/top`);
url.searchParams.set("limit", limit);
url.searchParams.set("minScore", minScore);
const res = await fetch(url, { headers: { "x-api-key": API_KEY } });
if (!res.ok) throw new Error(await res.text());
const { data } = await res.json();
return data;
}
const prints = await getTopFlow({ minScore: 80 });
prints.forEach(p =>
console.log(`${p.ticker} ${p.type} $${p.strike} score=${p.score} prem=$${p.premium.toLocaleString()}`)
);
WebSocket: Building a Live Alert Bot
For a Discord or Slack bot, connect to the WebSocket endpoint and push formatted alerts as prints arrive. The pattern is: connect → authenticate → receive prints → filter → post to webhook.
Python Discord bot (websockets + aiohttp)
import asyncio, json, os
import websockets
import aiohttp
API_KEY = os.environ["RADARPULSE_API_KEY"]
WS_URL = "wss://api.radarpulse.io/v1/stream"
DISCORD_WEBHOOK = os.environ["DISCORD_WEBHOOK_URL"]
MIN_SCORE = 85 # EXTREME signals only
MIN_PREM = 500_000 # $500K+ premium
async def post_discord(session, print_):
bias_emoji = "🐂" if print_.get("bias") == "BULL" else "🐻"
kind_tag = " ⚡ SWEEP" if print_.get("kind") == "SWEEP" else ""
msg = (
f"**{print_['ticker']} {print_['type']} ${print_['strike']} "
f"exp {print_['expiry']}**{kind_tag}\n"
f"Premium: ${print_['premium']:,.0f} | Vol/OI: {print_['volOI']:.1f}× | "
f"Score: {print_['score']} {bias_emoji}"
)
await session.post(DISCORD_WEBHOOK, json={"content": msg})
async def stream_flow():
async with aiohttp.ClientSession() as session:
async with websockets.connect(
WS_URL,
extra_headers={"x-api-key": API_KEY},
) as ws:
async for raw in ws:
print_ = json.loads(raw)
if (
print_.get("score", 0) >= MIN_SCORE
and print_.get("premium", 0) >= MIN_PREM
and print_.get("side") == "ASK" # bought at ask
):
await post_discord(session, print_)
asyncio.run(stream_flow())
REST API: Score Explanation Endpoint
A quality flow API exposes a score explanation endpoint that tells you which factors (Vol/OI, premium size, DTE, OTM distance) drove the composite score for a specific print. Useful for building "why this signal" features in your application.
# GET /v1/score-explain?ticker=NVDA&strike=200&type=CALL&expiry=2026-07-18
{
"score": 91,
"flag": "EXTREME",
"scoreParts": {
"volOI": 34, // out of 40 — highest weight
"premium": 28, // out of 30
"dte": 16, // out of 20 — 14 DTE is "hot"
"otm": 13 // out of 10 — slightly OTM
}
}
Outbound Webhooks (Server-to-Server)
Instead of maintaining a persistent WebSocket connection in your application, some APIs offer outbound webhooks: you register a URL and the API POSTs each qualifying print to it. This is simpler to operate (no persistent connection to maintain) and works well for serverless architectures.
# Register a webhook (POST /v1/webhooks)
curl -X POST \
-H "x-api-key: YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://your-server.com/flow-hook","minScore":75,"events":["flow.extreme","flow.elevated"]}' \
https://api.radarpulse.io/v1/webhooks
# Response
{
"id": "wh_abc123",
"secret": "whsec_..." // use to verify HMAC-SHA256 signature
}
Validate the webhook signature on every incoming request to prevent spoofed payloads:
import hmac, hashlib
def verify_webhook(payload_bytes, signature_header, secret):
expected = hmac.new(
secret.encode(), payload_bytes, hashlib.sha256
).hexdigest()
return hmac.compare_digest(f"sha256={expected}", signature_header)
Rate Limits and Best Practices
- Cache aggressively.
/flow/topdata doesn't change more than once per print (every few seconds live, slower for delayed feeds). Cache the response for 5–10 seconds before re-fetching rather than polling as fast as possible. - Use exponential backoff on 429 responses. If the API returns 429 (rate limit), wait 2s, then 4s, then 8s before retrying. Don't retry immediately.
- Prefer WebSocket for live use. One persistent connection uses far fewer resources than polling REST every few seconds and provides lower latency.
- Filter server-side when available. Pass
minScore,ticker, orminPremiumquery parameters so the server filters before sending, reducing payload size and your parsing overhead. - Store API keys in environment variables. Never commit an API key to source code, even private repositories. Use
.envfiles locally and secrets management in production (AWS Secrets Manager, Railway Secrets, Doppler).
What to Look for in a Quality Options Flow API
- Sweep and block flags are non-negotiable. An API that doesn't flag execution type is missing the most important signal in the flow.
- Vol/OI computed per-contract. Ticker-level OI ratios dilute the signal; you need the ratio at the specific strike and expiry.
- HMAC-signed webhooks. Any webhook provider that doesn't sign payloads exposes you to spoofed requests. The signature header should use HMAC-SHA256.
- Historical endpoint for backtesting. A live-only API limits your ability to build and validate filters on past sessions.
- Clear tier documentation. The API documentation should state precisely which data is available at each tier (Elite vs. Pro) and what latency each tier provides.
RadarPulse Developer API
RadarPulse's API layer is built on the same scoring engine the app uses. Every print you'd see in the Top 25 view or Whale Detector is available programmatically. The endpoint set includes:
GET /v1/flow: paginated scored flow for the current sessionGET /v1/flow/top: top-N highest-scoring printsGET /v1/score-explain: factor breakdown for any scored printGET /v1/heatmap: sector and ticker flow aggregatesGET /v1/congress: Congressional STOCK Act disclosures (Pro+)- WebSocket
/v1/stream: live scored prints as they arrive POST /v1/webhooks: register outbound webhook endpoints
All REST endpoints accept x-api-key header authentication. API keys are generated in-app under the Developer Console (Elite tier). Outbound webhooks are HMAC-SHA256 signed. SSRF protection is enforced on webhook URLs: private IP ranges and localhost are blocked.
Join the waitlist → to get early Elite access and a developer API key when the API launches.
Frequently Asked Questions
What is an options flow API?
An options flow API is a programmatic interface that provides access to unusual options activity data without a browser. Developers use it to build alerting bots, automate trading research, integrate flow signals into existing tools, and send alerts to Discord, Slack, or custom webhooks.
What data fields does an options flow API return?
A quality API returns: ticker, type (CALL/PUT), strike, expiry, DTE, volume, open interest, Vol/OI ratio, premium, aggressor side (bid/ask/mid), execution type (sweep/block/split), implied volatility, OTM%, spot price, and a composite score. Sector classification and directional bias are useful additions for bot filtering.
Should I use REST or WebSocket for options flow?
Use WebSocket for real-time streaming (alerts fire the moment a print arrives) and REST for snapshot reads, periodic polls, or historical queries. Live alert bots need WebSocket; polling REST every second misses prints and creates unnecessary load.
How do I verify an options flow webhook signature?
Compute an HMAC-SHA256 of the raw request body using your webhook secret, then compare it to the signature in the request header (typically X-Signature or X-Webhook-Signature). Use constant-time comparison (hmac.compare_digest in Python, crypto.timingSafeEqual in Node.js) to prevent timing attacks. Reject any request where the signatures don't match.
What's the minimum API tier for live options flow data?
Real-time flow (sub-second) typically requires an Elite-tier API key. 15-minute delayed flow is usually available at Pro tier. Free API access, when offered, provides end-of-day or sample data only. The data latency tier is the primary pricing axis for options flow APIs.
Can I use the API for high-frequency or automated trading?
Options flow APIs are designed for research and signal generation, not order routing. They provide analytical data (unusual activity, unusualness scores, sector flow) that you integrate into your trading workflow. Order execution is handled separately through your broker's API. Most provider terms of service prohibit using the API for automated order routing without explicit permission.
What programming languages can I use?
Any language with HTTP and WebSocket libraries works. Python is most common for trading automation (requests, websockets, pandas). JavaScript/Node.js is popular for Discord/Slack bots (ws library, Discord.js). Go and Rust are used in latency-sensitive applications. All examples in this guide can be adapted to any language with standard networking support.
Elite members get an API key, WebSocket stream access, and webhook management in the in-app Developer Console. All endpoints include scored flow with sweep/block flags, Vol/OI, and sector classification.
Join the waitlist →