Bullflow API
Build with options flow, gamma exposure (GEX), dark pool trades, and streaming alerts through Bullflow’s JSON data endpoints and Server-Sent Events (SSE) streams. Explore endpoint parameters, response formats, code examples, and historical alert replay. For developers and AI agents, each endpoint lists its price, accepted payment methods, and API-key requirements. Use an API subscription, prepaid credits with an API key, or separate x402 or MPP payments on eligible endpoints.
Base URL:https://api.bullflow.io
Transports:HTTPS JSON and Server-Sent Events (Content-Type text/event-stream)
Prepaid credits
Add credits in the API dashboard from $5 for 500 credits. Use the same API-key examples below; each REST endpoint lists its credit cost. Only successful responses consume credits, and each page is a separate request.
Purchases of $10+ receive 5% extra credits, $25+ receive 8%, and $50+ receive 10%. The highest eligible bonus applies to the whole purchase, rounded down to whole credits. Bonuses are capped at 10%; refunds and disputes recalculate credits based on the remaining payment.
The $129/month API subscription covers these requests without spending credits and includes streaming and MCP access. Active API subscribers cannot buy credits. Prepaid credits do not grant MCP, OAuth, or streaming access.
REST rate limits
60 requests per rolling 60 seconds per credential or payer, per endpoint. Bursts are allowed within the quota. No minimum spacing is required between requests, but at most 60 requests are allowed in any rolling 60-second window.
Each endpoint has a separate limit, shared across its tickers, dates, filters, and pages. API-key requests share the key’s limit, OAuth connections on the same account share its limit, and paid requests share the payer’s limit. Throttled requests return HTTP 429 with Retry-After in seconds. Wait at least that long before retrying.
Reference revision 1.21, updated 2026-10-20. The authoritative public API reference is https://www.bullflow.io/api/docs. Fetch https://www.bullflow.io/bullflow-api-agent-docs.yaml directly for the latest agent reference. The download is a structured YAML reference, not an OpenAPI specification. Open YAML reference
Try free closing market data
GET /v1/gexClosingSnapshotSummary?ticker=SPY needs no key or payment. It returns the previous trading session’s closing spot price, total net GEX and up to 12 strikes with the largest absolute exposure.
GET /v1/optionsFlowClosingSnapshotSummary?ticker=SPY is also free and returns recorded session totals and up to 12 largest-premium trades. Choose supported tickers from the options-flow availability list.
Coverage & limits
Choose a ticker from GET /v1/gexClosingSnapshots. Coverage changes with available closing data. The four public summaries and availability lists and their free MCP tools share a limit of 60 requests per fixed minute per client IP. Over the limit, REST returns 429 with Retry-After; MCP returns an error with the retry delay.
Paid access
Paid live data and full-history products are separate. On eligible paid REST requests: x402 · USDC on Base: $0.01; MPP · USDC.e on Tempo: $0.01; MPP · Card / Link SPT: $0.50 per request. The live 402 challenge confirms supported methods and the final price; network fees may apply. The four free closing-data MCP tools need no account; other market-data tools and streams require subscriber access.
Agent Payments
Pay per request with x402 or MPP, or use an active API subscription. Inspect the HTTP 402 challenge for available methods and the current price before paying.
Paid API requests are final and non-refundable, except where required by applicable law. Review the Terms of Service, Refund Policy, and Privacy Policy before authorizing payment. A separately paid retry may incur another charge; check the existing payment status if the outcome is unclear.
Here's how it works
- Preview the quote. Your agent makes an unpaid request and reads the price and payment requirements in Bullflow’s HTTP
402response. - Confirm the payment method. For crypto, confirm the exact token and network: USDC.e on Tempo for MPP, or USDC on Base for x402. For cards, confirm your eligible Link card.
- Fund only if needed. For crypto, check the available balance first and use a supported funding route if it does not cover the quote and any fees.
- Approve the purchase. Review the selected method’s quoted amount and authorize this request.
- Verify the data arrived. Your agent submits the payment proof and checks Bullflow’s HTTP status and expected data. Successful MPP payments also return a
Payment-Receipt.
For future requests, ask your agent to remember your preferred payment method. Remembering a method does not authorize future charges by itself. With a supported approval policy or wallet permission and spending limits you authorize, your agent can handle the quote, payment, and retry without asking you to approve each covered request.
{
"error": "Payment required"
}- x402 · USDC on Base
- Read the
PAYMENT-REQUIREDheader and retry with proof inPAYMENT-SIGNATURE. - MPP · Stripe cards or Tempo crypto
- Read the challenges in
WWW-Authenticate. Retry withAuthorization: PaymentorPayment-Authorization. A successful MPP payment returns aPayment-Receiptheader.
The JSON body signals that payment is required; available methods, prices, and payment requirements come from the response headers. Use one payment credential per request. The selected method’s live quote takes precedence over catalog pricing.
An active API subscription provides access without a separate per-request payment. Saved custom alerts require a valid API key to identify your account even when paying with x402 or MPP. When using MPP for these requests, supply the API key in X-API-Key so it does not conflict with payment authorization.
Prepaid API credits are another option for REST requests: add at least $5 in the API dashboard, then use your API key. Endpoint credit prices are separate from the x402 and MPP quotes shown here. An active API subscription takes priority and does not spend credits; subscribers cannot purchase additional credits. MCP, OAuth, and streaming still require subscriber access.
Set up agent payments
Agent payments are optional. You can use a subscription instead.
Choose a card or crypto payment client, then give your agent the Bullflow request instructions. Wallet setup happens with the payment provider. Your first request can be a net gamma exposure lookup for SPY.
A Shared Payment Token (SPT) lets your agent pay through Stripe without receiving your actual card details. No Tempo wallet or crypto deposit is needed. Link currently supports US accounts.
Recommended Link approval settings
- Keep the connection for next time. Connect Link on the computer where your agent runs. Reuse that sign-in while it remains valid; you do not need to connect again for every request.
- Choose an eligible card. Have your agent list available payment methods and confirm the card you want. If none appear, add a card in Link and check eligibility before starting a purchase.
- Start with approval for each purchase. For your first request, use manual approval in Link and keep the purchase approval page open. Connecting the agent grants account access; approving a purchase authorizes that specific amount. Neither step confirms that Bullflow delivered the data.
- Make approvals easy to find. Use the purchase approval link your agent provides, or install the Link app and allow its notifications. Once you approve, the agent should check that same request and continue automatically without asking you to approve it again.
- Enable unattended spending only with a verified policy. After a successful first payment, use automatic approval only if your Link integration offers an approval policy you can inspect. Authorize only the intended card and a small per-purchase limit that covers the quote. Have your agent show the actual policy before relying on it. If no policy is available, keep manual approval; a chat instruction cannot configure Link permissions or enforce a spending limit.
Link documents approval policies for integrations that support them, but availability varies. Check your installed CLI’s help before using approval-policy retrieve. If it is unavailable, use the standard purchase approval flow below.
Open Link · Get the Link app · Approval policy reference
Your first card payment
- Preview the live card quote. Make an unpaid request. Your agent reads the Stripe challenge in
WWW-Authenticateand explains the quote before starting the purchase. Card and crypto prices can differ.Inspect the quote without paying · shell curl -sS -D - -o /dev/null "https://api.bullflow.io/v1/data/netgex?ticker=SPY" - Check the connection and choose a card. Ask your agent to check sign-in first. Only run the login command if disconnected, complete the verification in Link, then select an eligible card.
Check Link and available cards · shell npx @stripe/link-cli auth status npx @stripe/link-cli payment-methods listConnect only if needed · shell npx @stripe/link-cli auth login --client-name "Bullflow agent" --interval 5 --timeout 300 - Let Link prepare the payment. Give your agent the copied prompt. The command below handles the challenge and SPT request automatically, using Link’s default eligible payment method; your agent can add
--payment-method-idfor the card you selected. This starts a real purchase flow.Start one card purchase after reviewing the quote · shell npx @stripe/link-cli mpp pay "https://api.bullflow.io/v1/data/netgex?ticker=SPY" \ --context "Purchase one Bullflow SPY gamma exposure API response using the live Stripe card quote for my first agent payment setup." \ --format json - Approve the purchase once in Link. Open the approval link returned by the command and review Bullflow, the card, and the amount. Your agent should poll that same request and, when approved, run the saved continuation. You do not need to sign in or approve that same purchase again. In agent mode,
mpp paycan return a pending request that needs this continuation.Check the existing request — replace the ID · shell npx @stripe/link-cli spend-request retrieve YOUR_SPEND_REQUEST_ID --interval 2 --max-attempts 25 --format json - Confirm the data arrived. Your agent checks Bullflow’s HTTP status, returned data, and
Payment-Receipt. Link’sapprovedstatus means permission to pay, not completed delivery. A zero CLI exit code alone also does not mean the API request succeeded.
Will I need to approve again? Reuse a valid Link connection. Every new purchase needs a new SPT; expect another purchase approval unless a verified policy covers it. The same approved, unsubmitted request should be continued, not replaced. An SPT does not replace a Bullflow API key; saved custom alerts also require X-API-Key.
Approved but still receiving 402? Stop before creating another purchase. Have your agent check the existing request and provide the HTTP status and non-sensitive request reference to Bullflow support. Changing approval settings will not resolve a payment-verification failure.
Shared Payment Token reference
Pay with USDC.e on Tempo
Bullflow’s Tempo payment method uses USDC.e on Tempo. Your wallet holds the funds your agent uses to pay for API requests. Match the exact token and network in the payment challenge when funding your wallet.
- Install Tempo and create your wallet. Follow the official Tempo installation guide below. Open a terminal on the computer where your agent runs and enter the command below. Complete the browser sign-in or create a wallet with a passkey when prompted.
Sign in or create a Tempo wallet · shell tempo wallet login - Preview the quote and confirm the token and network. Run this preview for Bullflow's SPY gamma exposure data. A preview reads the payment offer without paying. Confirm the amount, USDC.e token, and Tempo network before adding funds.
Preview the price without paying · shell tempo request --dry-run --payment-intent charge "https://api.bullflow.io/v1/data/netgex?ticker=SPY" - Check your balance and fund only if needed. Check the available balance first. If it does not cover the quote and any fees, run the funding command and follow its supported route to receive USDC.e on Tempo. If transferring from another wallet or exchange, confirm it supports the exact receiving network and token; do not send tokens using an incompatible network.
Check funds before funding · shell tempo wallet whoamiOpen wallet funding · shell tempo wallet fund - Wait for your available balance. After completing funding, check your wallet. Wait until the deposit appears as available funds and covers the request. A transfer still pending, or funds reserved for another payment, cannot pay for this request.
Check the wallet and available funds · shell tempo wallet whoami - Connect your agent and approve the first payment. Use “Let your AI agent handle it — copy the prompt” next to “Pay with USDC.e on Tempo” above. Paste the prompt into your agent running on the same computer as the configured Tempo client. Have it show a fresh quote and wait for your approval. Once approved, it can run the request below to pay and retrieve the JSON data. This command makes a real payment when a payment challenge is returned.
Run only after approving the payment · shell tempo request --payment-intent charge "https://api.bullflow.io/v1/data/netgex?ticker=SPY" - Verify the data arrived. Have your agent check Bullflow’s HTTP status, expected JSON data, and
Payment-Receipt, then summarize the data and its timestamps. If the result is unclear, check the existing payment before approving another charge.
Tempo wallet installation and payment instructions
If setup needs attention
- If the selected method is absent from the challenge, confirm the provider setup and choose an offered method before proceeding.
- If a payment fails, check the client's sign-in status, payment method or balance, and the challenge's current price and expiry.
- Keep wallet secrets and card credentials in the payment client. Configure spending controls there; a prompt asking for approval does not itself enforce a spending limit.
- To read saved custom alerts, include your valid Bullflow API key in
X-API-Keyas well as the MPP payment credential.
Responses & freshness
Paying per request returns the same data format as subscription access.
Use the timestamps supplied by the endpoint to assess freshness. A successful request does not imply a new trade or snapshot: historical queries reflect the requested period, and the latest available data can predate your request outside market hours.
For streaming endpoints, parse each SSE data frame as JSON and reconnect after a disconnect. See the endpoint’s event definitions and history options before resuming.
Errors & retries
- 400: Check the endpoint’s parameters and avoid sending multiple payment credentials.
- 401 / 403: Check your API key, account identity, and subscription permissions where required.
- 402: For prepaid API keys, check your credit balance in the dashboard. For x402 or MPP, inspect payment headers for the offered methods and current quote before approving a payment.
- 429: Slow down and follow the response’s retry guidance.
- 5xx: Retry with backoff. If a paid request’s outcome is unclear, check payment status before authorizing another charge.
Read the endpoint’s error body as well as its HTTP status. Error fields vary by endpoint and payment provider.
MCP server
api.bullflow.io/mcpConnect coding agents directly to Bullflow through the MCP server. This endpoint exposes Bullflow public API docs, free closing summaries, net GEX, net VEX, and net premium lookups, last trade price lookups, peak return lookups, custom alert creation, streaming endpoint metadata, and bounded backtesting replay samples over Streamable HTTP.
Access & pricing
The four free closing-data tools and public documentation need no account, API key, or payment.
Other tools require subscriber access. Prepaid REST credits and per-request payments do not grant access to subscriber MCP tools.
Connection
- Endpoint:
https://api.bullflow.io/mcp - Transport:
MCP Streamable HTTP - Supported method:
POST - Unsupported methods return an MCP error response.
GETandDELETEare not valid for this endpoint. - When using SSE endpoint metadata returned by MCP tools, it is recommended to implement auto reconnect functionality in your client in case the stream is disconnected for any reason.
Authentication
Public docs and the four free closing-data tools need no credentials. Other tools require subscriber access through one of the following:
- OAuth:
Authorization: Bearer YOUR_ACCESS_TOKEN, or query string:?key=YOUR_API_KEY - Header:
X-API-Key: YOUR_API_KEY - Header:
Authorization: Bearer YOUR_API_KEY - Subscriber tools request account connection when credentials are missing or expired. Check
isErrorin tool results even when HTTP returns 200.
Available tools
bullflow_free_delayed_gex_tickers— available public GEX tickers with each snapshot's capture timestamp and session date, with no account.bullflow_free_delayed_gex_snapshot— GEX delayed by at least 15 minutes, including the strike-by-expiration heat map, exposure totals, and key levels for a supportedticker, with no account.bullflow_free_options_flow_related_tickers— up to six related tickers with recorded premium and trade totals from the same closing session, with no account.bullflow_free_gex_tickers— available public closing GEX tickers and session dates, with no account.bullflow_free_gex_summary— closing spot, total net GEX and up to 12 strikes for a supportedticker, with no account.bullflow_free_options_flow_tickers— available public closing options-flow tickers and session dates, with no account.bullflow_free_options_flow_summary— recorded session totals and up to 12 largest-premium trades for a supportedticker, with no account.bullflow_api_docs— returns API docs and MCP connection details.bullflow_peak_return— runs the peak return lookup with the current MCP connection's API key.bullflow_net_gex— looks up calculated net GEX with the current MCP connection. Acceptstickerand optionaltype:oi(default) orvolume. Volume uses the current or most recent U.S. Eastern trading day.bullflow_net_vex— runs the net VEX lookup with the current MCP connection's API key.bullflow_net_premium_series— returns cumulative call and put net premium values with the current MCP connection's API key.bullflow_historical_options_flow— returns historical options trades with date, ticker, contract, trade filters, and pagination using the current connection's credentials.bullflow_options_profile— summarizes recorded ticker activity, 20-session relative volume, execution-side premium, sweeps, and unusual contracts.bullflow_options_top_tickers— returns leading option-flow tickers ranked by volume, premium, or directional net premium.bullflow_gex_alerts— returns GEX proximity and node movement alerts filtered by date range, ticker, and alert type.bullflow_last_trade_price— runs the last trade price lookup with the current MCP connection's API key.bullflow_dark_pool_trades— runs the dark pool trades lookup with the current MCP connection's API key.bullflow_get_custom_alerts— returns saved custom alerts for the current MCP connection's API key account.bullflow_create_alert— creates a saved custom alert for the current MCP connection's API key account.bullflow_streaming_endpoint— returns connection details for live alerts or backtesting replay SSE.bullflow_live_options_flow_endpoint— returns the live options flow SSE URL, authentication guidance, event types, and public trade fields.bullflow_backtesting_replay_sample— collects a bounded replay sample for agent workflows.
All free tools share 60 requests per fixed minute per client IP with the free REST endpoints. Read snapshot_date for the trading session and snapshot_timestamp for delayed GEX freshness; the latest capture may be older outside recording hours. A rate-limit error has structuredContent.status=429 and data.retryAfterSeconds; wait before retrying.
Resource
bullflow://api-docs— YAML docs resource exposed by the MCP server.
Free closing-data connection
{
"mcpServers": {
"bullflow": {
"url": "https://api.bullflow.io/mcp"
}
}
}This configuration works in Cursor and clients accepting an mcpServers URL. Other clients may require selecting Streamable HTTP. For subscriber tools, connect with OAuth or configure your client's secure credential storage to send X-API-Key or Authorization: Bearer YOUR_API_KEY.
Live Options Flow Alerts
api.bullflow.io/v1/streaming/alertsStreams Bullflow algo alerts in real time plus any custom alerts that match the account associated with your API key. Only alerts created after the connection opens are delivered, so reconnect if you miss time on the stream.
Access & pricing
Included with an active API subscription and valid API key. Subscription pricing applies.
Prepaid credits and per-request x402 or MPP payments are not accepted on this endpoint.
Query params
key— required API key value generated in the dashboard.
Event payloads
- Each SSE
data:frame contains JSON. Parse that JSON and useeventto identify the payload type. event === "init"— providesmode(alerts) andstartedAt(ISO timestamp).event === "heartbeat"— emitted every 10 seconds to keep the connection alive; safe to ignore.event === "alert"— includes the alertidand the alert payload indata.- Alert payloads include
data.alertType,data.symbol,data.alertName,data.alertPremium,data.averageFillPrice, anddata.timestamp. data.alertType— eitheralgo(Bullflow algo alerts such as Urgent Repeater, Sizable Sweep, etc.) orcustom(alerts matching the custom alerts you set in the Bullflow dashboard).- Alert payloads also include
data.latency,data.deliveryLatency, anddata.receivedAt. - Authentication, subscription, and connection-throttle failures are returned as normal HTTP JSON errors before the SSE stream begins.
- Custom alert delivery is limited to 10 custom alerts per 60 seconds and 1000 custom alerts per 12 hours. API subscribers receive up to 60 custom alerts per 60 seconds and 5000 custom alerts per 12 hours.
- It is recommended to implement auto reconnect functionality in your SSE client in case the stream is disconnected for any reason. Live alert streams only deliver alerts created after the connection opens.
Python example code
import json
import requests
from types import SimpleNamespace
with requests.get(
"https://api.bullflow.io/v1/streaming/alerts",
params={"key": "YOUR_API_KEY"},
stream=True,
) as stream:
stream.raise_for_status()
for line in stream.iter_lines(decode_unicode=True):
if not line or not line.startswith("data: "):
continue
message = json.loads(line[6:], object_hook=lambda d: SimpleNamespace(**d))
event = getattr(message, "event", None)
if event == "init":
print("connected at", getattr(message, "startedAt", "unknown"))
if event == "heartbeat":
continue
if event == "alert":
alert = getattr(message, "data", None)
if alert:
print(
"⚡ alert",
getattr(message, "id", ""),
getattr(alert, "symbol", ""),
"premium",
getattr(alert, "alertPremium", ""),
"avg fill",
getattr(alert, "averageFillPrice", ""),
"type",
getattr(alert, "alertType", ""),
"name",
getattr(alert, "alertName", ""),
)
Example payload
{
"event": "alert",
"id": "1MPDp-Qm6_urgent",
"data": {
"alertType": "algo",
"symbol": "O:AMD251205P00205000",
"alertName": "Urgent Repeater",
"alertPremium": 16965.0,
"averageFillPrice": 1.31,
"timestamp": 1764708086.0,
"latency": 0.842,
"deliveryLatency": 0.091,
"receivedAt": 1764708086.751
}
}alertPremium is the premium of the trade that triggered the alert; averageFillPrice is the average fill price for that trade.
Live options flow
api.bullflow.io/v1/streaming/live-options-flowStream our unusual options order flow feed for the current U.S. Eastern trading date. API-key access requires an active API subscription. Use your API key in key, X-API-Key, or an Authorization bearer header. OAuth access requires an active Bullflow Premium or API subscription and a bearer token with api:read permission.
Access & pricing
Included with an active API subscription and valid API key. Subscription pricing applies.
Prepaid credits and per-request x402 or MPP payments are not accepted on this endpoint.
There is no initial history payload. The date switches at midnight America/New_York, including daylight-saving changes, while your connection remains open. Trade timestamps use Unix seconds; delayed prints can have timestamps before the connection opened.
Connection limits and recovery
- One active live flow connection per API key. Opening another connection with that key replaces the previous one.
- The default limit is 3 connection attempts per rolling 60 seconds per API key. Exceeding it starts a 60-second cooldown; honor
Retry-Afteron429responses. - Reconnect with a delay after disconnection. New connections deliver future trades only;
Last-Event-IDdoes not replay missed trades. - Temporary interruptions can emit
errorevents while delivery is retried. Slow clients can be disconnected, so consume incoming frames promptly.
SSE events
| Event | Payload |
|---|---|
init | Includes mode: live-options-flow, date, timezone, and ISO timestamp startedAt. |
trade | A trade in data. The JSON id, data.id, and SSE id: line match. |
heartbeat | Sent every 10 seconds with an ISO timestamp, including when no trades arrive. |
date_changed | Includes the new YYYY-MM-DD date and timezone: America/New_York. |
error | Includes a message describing a temporary interruption; delivery is being retried. |
Trade fields
| Fields | Description |
|---|---|
id / tradeDate / timestamp | Trade identifier, YYYY-MM-DD trading date, and Unix trade timestamp in seconds. |
symbol / ticker / optionType | Option contract symbol, underlying ticker, and C or P. |
expirationDate / strikePrice | YYYY-MM-DD expiration date and strike in USD. |
premium / tradePrice / tradeSize | Total premium in USD, option fill price in USD per share, and number of contracts. |
tradeType / side | SWEEP, BLOCK, or MULTI, and Ask, Above Ask, Mid, Bid, or Below Bid when classified. |
spotPrice / currentBid / currentAsk | Underlying price and option bid/ask at the trade time, in USD. |
currentVolume / openInterest | Contract session volume at the trade time and open interest. |
impliedVolatility / sigScore | Implied volatility in percent and unusualness score from 0 to 1. |
delta / gamma / theta / vega / rho | Option Greeks at the trade time. |
isCancelled / isOutOfSequence | Whether the print was cancelled or reported out of sequence. |
Unavailable values are null. Live trade messages include cancellation flags; clients can choose how to handle those prints.
Add reconnection handling to production clients. Missing or expired credentials return 401; invalid credentials, inactive subscriptions, or missing permissions return 403. Too many connection attempts return 429; temporary unavailability before streaming starts returns 503.
cURL example
curl --no-buffer \ --header "X-API-Key: $BULLFLOW_API_KEY" \ 'https://api.bullflow.io/v1/streaming/live-options-flow'
Python example
import json
import os
import requests
with requests.get(
"https://api.bullflow.io/v1/streaming/live-options-flow",
headers={"X-API-Key": os.environ["BULLFLOW_API_KEY"]},
stream=True, timeout=(10, 35),
) as response:
response.raise_for_status()
for line in response.iter_lines(chunk_size=1, decode_unicode=True):
if not line or not line.startswith("data: "):
continue
message = json.loads(line[6:])
if message["event"] == "trade":
trade = message["data"]
print(trade["symbol"], trade["premium"], trade["timestamp"])
elif message["event"] == "date_changed":
print("Trading date:", message["date"])
elif message["event"] == "error":
print(message["message"])Live GEX setups
api.bullflow.io/v1/streaming/gexSetupsStreams newly created GEX setup alerts in real time. By default, the stream only delivers alerts created after the connection opens. Pass history=true to receive the current U.S. Eastern market date's alerts in the first SSE frame before live delivery begins.
Access & pricing
Included with an active API subscription and valid API key. Subscription pricing applies.
Prepaid credits and per-request x402 or MPP payments are not accepted on this endpoint.
Authentication
Requires an OAuth token with the relevant permission or an active Bullflow API key. For API keys, pass it as ?key=YOUR_API_KEY, an X-API-Key header, or an Authorization: Bearer YOUR_API_KEY header.
Query params
key— required when the API key is not supplied in a header.history— optional boolean, defaults tofalse. Whentrue, the first event contains all alerts from the current U.S. Eastern market date, ordered oldest-first.
Event payloads
- Each SSE
data:frame contains JSON. Use its top-leveleventfield to route the payload. event === "history"— sent first only whenhistory=true. Itsdataobject containsversion,date,timezone,alertCount, and an oldest-firstalertsarray.event === "init"— confirms the connection withmode(gex-setups) andstartedAt.event === "heartbeat"— keeps the connection alive and is safe to ignore.event === "gex_setup"— contains one newly created setup indata.- Every setup includes
id,type,ticker,slot,date,alertedAt,classification,severity,title,message,spotPrice, andpreviousSpotPrice. - Setup-specific fields may include
thresholdPercent,expiration,nodeStrike,nodeGex,distancePercent,absoluteDistancePercent,oldNodeStrike,newNodeStrike,oldNodeExpiration,newNodeExpiration,oldNodeGex,newNodeGex, andseverityScore. - Live setup frames also include an SSE
id:line matchingdata.id, which clients can use for deduplication. - Reconnecting with
history=truesends the current day's history again, so use each alert'sidif your client needs to deduplicate reconnects.
Python example code
import json
import requests
with requests.get(
"https://api.bullflow.io/v1/streaming/gexSetups",
params={"key": "YOUR_API_KEY", "history": "true"},
stream=True,
) as stream:
stream.raise_for_status()
for line in stream.iter_lines(decode_unicode=True):
if not line or not line.startswith("data: "):
continue
message = json.loads(line[6:])
event = message.get("event")
if event == "history":
history = message["data"]
print("history:", history["alertCount"], "alerts")
continue
if event == "heartbeat":
continue
if event == "gex_setup":
alert = message["data"]
print(alert["ticker"], alert["type"], alert["classification"])
History first-frame example
{
"event": "history",
"data": {
"version": 1,
"date": "2026-08-25",
"timezone": "America/New_York",
"alertCount": 1,
"alerts": [
{
"id": 1841,
"type": "gex_node_proximity",
"ticker": "SPY",
"alertedAt": "2026-08-25T14:30:04+00:00",
"classification": "neutral",
"title": "GEX Node Proximity",
"spotPrice": 648.21,
"nodeStrike": 650
}
]
}
}Live setup example
{
"event": "gex_setup",
"data": {
"id": 1842,
"type": "largest_node_moved_higher",
"ticker": "NVDA",
"date": "2026-08-25",
"alertedAt": "2026-08-25T14:35:12+00:00",
"classification": "bullish",
"severity": "high",
"title": "Largest GEX Node Moved",
"message": "The largest GEX node moved higher.",
"spotPrice": 181.42,
"oldNodeStrike": 180,
"newNodeStrike": 185
}
}Backtesting replay
api.bullflow.io/v1/streaming/backtestingReplays one historical trading day over SSE using your saved custom alerts plus Bullflow algo alerts from the regular session. The stream loads the day's trades, evaluates every trade against your current custom alert set, then emits matched custom alerts and algo alerts in replay order.
Access & pricing
Included with an active API subscription and valid API key. Subscription pricing applies.
Prepaid credits and per-request x402 or MPP payments are not accepted on this endpoint.
Query params
key— required API key value.date— required replay date inYYYY-MM-DDformat. Must be on or after2025-06-01and cannot be in the future.speed— optional replay speed multiplier. Passing1replays in real time.
Event payloads
- Each SSE
data:frame contains JSON. Parse that JSON and useeventto identify the payload type. event === "init"— includesmode(alerts-backtesting),replayDate, andconnected.event === "status"— a single initialization message:Initializing trades, custom alerts and algo alerts... This can take up to a minute.event === "ready"— includesreplayDate,speed,totalTrades,totalCustomAlerts,processedTrades,customAlerts,algoAlerts, andtotalReplayAlerts.event === "heartbeat"— emitted during replay gaps and includesplaybackTimesuch as10:42:14 EST.event === "alert"— includessequence,id, and adataobject withalertType,symbol,alertName,alertPremium,tradePrice,timestamp, andestTimestamp.data.alertType— eitheralgoorcustom.event === "complete"— includesalertsSent,totalTrades,customAlerts,algoAlerts,totalReplayAlerts, andelapsedSeconds.event === "error"— sent before the stream closes if the request cannot be loaded or replayed.- It is recommended to implement auto reconnect functionality in your SSE client in case the stream is disconnected for any reason.
Python example code
import json
import requests
with requests.get(
"https://api.bullflow.io/v1/streaming/backtesting",
params={"key": "YOUR_API_KEY", "date": "2026-04-08", "speed": 60},
stream=True,
) as stream:
stream.raise_for_status()
for line in stream.iter_lines(decode_unicode=True):
if not line or not line.startswith("data: "):
continue
message = json.loads(line[6:])
event = message.get("event")
if event == "status":
print("status:", message.get("message"))
continue
if event == "heartbeat":
print("heartbeat:", message.get("playbackTime"))
continue
if event == "alert":
alert = message.get("data") or {}
print(
"alert",
message.get("sequence"),
alert.get("alertType"),
alert.get("symbol"),
alert.get("alertName"),
alert.get("tradePrice"),
alert.get("estTimestamp"),
)
continue
if event == "complete":
print("finished replay:", message.get("alertsSent"), "events sent")
breakExample payload
{
"event": "alert",
"id": "16",
"sequence": 16,
"data": {
"alertType": "custom",
"symbol": "O:SPY260409P00676000",
"alertName": "Ultra Repeater",
"alertPremium": 63022,
"tradePrice": 1.31,
"timestamp": 1775672380,
"estTimestamp": "2026-04-09 10:46:20 EST"
}
}Backtesting replays both matched custom alerts and algo alerts in timestamp order.
Create alert
api.bullflow.io/v1/alerts/create-alertCreates a saved custom alert for the account associated with your API key.
Access & pricing
1 credit per successful response with a prepaid API key. Included with an active API subscription.
Use your API key with an active API subscription or enough prepaid credits. x402 and MPP payments are not accepted on this endpoint.
Limit: 60 requests per rolling 60 seconds per credential or payer, per endpoint. Throttled requests return HTTP 429 with Retry-After in seconds. Wait at least that long before retrying.
Authentication
- OAuth:
Authorization: Bearer YOUR_ACCESS_TOKEN, or query string:?key=YOUR_API_KEY - Header:
X-API-Key: YOUR_API_KEY - Header:
Authorization: Bearer YOUR_API_KEY
JSON body
name— required human-readable alert name.- Numeric range fields use clean min/max names:
premiumMin/premiumMax,dteMin/dteMax,otmPercentMin/otmPercentMax,scoreMin/scoreMax,strikeMin/strikeMax,impliedVolatilityMin/impliedVolatilityMax, and the other range fields shown in the YAML download. - Ticker filters:
tickerBlocklistexcludes tickers,tickerAllowlistlimits matches to specific tickers, and values are uppercased and deduped. - Quick filters: pass user-facing chip labels in
quickFilters. - Sector filter:
sectorCodedefaults to12. - Include switches:
includeCalls,includePuts,includeAskSide,includeBidSide,includeMid,includeBullish,includeBearish,includeNeutral,includeSingles,includeSweeps,includeSplits,includeBlocks,includeMultiLeg, andincludeExDividend.
Quick filter labels
Send labels in quickFilters. The tooltip text below describes what each quick filter means.
| Label | Tooltip |
|---|---|
| ETFs | ETFs |
| Stocks | Stocks |
| Sweeps | Trades executed rapidly across multiple exchanges |
| Calls | Call options |
| Puts | Put options |
| Bid | Trades executed on the bid side |
| Ask | Trades executed on the ask side |
| AA | Above Ask. They really wanted these contracts! |
| Unusual | Trade size exceeding open interest |
| Urgent | Rapid repeat trades matching Bullflow criteria |
| Bullflow | Aggressive repeat trades matching Bullflow criteria. |
| Position Builders | Consistent repeat trades matching Bullflow criteria |
| Sizable | Large Unusual Trades |
| Grenade | Risky short term trades |
| 100k+ | Trades with $100,000+ value |
| Whales | $1M+ |
| Rising Vol | First trade that hits the scanner where volume exceeds OI |
| AM Spike | Volume exceeding 15% of the OI, 25k OI minimum, before 11am EST |
| LEAPS | Long dated expirations |
| High Sig | SigScore 0.8+ |
| Repeat Flow | Contracts that have 3 or more size>OI trades. |
| Large Size | Size > 5000 |
| Earnings Soon | Earnings within 2 days |
| Vol>OI | Volume greater than open interest |
| Weeklies | Trades expiring within a week |
| Penny Stocks | Stock price < $5 |
| Oddities | Stocks not seen on Bullflow in a day |
| Unicorns | Stocks not seen on Bullflow in a week or longer |
| OTM | Out of the money |
| Bullish Flow | Stocks with 80%+ bullish/bearish ratio |
| > Avg | Total premium has exceeded the daily average for this stock. |
Validation
- Unknown fields are rejected. Numeric fields must be finite, and each min value must be less than or equal to its matching max value.
- Missing optional fields use broad defaults.
Example request
{
"name": "Large bullish SPY flow",
"premiumMin": 50000,
"tickerAllowlist": ["SPY"],
"includePuts": false,
"includeBearish": false,
"quickFilters": ["100k+"]
}JavaScript example code
const response = await fetch(
"https://api.bullflow.io/v1/alerts/create-alert?key=YOUR_API_KEY",
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
name: "Large bullish SPY flow",
premiumMin: 50000,
tickerAllowlist: ["SPY"],
includePuts: false,
includeBearish: false,
quickFilters: ["100k+"]
})
}
);
if (!response.ok) {
throw new Error(await response.text());
}
console.log(await response.json());Example response
{
"id": "abc123",
"status": "created",
"alertName": "Large bullish SPY flow"
}Custom Options Flow Alerts
api.bullflow.io/v1/alerts/custom-alertsReturns the saved custom alerts for the account associated with your API key.
Access & pricing
1 credit per successful response with a prepaid API key. Included with an active API subscription.
Separate agent payments: x402 · USDC on Base $0.01; MPP · USDC.e on Tempo $0.01; MPP · Card / Link SPT $0.50 per request. Confirm the final price in the live HTTP 402 quote.
A valid API key identifies your account with every payment method. Send it in X-API-Key alongside MPP payment authorization.
Limit: 60 requests per rolling 60 seconds per credential or payer, per endpoint. Throttled requests return HTTP 429 with Retry-After in seconds. Wait at least that long before retrying.
Authentication
- OAuth:
Authorization: Bearer YOUR_ACCESS_TOKEN, or query string:?key=YOUR_API_KEY - Header:
X-API-Key: YOUR_API_KEY - Header:
Authorization: Bearer YOUR_API_KEY
Response
count— number of saved custom alerts returned.alerts— saved alerts, including each alertid.quickFilters— user-facing quick filter labels for the alert.
Request examples
API-key example · use an active API subscription or enough prepaid credits. Without a subscription, each successful response costs 1 credit.
JavaScript example code
const response = await fetch(
"https://api.bullflow.io/v1/alerts/custom-alerts?key=YOUR_API_KEY"
);
if (!response.ok) {
throw new Error(await response.text());
}
console.log(await response.json());Example response
{
"count": 1,
"alerts": [
{
"id": "abc123",
"alertName": "Large bullish SPY flow",
"minPremium": 50000,
"maxPremium": 5000000000,
"quickFilters": ["100k+"],
"timestamp": "2026-05-13T18:24:00.000Z"
}
]
}Peak return
api.bullflow.io/v1/data/peakReturnReturns the highest percent return reached by an option contract after the trade timestamp you provide.
Access & pricing
10 credits per successful response with a prepaid API key. Included with an active API subscription.
Separate agent payments: x402 · USDC on Base $0.01; MPP · USDC.e on Tempo $0.01; MPP · Card / Link SPT $0.50 per request. Confirm the final price in the live HTTP 402 quote.
Subscription and prepaid access use a valid API key. A key is optional for separate x402 or MPP payments.
Query params
key— required for subscription or prepaid-credit access; optional when paying per request.sym— required option symbol, for exampleO:SPY260408C00520000.old_price— required entry price for the contract.trade_timestamp— required Unix timestamp for the trade.
Behavior
- Successful responses return a JSON object with the peak price and the peak percent return since the provided timestamp.
- Subscription requests require a valid API key. Per-request payments use the payment challenge instead.
- This endpoint is rate-limited to 60 requests per rolling 60 seconds per credential or payer, per endpoint.
Request examples
API-key example · use an active API subscription or enough prepaid credits. Without a subscription, each successful response costs 10 credits.
Python example code
import requests
response = requests.get(
"https://api.bullflow.io/v1/data/peakReturn",
params={
"key": "YOUR_API_KEY",
"sym": "O:SPY260408C00520000",
"old_price": 1.35,
"trade_timestamp": 1775669400,
},
timeout=30,
)
response.raise_for_status()
print(response.json())Example response
{
"peakPriceSinceTimestamp": "125.47",
"peakPercentReturnSinceTimestamp": 12.22
}Net GEX
api.bullflow.io/v1/data/netgexReturns calculated net GEX by strike and expiration, weighted by open interest or cumulative contract volume from the current or most recent U.S. Eastern trading day.
Access & pricing
4 credits per successful response with a prepaid API key. Included with an active API subscription.
Separate agent payments: x402 · USDC on Base $0.01; MPP · USDC.e on Tempo $0.01; MPP · Card / Link SPT $0.50 per request. Confirm the final price in the live HTTP 402 quote.
Subscription and prepaid access use a valid API key. A key is optional for separate x402 or MPP payments.
Query params
key— required for subscription or prepaid-credit access; optional when paying per request.ticker— required underlying ticker symbol, for exampleSPY.symis also accepted as an alias.type— optional:oi(default) weights exposure by open interest;volumeuses cumulative contracts traded during the current or most recent U.S. Eastern trading day.
Behavior
- Gamma and spot calculations refresh approximately every 5 seconds. Volume mode uses the latest available cumulative contract volume for the current or most recent U.S. Eastern trading day. Before a new session has volume, and on weekends or holidays, it uses the most recent completed trading day. Check as_of for the gamma and spot calculation timestamp.
- Successful responses return a JSON object with
ticker,spot_price,as_of, andstrikes. - Each strike row includes
expiration,strike,call_gex,put_gex,net_gex,call_gamma, andput_gamma. - GEX uses a 1% underlying-price move: gamma × selected contract count × 100 × spot price squared × 0.01. Gamma fields equal gamma × selected contract count × 100. Calls contribute positively and puts negatively;
net_gexis their sum. Expiration usesYYYYMMDDand strike prices are in dollars. - Once the current session has volume, all tickers use that session. Contracts with no volume in the selected session contribute zero. No matching volume returns an empty
strikesarray. Unavailable volume returns HTTP 503 withIntraday contract volume is temporarily unavailable. - Both weighting modes share this endpoint's limit of 60 requests per rolling 60 seconds per credential or payer, per endpoint.
- Each endpoint has a separate limit, shared across its tickers, dates, filters, and pages. API-key requests share the key’s limit, OAuth connections on the same account share its limit, and paid requests share the payer’s limit.
- Bursts are allowed within the quota. No minimum spacing is required between requests, but at most 60 requests are allowed in any rolling 60-second window.
- Throttled requests return HTTP 429 with Retry-After in seconds. Wait at least that long before retrying.
- Coordinate clients using the same credential or payer to stay within 60 requests per rolling 60 seconds per endpoint, and honor Retry-After on HTTP 429.
Request examples
API-key example · use an active API subscription or enough prepaid credits. Without a subscription, each successful response costs 4 credits.
Python example code
import requests
response = requests.get(
"https://api.bullflow.io/v1/data/netgex",
params={
"key": "YOUR_API_KEY",
"ticker": "SPY",
"type": "volume",
},
timeout=30,
)
response.raise_for_status()
print(response.json())Example response
{
"ticker": "SPY",
"spot_price": 500,
"as_of": "2026-10-08T14:00:00.000Z",
"strikes": [
{
"expiration": "20261009",
"strike": 500,
"call_gex": 50000,
"put_gex": 0,
"net_gex": 50000,
"call_gamma": 20,
"put_gamma": 0
}
]
}End-of-day GEX
api.bullflow.io/v1/data/eodGexAccess & pricing
4 credits per successful response with a prepaid API key. Included with an active API subscription.
Separate agent payments: x402 · USDC on Base $0.01; MPP · USDC.e on Tempo $0.01; MPP · Card / Link SPT $0.50 per request. Confirm the final price in the live HTTP 402 quote.
Subscription and prepaid access use a valid API key. A key is optional for separate x402 or MPP payments.
Retrieve an end-of-day gamma exposure snapshot using closing gamma and the closing underlying price, weighted by the open interest reported for the selected session. That open interest represents the previous trading day’s closing positions, identified by open_interest_date.
Historical coverage
History is ticker-dependent and may have gaps. Earliest available snapshots verified on 2026-10-19: AAPL and QQQ 2012-06-01; SPY 2017-01-03; HOOD 2021-08-05. These are verified coverage examples, not a universal cutoff or a guarantee for every session. Requests outside a ticker’s available history return HTTP 404.
Query parameters
ticker— Required underlying ticker, for example SPY.date— Optional trading date in YYYY-MM-DD format within the ticker’s available history. Defaults to the latest eligible session. Each session becomes eligible after 17:15 America/New_York; before then, the previous trading session is selected.
Response fields
ticker,date— Requested ticker and selected trading date.open_interest_date— Previous trading date represented by the session’s reported open interest. Intraday changes in positions are not included.timezone— America/New_York, used for trading dates.spot_price,as_of— Closing underlying price in USD and its timestamp in UTC.strikes— Rows withexpiration(YYYYMMDD),strike,call_gex,put_gex, andnet_gex, ordered by expiration and strike.
GEX is USD exposure per 1% underlying-price move: gamma × open interest × 100 × spot price² × 0.01. Calls are positive, puts negative, and net GEX is their sum. Expirations before the selected date and contracts without matching positive open interest are excluded.
Limit: 60 requests per rolling 60 seconds per credential or payer, per endpoint. HTTP 429 includes Retry-After in seconds. MCP tool: bullflow_eod_gex, with ticker and optional date.
400: invalid ticker/date, weekend, future or not-yet-eligible session. 402: active subscription, sufficient prepaid credits, or separate payment required. 404: no snapshot for the ticker/date, including dates before the ticker’s available history, gaps, or holidays. 429: rate limit exceeded. 502: temporarily unavailable. 504: request timed out.
Request examples
API-key example · use an active API subscription or enough prepaid credits. Without a subscription, each successful response costs 4 credits.
Python example
import requests
response = requests.get(
"https://api.bullflow.io/v1/data/eodGex",
params={"key": "YOUR_API_KEY", "ticker": "SPY", "date": "2026-10-14"},
timeout=30,
)
response.raise_for_status()
print(response.json())Example response
{
"ticker": "SPY",
"date": "2026-10-14",
"open_interest_date": "2026-10-13",
"timezone": "America/New_York",
"spot_price": 500,
"as_of": "2026-10-14T21:15:00.000Z",
"strikes": [
{
"expiration": "20261016",
"strike": 500,
"call_gex": 50000,
"put_gex": -25000,
"net_gex": 25000
}
]
}Net VEX
api.bullflow.io/v1/data/netvexReturns net VEX by strike and expiration.
Access & pricing
4 credits per successful response with a prepaid API key. Included with an active API subscription.
Separate agent payments: x402 · USDC on Base $0.01; MPP · USDC.e on Tempo $0.01; MPP · Card / Link SPT $0.50 per request. Confirm the final price in the live HTTP 402 quote.
Subscription and prepaid access use a valid API key. A key is optional for separate x402 or MPP payments.
Query params
key— required for subscription or prepaid-credit access; optional when paying per request.ticker— required underlying ticker symbol, for exampleSPY.symis also accepted as an alias.
Behavior
- Results are cached for 5 seconds per ticker. Repeated requests within that window may return the same calculation; the next request after expiry recalculates using the latest available data. Check as_of for the calculation timestamp.
- Successful responses return a JSON object with
ticker,spot_price,as_of, andstrikes. - Each strike row includes
expiration,strike,call_vex,put_vex,net_vex,call_vanna, andput_vanna. - Net VEX uses
spot_price * vanna * open_interestand calculatesnet_vexas call VEX plus put VEX. - This endpoint is rate-limited to 60 requests per rolling 60 seconds per credential or payer, per endpoint.
- Each endpoint has a separate limit, shared across its tickers, dates, filters, and pages. API-key requests share the key’s limit, OAuth connections on the same account share its limit, and paid requests share the payer’s limit.
- Bursts are allowed within the quota. No minimum spacing is required between requests, but at most 60 requests are allowed in any rolling 60-second window.
- Throttled requests return HTTP 429 with Retry-After in seconds. Wait at least that long before retrying.
- Coordinate clients using the same credential or payer to stay within 60 requests per rolling 60 seconds per endpoint, and honor Retry-After on HTTP 429.
Request examples
API-key example · use an active API subscription or enough prepaid credits. Without a subscription, each successful response costs 4 credits.
Python example code
import requests
response = requests.get(
"https://api.bullflow.io/v1/data/netvex",
params={
"key": "YOUR_API_KEY",
"ticker": "SPY",
},
timeout=30,
)
response.raise_for_status()
print(response.json())Example response
{
"ticker": "SPY",
"spot_price": 719.245,
"as_of": "2026-04-30T19:24:26.236Z",
"strikes": [
{
"expiration": "20260430",
"strike": 659,
"call_vex": 1204.33,
"put_vex": -455.12,
"net_vex": 749.21,
"call_vanna": 1.6744,
"put_vanna": -0.6328
}
]
}Options Activity Profile
api.bullflow.io/v1/data/optionsProfileA ticker snapshot of recorded Bullflow options activity: call and put volume, relative volume, premium, execution-side percentages, sweeps, short-dated concentration, and unusual contracts. Coverage is recorded options flow, not complete market-wide volume or premium. Cancelled trades are excluded.
Access & pricing
3 credits per successful response with a prepaid API key. Included with an active API subscription.
Separate agent payments: x402 · USDC on Base $0.01; MPP · USDC.e on Tempo $0.01; MPP · Card / Link SPT $0.50 per request. Confirm the final price in the live HTTP 402 quote.
Subscription and prepaid access use a valid API key. A key is optional for separate x402 or MPP payments.
Request and access
symbol is required: supply an underlying ticker such as AAPL; letters are normalized to uppercase. Use an API key with an active API subscription or enough prepaid credits in key or X-API-Key, or an active Bullflow Premium or API subscription with an OAuth bearer token with api:read. You can also pay per REST request with x402 or MPP; inspect the live payment challenge for methods and pricing. The limit is 60 requests per rolling 60 seconds per credential or payer, per endpoint. Honor Retry-After on HTTP 429. The MCP tool is bullflow_options_profile and accepts the same symbol input with subscriber access.
Session and comparison baseline
The latest date with recorded activity across tickers is selected. Before new-session activity, on weekends, and on holidays, this can be the most recent completed session. A ticker with no recorded trades returns zero totals for that selected session. Check tradingDate and asOf for freshness.
relativeVolumeDaily: selected-session recorded volume / average full-day recorded volume over the prior 20 available trading dates.relativeVolumeIntraday: selected-session recorded volume / average volume through the same Eastern time ofasOfover those dates. Daylight-saving changes are accounted for.callRelativeVolumeDaily,callRelativeVolumeIntraday,putRelativeVolumeDaily, andputRelativeVolumeIntradayapply the same formulas to calls or puts.- The selected session is excluded from the baseline. Dates with no activity for the ticker contribute zero; unavailable dates are not assumed to be zero-volume sessions. Shortened sessions contribute their available activity.
- Fewer than 20 prior dates makes relative-volume ratios
null. Ratios and percentages are alsonullwhen their denominator is zero. For a past session, the cutoff is23:59:59Eastern and both comparisons use full days.
Response fields
symbolandtradingDateidentify the ticker and selected trading session.asOfis the latest recorded trade time across tickers in the selected session, in UTC ISO 8601.activity:totalVolume,callVolume,putVolume, the relative-volume ratios above, andputCallRatio(put volume / call volume). Volumes sum recorded trade sizes, including multi-leg trades.premium:totalPremium,callPremium,putPremium, andnetDirectionalPremium, all in USD.- Directional premium = call ask premium − call bid premium − put ask premium + put bid premium. These four side premiums exclude multi-leg trades; mid and unknown executions contribute zero. Total call and put premiums include multi-leg trades. Execution-side direction does not establish opening positions or trader intent.
execution:callAskSidePercentandputAskSidePercent, from 0–100. Ask and above-ask contract volume is divided by all recorded volume for that option type.concentration:sweepPremium(USD),sweepVolumePercent, andshortDatedVolumePercent. Short-dated means 0–7 calendar days from the trading date, inclusive.unusualContracts: up to five contracts with recorded volume/OI > 1, ranked by ratio, then premium, then symbol. Fields aresymbol(option contract),type(CALL/PUT),strike,expiration,volume,openInterest,volumeOiRatio,premium, andaskSidePercent. OI uses its latest available observation; zero or missing OI is excluded. Strike is USD and expiration is YYYY-MM-DD; unavailable descriptive fields are null.largestPremiumTrade: a separate single trade, ornull. Includes contractsymbol,type,strike,expiration, UTCtimestamp, tradevolume, USDpremium,tradeType(SWEEP/BLOCK/MULTI), andside(Ask/Above Ask/Mid/Bid/Below Bid); unavailable descriptive fields are null.
Structured flags
INSUFFICIENT_HISTORY: fewer than 20 prior available trading dates.NO_RECORDED_ACTIVITY: no recorded ticker volume in the selected session.CALL_VOLUME_SPIKE/PUT_VOLUME_SPIKE: the corresponding intraday relative volume is at least 2.CALL_BUYING_SURGE: call intraday relative volume is at least 2 and call ask-side volume is at least 70%. This describes execution-side classification.UNUSUAL_WEEKLY_ACTIVITY: a contract expiring in 0–7 days has recorded volume/OI of at least 2. This does not identify the exchange's weekly listing designation.
HTTP 400 means a missing or invalid symbol; 401/403 indicate credential, subscription, or scope problems; 402 requests payment; 429 indicates the rate limit; 503 indicates unavailable activity; 504 indicates a timeout.
Request examples
API-key example · use an active API subscription or enough prepaid credits. Without a subscription, each successful response costs 3 credits.
Python example
import os
import requests
response = requests.get(
"https://api.bullflow.io/v1/data/optionsProfile",
headers={"X-API-Key": os.environ["BULLFLOW_API_KEY"]},
params={"symbol": "AAPL"},
timeout=35,
)
response.raise_for_status()
print(response.json())Example response · illustrative data
Not actual AAPL market activity.
{
"symbol": "AAPL",
"tradingDate": "2026-10-08",
"asOf": "2026-10-08T15:30:00.000Z",
"activity": {
"totalVolume": 325,
"callVolume": 270,
"putVolume": 55,
"relativeVolumeDaily": 4.0625,
"relativeVolumeIntraday": 10.8333,
"callRelativeVolumeDaily": 4.5,
"callRelativeVolumeIntraday": 13.5,
"putRelativeVolumeDaily": 2.75,
"putRelativeVolumeIntraday": 5.5,
"putCallRatio": 0.2037
},
"premium": {
"totalPremium": 3945,
"callPremium": 3240,
"putPremium": 705,
"netDirectionalPremium": 300
},
"execution": {
"callAskSidePercent": 74.07,
"putAskSidePercent": 72.73
},
"concentration": {
"sweepPremium": 1600,
"sweepVolumePercent": 43.08,
"shortDatedVolumePercent": 100
},
"unusualContracts": [
{
"symbol": "O:AAPL261009C00270000",
"type": "CALL",
"strike": 270,
"expiration": "2026-10-09",
"volume": 270,
"openInterest": 50,
"volumeOiRatio": 5.4,
"premium": 3240,
"askSidePercent": 74.07
}
],
"largestPremiumTrade": {
"symbol": "O:AAPL261009C00270000",
"type": "CALL",
"strike": 270,
"expiration": "2026-10-09",
"timestamp": "2026-10-08T14:00:00.000Z",
"volume": 100,
"premium": 2000,
"tradeType": "MULTI",
"side": "Ask"
},
"flags": [
"CALL_VOLUME_SPIKE",
"PUT_VOLUME_SPIKE",
"CALL_BUYING_SURGE",
"UNUSUAL_WEEKLY_ACTIVITY"
]
}Options top tickers
api.bullflow.io/v1/data/optionsTopTickersReturns the leading option-flow tickers ranked by volume, premium, or net premium for the current trading day, a selected date, or an inclusive date range.
Access & pricing
3 credits per successful response with a prepaid API key. Included with an active API subscription.
Separate agent payments: x402 · USDC on Base $0.01; MPP · USDC.e on Tempo $0.01; MPP · Card / Link SPT $0.50 per request. Confirm the final price in the live HTTP 402 quote.
Subscription and prepaid access use a valid API key. A key is optional for separate x402 or MPP payments.
Query params
key— required for subscription or prepaid-credit access; optional when paying per request.date— optional single trading date inYYYY-MM-DDformat. Cannot be combined withfromorto.from— optional start date for an inclusive range inYYYY-MM-DDformat. Must be supplied withto.to— optional end date for an inclusive range inYYYY-MM-DDformat. Must be supplied withfrom; the range cannot exceed 30 days.metric— optional ranking metric:volume,premium, ornet_premium. Defaults topremium.ticker_count— optional result count:10,20,30,40, or50. Defaults to20.exclude_etfs— optional boolean that excludes ETF option flow. Defaults tofalse.sweeps_only— optional boolean that limits results to sweep trades. Defaults tofalse.bullish_bearish— optional boolean fornet_premium. When enabled, returns a balanced selection of bullish and bearish leaders. Defaults tofalse.
Behavior
- When
date,from, andtoare omitted, the endpoint returns the current trading day's flow. - A supplied
datereturns that day's ranking. A suppliedfrom/topair aggregates all available trading days in the inclusive range. - Volume results include
totalVolume,callVolume, andputVolumefor each ticker. - Premium results include
totalPremium,callPremium, andputPremiumfor each ticker. - Net-premium results include directional call and put values plus ask-side and bid-side premium breakdowns.
totalNetPremiumis call net premium minus put net premium. - This endpoint is rate-limited to 60 requests per rolling 60 seconds per credential or payer, per endpoint.
Request examples
API-key example · use an active API subscription or enough prepaid credits. Without a subscription, each successful response costs 3 credits.
Python example code
import requests
response = requests.get(
"https://api.bullflow.io/v1/data/optionsTopTickers",
params={
"key": "YOUR_API_KEY",
"from": "2026-08-03",
"to": "2026-08-14",
"metric": "premium",
"ticker_count": 20,
"exclude_etfs": False,
"sweeps_only": False,
"bullish_bearish": False,
},
timeout=30,
)
response.raise_for_status()
print(response.json())Example response
{
"tradingDate": "2026-08-14",
"from": "2026-08-03",
"to": "2026-08-14",
"generatedAt": "2026-08-14T20:05:10.000Z",
"metric": "premium",
"tickerCount": 20,
"filters": {
"excludeEtfs": false,
"sweepsOnly": false,
"bullishBearish": false
},
"sourceTradeCount": 18420,
"matchedTradeCount": 16275,
"count": 2,
"rows": [
{
"ticker": "NVDA",
"totalPremium": 128450000,
"callPremium": 76400000,
"putPremium": 52050000
},
{
"ticker": "SPY",
"totalPremium": 113200000,
"callPremium": 58900000,
"putPremium": 54300000
}
]
}Historical options flow
api.bullflow.io/v1/data/historicalOptionsFlowQuery recorded options trades for a single trading date or an inclusive date range of up to 30 calendar days. Results are ordered by trading date and timestamp, newest first; cancelled trades are excluded.
Access & pricing
5 credits per successful response with a prepaid API key. Included with an active API subscription.
Separate agent payments: x402 · USDC on Base $0.01; MPP · USDC.e on Tempo $0.01; MPP · Card / Link SPT $0.50 per request. Confirm the final price in the live HTTP 402 quote.
Subscription and prepaid access use a valid API key. A key is optional for separate x402 or MPP payments.
Use an API key with an active API subscription or enough prepaid credits, or an eligible OAuth bearer token with api:read permission. No API key is required when paying per request. Dates refer to U.S. Eastern trading dates. The endpoint allows 60 requests per rolling 60 seconds per credential or payer, per endpoint; a 429 response includes Retry-After.
Query parameters
| Parameter | Description |
|---|---|
key | API key for subscription or prepaid-credit access; omit when using x402/MPP or an OAuth bearer token. |
date | Single YYYY-MM-DD date. Supply date or both from and to; never combine them. |
from / to | Inclusive YYYY-MM-DD range, up to 30 calendar days. Future dates are rejected. |
ticker | Optional underlying stock, ETF, or index ticker, such as SPY. Case-insensitive. |
symbol | Optional exact option contract symbol, such as O:SPY260925C00650000. Case-insensitive. |
optionType | C for calls or P for puts. |
tradeType | SWEEP, BLOCK, or MULTI. |
side | Ask, Above Ask, Mid, Bid, or Below Bid. |
minPremium / maxPremium | Inclusive total premium range in USD; nonnegative numbers. |
minSize / maxSize | Inclusive option contract count range; nonnegative integers. |
minScore | Minimum SigScore between 0 and 1. |
limit | Page size from 1 to 5000, default 500. |
cursor | nextCursor from the previous page; retain the same dates and trade filters. |
All supplied filters are combined. Minimum values cannot exceed their corresponding maximum values. Each response is one page; count counts that page's trades. Continue with nextCursor while hasMore is true. You may change limit between pages.
Response fields
The response includes from, to, timezone, each applied trade filter (or null when omitted), count, limit, hasMore, nextCursor, and rows. Dates without matching recorded trades return an empty rows array. Unavailable trade values are null.
| Trade fields | Description |
|---|---|
id | Trade identifier for deduplication. |
tradeDate / timestamp | YYYY-MM-DD trading date and Unix trade timestamp in seconds. |
symbol / ticker / optionType | Option contract symbol, underlying ticker, and C or P. |
expirationDate / strikePrice | YYYY-MM-DD expiration date and strike in USD. |
premium / tradePrice / tradeSize | Total premium in USD, option fill price in USD per share, and number of contracts. |
tradeType / side | Trade classification and execution side. |
spotPrice / currentBid / currentAsk | Underlying spot price and option bid/ask at the trade time, in USD. |
currentVolume / openInterest | Contract session volume at the trade time and open interest. |
impliedVolatility / sigScore | Implied volatility in percent and trade unusualness score from 0 to 1. |
delta / gamma / theta / vega / rho | Option Greeks at the trade time, when available. |
Invalid dates, filters, page sizes, or mismatched cursors return 400. Temporary data unavailability returns 503; a request timeout returns 504. Historical flow covers recorded Bullflow activity and should not be treated as a complete record of every options transaction.
Request examples
API-key example · use an active API subscription or enough prepaid credits. Without a subscription, each successful response costs 5 credits.
cURL example
curl --get 'https://api.bullflow.io/v1/data/historicalOptionsFlow' \ --data-urlencode "key=$BULLFLOW_API_KEY" \ --data-urlencode 'date=2026-09-25' \ --data-urlencode 'ticker=SPY' \ --data-urlencode 'minPremium=100000'
Python pagination example
import os
import time
import requests
params = {
"key": os.environ["BULLFLOW_API_KEY"],
"from": "2026-09-21", "to": "2026-09-25",
"ticker": "SPY", "minPremium": 100000, "limit": 500,
}
while True:
response = requests.get(
"https://api.bullflow.io/v1/data/historicalOptionsFlow",
params=params, timeout=35,
)
if response.status_code == 429:
time.sleep(int(response.headers.get("Retry-After", "1")))
continue
response.raise_for_status()
page = response.json()
for trade in page["rows"]:
print(trade["symbol"], trade["premium"], trade["timestamp"])
if not page["hasMore"]:
break
params["cursor"] = page["nextCursor"]
time.sleep(1)Example response · illustrative data
{
"from": "2026-09-25",
"to": "2026-09-25",
"ticker": "SPY",
"symbol": null,
"optionType": null,
"tradeType": null,
"side": null,
"minPremium": 100000,
"maxPremium": null,
"minSize": null,
"maxSize": null,
"minScore": null,
"timezone": "America/New_York",
"count": 1,
"limit": 500,
"hasMore": false,
"nextCursor": null,
"rows": [
{
"id": "2026-09-25:314159",
"tradeDate": "2026-09-25",
"timestamp": 1790344800,
"symbol": "O:SPY261016C00650000",
"ticker": "SPY",
"optionType": "C",
"expirationDate": "2026-10-16",
"strikePrice": 650,
"tradeType": "SWEEP",
"side": "Ask",
"premium": 150000,
"tradePrice": 3,
"tradeSize": 500,
"spotPrice": 649.5,
"currentBid": 2.95,
"currentAsk": 3,
"currentVolume": 1500,
"openInterest": 1000,
"impliedVolatility": 25,
"sigScore": 0.85,
"delta": null,
"gamma": null,
"theta": null,
"vega": null,
"rho": null
}
]
}Last trade price
api.bullflow.io/v1/data/lastTradePriceReturns the latest last trade price for a stock or supported index ticker.
Access & pricing
1 credit per successful response with a prepaid API key. Included with an active API subscription.
Separate agent payments: x402 · USDC on Base $0.01; MPP · USDC.e on Tempo $0.01; MPP · Card / Link SPT $0.50 per request. Confirm the final price in the live HTTP 402 quote.
Subscription and prepaid access use a valid API key. A key is optional for separate x402 or MPP payments.
Query params
key— required for subscription or prepaid-credit access; optional when paying per request.ticker— required stock or supported index ticker symbol, for exampleSPYorSPX.symis also accepted as an alias.
Behavior
- Successful responses return a JSON object with
lastTradePriceandtimestamp. When present,timestampis UTC and uses ISO 8601 format with a trailingZ. - Subscription requests require a valid API key. Per-request payments use the payment challenge instead.
- This endpoint is rate-limited to 60 requests per rolling 60 seconds per credential or payer, per endpoint.
Request examples
API-key example · use an active API subscription or enough prepaid credits. Without a subscription, each successful response costs 1 credit.
Python example code
import requests
response = requests.get(
"https://api.bullflow.io/v1/data/lastTradePrice",
params={
"key": "YOUR_API_KEY",
"ticker": "SPY",
},
timeout=30,
)
response.raise_for_status()
print(response.json())Example response
{
"lastTradePrice": 719.24,
"timestamp": "2026-04-30T19:24:26.236Z"
}GEX alerts
api.bullflow.io/v1/data/gexAlertsRead near-node and largest-node moved higher or lower alerts for the closest options expiration. Defaults to the current U.S. Eastern date and returns an empty list when no alerts exist.
Access & pricing
2 credits per successful response with a prepaid API key. Included with an active API subscription.
Separate agent payments: x402 · USDC on Base $0.01; MPP · USDC.e on Tempo $0.01; MPP · Card / Link SPT $0.50 per request. Confirm the final price in the live HTTP 402 quote.
Subscription and prepaid access use a valid API key. A key is optional for separate x402 or MPP payments.
Query params
key— your API key for subscription or prepaid-credit access; omit when paying per request or using an OAuth bearer token withapi:readpermission.date— optional single date inYYYY-MM-DDformat.fromandto— inclusive date range, up to 30 calendar days. Supply both; do not combine withdate.ticker— optional stock, ETF, or index ticker.type— optionalgex_node_proximity,largest_node_moved_higher, orlargest_node_moved_lower.limit— page size from 1 to 5,000; defaults to 500.cursor— the preceding response'snextCursor. Keep the same date, ticker, and type filters.
Response
Returns version, from, to, timezone, applied ticker and type filters (null when omitted),count, limit, hasMore, nextCursor, and alerts. The count is for the current page. Alerts are ordered by date, detection time, and identifier, newest first.
Each alert contains id, type, ticker, date,alertedAt, classification, severity, title,message, spotPrice, previousSpotPrice, thresholdPercent,expiration, nodeStrike, nodeGex, distancePercent, and absoluteDistancePercent. Movement alerts also populate oldNodeStrike,newNodeStrike, oldNodeExpiration, newNodeExpiration,oldNodeGex, newNodeGex, and severityScore. Fields that do not apply are null. Expirations use YYYYMMDD; prices are in USD, GEX values are signed, and distances are percentages.
Limits and errors
60 requests per rolling 60 seconds per credential or payer, per endpoint. Invalid parameters or cursors return 400. Throttled requests return 429 with Retry-After in seconds. Unavailable alert data returns 503; unexpected failures return 500.
Request examples
API-key example · use an active API subscription or enough prepaid credits. Without a subscription, each successful response costs 2 credits.
Python example
import os
import requests
response = requests.get(
"https://api.bullflow.io/v1/data/gexAlerts",
headers={"X-API-Key": os.environ["BULLFLOW_API_KEY"]},
params={"date": "2026-09-29", "ticker": "TSLA", "limit": 100},
timeout=30,
)
response.raise_for_status()
page = response.json()
print(page["alerts"])
# Use page["nextCursor"] with the same filters for the next page.Dark pool trades
api.bullflow.io/v1/data/darkPoolTradesReturns dark pool trades for an inclusive date range, optionally filtered by ticker.
Access & pricing
3 credits per successful response with a prepaid API key. Included with an active API subscription.
Separate agent payments: x402 · USDC on Base $0.01; MPP · USDC.e on Tempo $0.01; MPP · Card / Link SPT $0.50 per request. Confirm the final price in the live HTTP 402 quote.
Subscription and prepaid access use a valid API key. A key is optional for separate x402 or MPP payments.
Query params
key— required for subscription or prepaid-credit access; optional when paying per request.from— required start date inYYYY-MM-DDformat.to— required end date inYYYY-MM-DDformat.ticker— optional stock ticker symbol, for exampleSPY.limit— optional page size. Defaults to500and cannot exceed5000.cursor— optional pagination cursor from a previous response'snextCursorfield.minNotional— optional minimum trade notional value.
Behavior
- Date ranges are inclusive. Passing the same date for
fromandtoreturns trades for that day. - This endpoint returns trades reported through Nasdaq trade reporting data. Based on Nasdaq's public figures, FINRA/Nasdaq TRFs support more than 40% of total U.S. equities trading while off-exchange trading is over 45% of volume, making Nasdaq-reported off-exchange flow roughly 90% of U.S. off-exchange equity trading.
- The date range cannot exceed 30 days.
- Successful responses return
from,to,ticker,minNotional,count,limit,hasMore,nextCursor, androws. - When
hasMoreistrue, passnextCursorascursoron the next request to fetch the following page. - Condition codes can be cross-referenced against Nasdaq Trader's sale condition modifier definitions.
- This endpoint is rate-limited to 60 requests per rolling 60 seconds per credential or payer, per endpoint.
Request examples
API-key example · use an active API subscription or enough prepaid credits. Without a subscription, each successful response costs 3 credits.
Python example code
import requests
response = requests.get(
"https://api.bullflow.io/v1/data/darkPoolTrades",
params={
"key": "YOUR_API_KEY",
"from": "2026-04-01",
"to": "2026-04-01",
"ticker": "SPY",
"limit": 500,
"minNotional": 1000000,
},
timeout=30,
)
response.raise_for_status()
print(response.json())Example response
{
"from": "2026-04-01",
"to": "2026-04-01",
"ticker": "SPY",
"minNotional": 1000000,
"count": 1,
"limit": 500,
"hasMore": false,
"nextCursor": null,
"rows": [
{
"symbol": "SPY",
"tradeId": "123456789",
"sequence": 987654,
"exchange": "D",
"trfId": "N",
"price": 519.24,
"size": 10000,
"notional": 5192400,
"volume": 74231812,
"conditions": [37],
"sipTimestampMs": 1775067000000,
"trfTimestampMs": 1775067000123,
"pctDayVolume": 0.1348,
"volumePercent": 13.48,
"percent30DayVolume": 4.91,
"correctionOnlyUpdate": false,
"tradeDate": "2026-04-01"
}
]
}