Dashboard
Developer resources v1

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.

Options flow guide

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

  1. Preview the quote. Your agent makes an unpaid request and reads the price and payment requirements in Bullflow’s HTTP 402 response.
  2. 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.
  3. 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.
  4. Approve the purchase. Review the selected method’s quoted amount and authorize this request.
  5. 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.

Payment-required response — example JSON body · json
{
  "error": "Payment required"
}
x402 · USDC on Base
Read the PAYMENT-REQUIRED header and retry with proof in PAYMENT-SIGNATURE.
MPP · Stripe cards or Tempo crypto
Read the challenges in WWW-Authenticate. Retry with Authorization: Payment or Payment-Authorization. A successful MPP payment returns a Payment-Receipt header.

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.

Pay by card with Shared Payment Tokens

Or pay with Crypto

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.

  • 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

  1. Preview the live card quote. Make an unpaid request. Your agent reads the Stripe challenge in WWW-Authenticate and 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"
  2. 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 list
    Connect only if needed · shell
    npx @stripe/link-cli auth login --client-name "Bullflow agent" --interval 5 --timeout 300
  3. 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-id for 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
  4. 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 pay can 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
  5. Confirm the data arrived. Your agent checks Bullflow’s HTTP status, returned data, and Payment-Receipt. Link’s approved status 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.

  1. 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
  2. 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"
  3. 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 whoami
    Open wallet funding · shell
    tempo wallet fund
  4. 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
  5. 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"
  6. 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-Key as 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

MCP server

POSTapi.bullflow.io/mcp

Connect 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. GET and DELETE are 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 isError in 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 supported ticker, 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 supported ticker, 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 supported ticker, 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. Accepts ticker and optional type: oi (default) or volume. 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.

Alerts

Live Options Flow Alerts

GETapi.bullflow.io/v1/streaming/alerts

Streams 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 use event to identify the payload type.
  • event === "init" — provides mode (alerts) and startedAt (ISO timestamp).
  • event === "heartbeat" — emitted every 10 seconds to keep the connection alive; safe to ignore.
  • event === "alert" — includes the alert id and the alert payload in data.
  • Alert payloads include data.alertType, data.symbol, data.alertName, data.alertPremium, data.averageFillPrice, and data.timestamp.
  • data.alertType — either algo (Bullflow algo alerts such as Urgent Repeater, Sizable Sweep, etc.) or custom (alerts matching the custom alerts you set in the Bullflow dashboard).
  • Alert payloads also include data.latency, data.deliveryLatency, and data.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.

Streaming

Live options flow

GETapi.bullflow.io/v1/streaming/live-options-flow

Stream 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-After on 429 responses.
  • Reconnect with a delay after disconnection. New connections deliver future trades only; Last-Event-ID does not replay missed trades.
  • Temporary interruptions can emit error events while delivery is retried. Slow clients can be disconnected, so consume incoming frames promptly.

SSE events

EventPayload
initIncludes mode: live-options-flow, date, timezone, and ISO timestamp startedAt.
tradeA trade in data. The JSON id, data.id, and SSE id: line match.
heartbeatSent every 10 seconds with an ISO timestamp, including when no trades arrive.
date_changedIncludes the new YYYY-MM-DD date and timezone: America/New_York.
errorIncludes a message describing a temporary interruption; delivery is being retried.

Trade fields

FieldsDescription
id / tradeDate / timestampTrade identifier, YYYY-MM-DD trading date, and Unix trade timestamp in seconds.
symbol / ticker / optionTypeOption contract symbol, underlying ticker, and C or P.
expirationDate / strikePriceYYYY-MM-DD expiration date and strike in USD.
premium / tradePrice / tradeSizeTotal premium in USD, option fill price in USD per share, and number of contracts.
tradeType / sideSWEEP, BLOCK, or MULTI, and Ask, Above Ask, Mid, Bid, or Below Bid when classified.
spotPrice / currentBid / currentAskUnderlying price and option bid/ask at the trade time, in USD.
currentVolume / openInterestContract session volume at the trade time and open interest.
impliedVolatility / sigScoreImplied volatility in percent and unusualness score from 0 to 1.
delta / gamma / theta / vega / rhoOption Greeks at the trade time.
isCancelled / isOutOfSequenceWhether 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"])
GEX

Live GEX setups

GETapi.bullflow.io/v1/streaming/gexSetups

