Option Contract Minute History API - Per-Contract Buy/Sell Volume | FlashAlpha
  1. Contract Minute History

Option Contract Minute History API

Minute buckets of buy, sell and mid classified volume for every option contract (strike, right, expiry) on an underlying. Sum buys minus sells per strike for net customer flow.

Endpoint

GET /v1/flow/options/{symbol}/option-minute-history
Auth required (X-Api-Key) Rate Limited: Yes Plan: Alpha+

Parameters

Name In Type Required Default Description
symbol path string required - Underlying symbol (case-insensitive)
expiry query date - Only contracts of one expiration, yyyy-MM-dd. Omit to return every expiry - a large payload on busy chains (SPY: about 7 MB). Invalid values return 400 invalid_expiry. An expiry with no data returns an empty result, not an error.

Request

curl -H "X-Api-Key: YOUR_API_KEY" \
  "https://lab.flashalpha.com/v1/flow/options/SPY/option-minute-history?expiry=2026-12-18"
import requests
from collections import defaultdict

resp = requests.get(
    "https://lab.flashalpha.com/v1/flow/options/SPY/option-minute-history",
    params={"expiry": "2026-12-18"},
    headers={"X-Api-Key": "YOUR_API_KEY"}
)
resp.raise_for_status()
data = resp.json()

# net customer flow per strike = sum of (buy - sell) over all minutes
net = defaultdict(int)
for c in data["contracts"]:
    net[c["strike"]] += sum(b["buy"] - b["sell"] for b in c["buckets"])
for strike in sorted(net):
    print(strike, net[strike])
const resp = await fetch(
  "https://lab.flashalpha.com/v1/flow/options/SPY/option-minute-history?expiry=2026-12-18",
  { headers: { "X-Api-Key": "YOUR_API_KEY" } }
);
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
const data = await resp.json();

// net customer flow per strike = sum of (buy - sell) over all minutes
const net = {};
for (const c of data.contracts) {
  for (const b of c.buckets) net[c.strike] = (net[c.strike] || 0) + b.buy - b.sell;
}
console.log(net);

Try it live

Runs on live market data and uses 1 request from your daily quota.

GET

Response

{
  "symbol": "SPY",
  "contracts": [
    {
      "strike": 300,
      "right": "C",
      "expiry": "2026-12-18",
      "buckets": [
        {
          "t": "2026-10-29T13:55:00Z",
          "buy": 0,
          "sell": 0,
          "mid": 1
        },
        {
          "t": "2026-10-29T14:14:00Z",
          "buy": 1,
          "sell": 0,
          "mid": 0
        }
      ]
    },
    {
      "strike": 375,
      "right": "P",
      "expiry": "2026-12-18",
      "buckets": [
        {
          "t": "2026-10-29T15:36:00Z",
          "buy": 2,
          "sell": 0,
          "mid": 0
        }
      ]
    }
  ],
  "endpoint_version": "2026.09.30",
  "data_as_of": {
    "node": "fa5",
    "equity_feed": "2026-10-30T14:15:29.104Z",
    "equity_options_feed": "2026-10-30T14:15:28Z",
    "index_feed": "2026-10-30T14:15:29.102Z",
    "index_options_feed": "2026-10-30T14:15:27Z",
    "futures_feed": "2026-10-30T14:15:28.643Z",
    "futures_options_feed": "2026-10-30T14:15:27.966Z",
    "flow_feed": "2026-10-30T14:15:00Z",
    "oi_feed": "2026-10-29T20:00:00Z",
    "macro_feed": "2026-10-29T21:00:20Z"
  }
}

Sending request…

See this endpoint on live data

Send this exact request and the real response shows up here, right next to the example.

Responses can exceed 380 KB.

Response Fields

Field Type Description
symbolstringUppercase underlying symbol
contracts[]arrayOne item per option contract that traded. Empty when there is no flow for the symbol or expiry (still 200). Not sorted.
contracts[].strikenumberStrike price
contracts[].rightstringC (call) or P (put)
contracts[].expirystringExpiration date, yyyy-MM-dd
contracts[].buckets[]arrayMinutes with trades only, oldest first
contracts[].buckets[].tstringMinute start (UTC)
contracts[].buckets[].buynumberContracts bought at the ask in that minute
contracts[].buckets[].sellnumberContracts sold at the bid in that minute
contracts[].buckets[].midnumberContracts traded at mid in that minute
endpoint_version, data_as_ofstring, objectResponse envelope, see Response envelope.

Errors

Status Error When
400invalid_expiryexpiry is not a valid yyyy-MM-dd date.
401-Missing or invalid X-Api-Key. The body is empty; check the status code before parsing JSON.
403tier_restrictedYour plan is below Alpha. The body includes current_plan and required_plan.
429Quota exceededDaily quota used up. Retry-After gives the seconds until the reset at 00:00 UTC. Rejected requests (including 403) count toward the quota.

About

Returns the option tape of an underlying split by contract: for every strike, right and expiry that traded, one bucket per minute with the contracts bought, sold and traded at mid. Sum buy - sell per strike for net customer flow. The inferred dealer inventory change is its negation, sell - buy, accumulating from zero at the 09:30 ET open - a change over the session, never an absolute dealer position.

Without expiry the response covers the whole chain and can be large (SPY: about 4,500 contracts and 7 MB). Filter to one expiry when you only need one cycle. For totals per underlying instead of per contract, use Options Trade History.

Common Use Cases

  • Net customer flow by strike - sum buy - sell over every bucket of each strike to see where customers bought or sold options today
  • Dealer inventory change by strike - negate the customer flow (sell - buy) to estimate how dealer positioning changed since the open
  • Strike x time heatmap - plot per-minute net flow for each strike to see when and where activity concentrated
  • One expiry cycle - pass expiry to follow flow into a single OPEX or weekly without downloading the full chain
  • Calls vs puts - split by right to compare call and put buying at the same strike

Related reading

Complementary endpoints

  • Options Trade History - the same minute flow rolled up per underlying, with VWAP and high/low
  • Options Recent Trades - the individual prints behind each bucket
  • Flow GEX - ?polarity=flow signs each strike by the dealer inventory change inferred from the tape
  • 0DTE Strike Flow - per-strike signed aggressor flow for the same-day expiry

Ready to build with FlashAlpha?

Get your free API key and start pulling live options data in 60 seconds.

No credit card required Setup in 60 seconds Secure & reliable