Streams 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 to false. When true, 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-level event field to route the payload.
  • event === "history" — sent first only when history=true. Its data object contains version, date, timezone, alertCount, and an oldest-first alerts array.
  • event === "init" — confirms the connection with mode (gex-setups) and startedAt.
  • event === "heartbeat" — keeps the connection alive and is safe to ignore.
  • event === "gex_setup" — contains one newly created setup in data.
  • Every setup includes id, type, ticker, slot, date, alertedAt, classification, severity, title, message, spotPrice, and previousSpotPrice.
  • Setup-specific fields may include thresholdPercent, expiration, nodeStrike, nodeGex, distancePercent, absoluteDistancePercent, oldNodeStrike, newNodeStrike, oldNodeExpiration, newNodeExpiration, oldNodeGex, newNodeGex, and severityScore.
  • Live setup frames also include an SSE id: line matching data.id, which clients can use for deduplication.
  • Reconnecting with history=true sends the current day's history again, so use each alert's id if 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

Backtesting replay

GETapi.bullflow.io/v1/streaming/backtesting

Replays 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 in YYYY-MM-DD format. Must be on or after 2025-06-01 and cannot be in the future.
  • speed — optional replay speed multiplier. Passing 1 replays in real time.

Event payloads

  • Each SSE data: frame contains JSON. Parse that JSON and use event to identify the payload type.
  • event === "init" — includes mode (alerts-backtesting), replayDate, and connected.
  • event === "status" — a single initialization message: Initializing trades, custom alerts and algo alerts... This can take up to a minute.
  • event === "ready" — includes replayDate, speed, totalTrades, totalCustomAlerts, processedTrades, customAlerts, algoAlerts, and totalReplayAlerts.
  • event === "heartbeat" — emitted during replay gaps and includes playbackTime such as 10:42:14 EST.
  • event === "alert" — includes sequence, id, and a data object with alertType, symbol, alertName, alertPremium, tradePrice, timestamp, and estTimestamp.
  • data.alertType — either algo or custom.
  • event === "complete" — includes alertsSent, totalTrades, customAlerts, algoAlerts, totalReplayAlerts, and elapsedSeconds.
  • 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")
            break

Example 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.

Alerts

Create alert

POSTapi.bullflow.io/v1/alerts/create-alert

Creates 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: tickerBlocklist excludes tickers, tickerAllowlist limits matches to specific tickers, and values are uppercased and deduped.
  • Quick filters: pass user-facing chip labels in quickFilters.
  • Sector filter: sectorCode defaults to 12.
  • Include switches: includeCalls, includePuts, includeAskSide, includeBidSide, includeMid, includeBullish, includeBearish, includeNeutral, includeSingles, includeSweeps, includeSplits, includeBlocks, includeMultiLeg, and includeExDividend.

Quick filter labels

Send labels in quickFilters. The tooltip text below describes what each quick filter means.

LabelTooltip
ETFsETFs
StocksStocks
SweepsTrades executed rapidly across multiple exchanges
CallsCall options
PutsPut options
BidTrades executed on the bid side
AskTrades executed on the ask side
AAAbove Ask. They really wanted these contracts!
UnusualTrade size exceeding open interest
UrgentRapid repeat trades matching Bullflow criteria
BullflowAggressive repeat trades matching Bullflow criteria.
Position BuildersConsistent repeat trades matching Bullflow criteria
SizableLarge Unusual Trades
GrenadeRisky short term trades
100k+Trades with $100,000+ value
Whales$1M+
Rising VolFirst trade that hits the scanner where volume exceeds OI
AM SpikeVolume exceeding 15% of the OI, 25k OI minimum, before 11am EST
LEAPSLong dated expirations
High SigSigScore 0.8+
Repeat FlowContracts that have 3 or more size>OI trades.
Large SizeSize > 5000
Earnings SoonEarnings within 2 days
Vol>OIVolume greater than open interest
WeekliesTrades expiring within a week
Penny StocksStock price < $5
OdditiesStocks not seen on Bullflow in a day
UnicornsStocks not seen on Bullflow in a week or longer
OTMOut of the money
Bullish FlowStocks with 80%+ bullish/bearish ratio
> AvgTotal 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"
}
Alerts

Custom Options Flow Alerts

GETapi.bullflow.io/v1/alerts/custom-alerts

Returns 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 alert id.
  • 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

GETapi.bullflow.io/v1/data/peakReturn

Returns 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 example O: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

GETapi.bullflow.io/v1/data/netgex

Returns 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 example SPY. sym is also accepted as an alias.
  • type — optional: oi (default) weights exposure by open interest; volume uses 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, and strikes.
  • Each strike row includes expiration, strike, call_gex, put_gex, net_gex, call_gamma, and put_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_gex is their sum. Expiration uses YYYYMMDD and 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 strikes array. Unavailable volume returns HTTP 503 with Intraday 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

GETapi.bullflow.io/v1/data/eodGex

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.

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 with expiration (YYYYMMDD), strike, call_gex, put_gex, and net_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

GETapi.bullflow.io/v1/data/netvex

Returns 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 example SPY. sym is 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, and strikes.
  • Each strike row includes expiration, strike, call_vex, put_vex, net_vex, call_vanna, and put_vanna.
  • Net VEX uses spot_price * vanna * open_interest and calculates net_vex as 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
    }
  ]
}

Net premium

GETapi.bullflow.io/v1/data/netPremiumSeries

Returns chronological cumulative call and put net premium values for a ticker and inclusive date range.

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 — required for subscription or prepaid-credit access; optional when paying per request.
  • ticker — required underlying ticker symbol, for example SPY.
  • from — required inclusive start date in YYYY-MM-DD format.
  • to — required inclusive end date in YYYY-MM-DD format.
  • period — optional aggregation period: 1D, 7D, 1M, 3M, 1Y, or MAX. Defaults to 1D.
  • include_multileg — optional boolean. Defaults to false.
  • sweeps_only — optional boolean. Defaults to false.

Behavior

  • Each point contains a Unix timestamp, cumulative callsNetPremium, and cumulative putsNetPremium.
  • bucket_seconds reports the time bucket size. A value of 0 means individual time points.
  • Results are returned in chronological order.
  • 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 2 credits.

Python example code

import requests

response = requests.get(
    "https://api.bullflow.io/v1/data/netPremiumSeries",
    params={
        "key": "YOUR_API_KEY",
        "ticker": "SPY",
        "from": "2026-07-24",
        "to": "2026-07-24",
        "period": "1D",
        "include_multileg": False,
        "sweeps_only": False,
    },
    timeout=30,
)
response.raise_for_status()
print(response.json())

Example response

{
  "ticker": "SPY",
  "period": "1D",
  "from": "2026-07-24",
  "to": "2026-07-24",
  "include_multileg": false,
  "sweeps_only": false,
  "multilegs_filtered_count": 593,
  "sweeps_filtered_count": 0,
  "bucket_seconds": 0,
  "point_count": 2,
  "points": [
    {
      "timestamp": 1784899805,
      "callsNetPremium": -274992,
      "putsNetPremium": 0
    },
    {
      "timestamp": 1784899812,
      "callsNetPremium": -449529,
      "putsNetPremium": 125000
    }
  ]
}

Options Activity Profile

GETapi.bullflow.io/v1/data/optionsProfile

A 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 of asOf over those dates. Daylight-saving changes are accounted for.
  • callRelativeVolumeDaily, callRelativeVolumeIntraday, putRelativeVolumeDaily, and putRelativeVolumeIntraday apply 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 also null when their denominator is zero. For a past session, the cutoff is 23:59:59 Eastern and both comparisons use full days.

Response fields

  • symbol and tradingDate identify the ticker and selected trading session.
  • asOf is the latest recorded trade time across tickers in the selected session, in UTC ISO 8601.
  • activity: totalVolume, callVolume, putVolume, the relative-volume ratios above, and putCallRatio (put volume / call volume). Volumes sum recorded trade sizes, including multi-leg trades.
  • premium: totalPremium, callPremium, putPremium, and netDirectionalPremium, 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: callAskSidePercent and putAskSidePercent, from 0–100. Ask and above-ask contract volume is divided by all recorded volume for that option type.
  • concentration: sweepPremium (USD), sweepVolumePercent, and shortDatedVolumePercent. 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 are symbol (option contract), type (CALL/PUT), strike, expiration, volume, openInterest, volumeOiRatio, premium, and askSidePercent. 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, or null. Includes contract symbol, type, strike, expiration, UTC timestamp, trade volume, USD premium, tradeType (SWEEP/BLOCK/MULTI), and side (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

GETapi.bullflow.io/v1/data/optionsTopTickers

Returns 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 in YYYY-MM-DD format. Cannot be combined with from or to.
  • from — optional start date for an inclusive range in YYYY-MM-DD format. Must be supplied with to.
  • to — optional end date for an inclusive range in YYYY-MM-DD format. Must be supplied with from; the range cannot exceed 30 days.
  • metric — optional ranking metric: volume, premium, or net_premium. Defaults to premium.
  • ticker_count — optional result count: 10, 20, 30, 40, or 50. Defaults to 20.
  • exclude_etfs — optional boolean that excludes ETF option flow. Defaults to false.
  • sweeps_only — optional boolean that limits results to sweep trades. Defaults to false.
  • bullish_bearish — optional boolean for net_premium. When enabled, returns a balanced selection of bullish and bearish leaders. Defaults to false.

Behavior

  • When date, from, and to are omitted, the endpoint returns the current trading day's flow.
  • A supplied date returns that day's ranking. A supplied from/to pair aggregates all available trading days in the inclusive range.
  • Volume results include totalVolume, callVolume, and putVolume for each ticker.
  • Premium results include totalPremium, callPremium, and putPremium for each ticker.
  • Net-premium results include directional call and put values plus ask-side and bid-side premium breakdowns. totalNetPremium is 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

GETapi.bullflow.io/v1/data/historicalOptionsFlow

Query 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

ParameterDescription
keyAPI key for subscription or prepaid-credit access; omit when using x402/MPP or an OAuth bearer token.
dateSingle YYYY-MM-DD date. Supply date or both from and to; never combine them.
from / toInclusive YYYY-MM-DD range, up to 30 calendar days. Future dates are rejected.
tickerOptional underlying stock, ETF, or index ticker, such as SPY. Case-insensitive.
symbolOptional exact option contract symbol, such as O:SPY260925C00650000. Case-insensitive.
optionTypeC for calls or P for puts.
tradeTypeSWEEP, BLOCK, or MULTI.
sideAsk, Above Ask, Mid, Bid, or Below Bid.
minPremium / maxPremiumInclusive total premium range in USD; nonnegative numbers.
minSize / maxSizeInclusive option contract count range; nonnegative integers.
minScoreMinimum SigScore between 0 and 1.
limitPage size from 1 to 5000, default 500.
cursornextCursor 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 fieldsDescription
idTrade identifier for deduplication.
tradeDate / timestampYYYY-MM-DD trading date and Unix trade timestamp in seconds.
symbol / ticker / optionTypeOption contract symbol, underlying ticker, and C or P.
expirationDate / strikePriceYYYY-MM-DD expiration date and strike in USD.
premium / tradePrice / tradeSizeTotal premium in USD, option fill price in USD per share, and number of contracts.
tradeType / sideTrade classification and execution side.
spotPrice / currentBid / currentAskUnderlying spot price and option bid/ask at the trade time, in USD.
currentVolume / openInterestContract session volume at the trade time and open interest.
impliedVolatility / sigScoreImplied volatility in percent and trade unusualness score from 0 to 1.
delta / gamma / theta / vega / rhoOption 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

GETapi.bullflow.io/v1/data/lastTradePrice

Returns 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 example SPY or SPX. sym is also accepted as an alias.

Behavior

  • Successful responses return a JSON object with lastTradePrice and timestamp. When present, timestamp is UTC and uses ISO 8601 format with a trailing Z.
  • 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

GETapi.bullflow.io/v1/data/gexAlerts

Read 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 with api:read permission.
  • date — optional single date in YYYY-MM-DD format.
  • from and to — inclusive date range, up to 30 calendar days. Supply both; do not combine with date.
  • ticker — optional stock, ETF, or index ticker.
  • type — optional gex_node_proximity, largest_node_moved_higher, or largest_node_moved_lower.
  • limit — page size from 1 to 5,000; defaults to 500.
  • cursor — the preceding response's nextCursor. 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

GETapi.bullflow.io/v1/data/darkPoolTrades

Returns 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 in YYYY-MM-DD format.
  • to — required end date in YYYY-MM-DD format.
  • ticker — optional stock ticker symbol, for example SPY.
  • limit — optional page size. Defaults to 500 and cannot exceed 5000.
  • cursor — optional pagination cursor from a previous response's nextCursor field.
  • minNotional — optional minimum trade notional value.

Behavior

  • Date ranges are inclusive. Passing the same date for from and to returns 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, and rows.
  • When hasMore is true, pass nextCursor as cursor on 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"
    }
  ]
}