Options Screener API — Filter Every U.S. Contract
/screen runs a constrained query across the entire options
snapshot at once — every contract on every underlying — and returns
matching rows. It’s the tool for cross-market questions: highest-IV names,
contracts where today’s volume exceeds open interest, high-open-interest contracts,
and so on.
Columns, filters, and sorts all use the same
supported chain fields. Option bid/ask
quotes, quote spreads, midpoint, NBBO, and last trades are not available; use
fair_market_value when a current valuation estimate is needed.
Calling it
// Unusual activity: today's volume above open interest
const hot = await cvApi.screen({
columns: ['underlying_ticker', 'ticker', 'strike_price', 'expiration_date',
'day_volume', 'open_interest', 'implied_volatility', 'fair_market_value'],
filters: [
{ field: 'day_volume', op: 'gt_field', field_ref: 'open_interest' },
{ field: 'open_interest', op: 'gt', value: 1000 },
],
sort: [{ field: 'day_volume', direction: 'desc' }],
limit: 100,
}); curl -X POST -H "Authorization: Bearer cv_live_..." \
-H "Content-Type: application/json" \
-d '{
"columns": ["underlying_ticker", "strike_price", "implied_volatility"],
"filters": [{ "field": "implied_volatility", "op": "gt", "value": 1.5 }],
"sort": [{ "field": "implied_volatility", "direction": "desc" }],
"limit": 50
}' \
https://tap.convexvalue.com/api/data/screen From a coding agent, the MCP tool is screen — see the MCP reference.
Request shape
| Parameter | Type | Description |
|---|---|---|
columns | string[] | Supported fields to return, in order. 1–32 entries; duplicates dropped. cvApi.screen() fills in its default set if omitted. |
filters required | object[] | Predicates ANDed together. Up to 16. Each is { field, op, value } or { field, op, field_ref }. An empty array matches everything. |
sort | object[] | Up to 4 entries of { field, direction: "asc" | "desc" }. Direction defaults to ascending. |
limit | integer | Max rows. Default 100, capped at 500. The response sets truncated: true when more rows matched. |
Operators
Value operators compare a field to a literal value (number or string):
| op | Type | Description |
|---|---|---|
eq | value | equals |
ne | value | not equal |
gt | value | greater than |
gte | value | greater than or equal |
lt | value | less than |
lte | value | less than or equal |
Field operators compare a field to another field on the same
contract via field_ref — this is how you express relationships like
“volume above open interest” without pulling everything client-side:
| op | Type | Description |
|---|---|---|
eq_field | field_ref | field equals another field |
ne_field | field_ref | field differs from another field |
gt_field | field_ref | field greater than another field |
gte_field | field_ref | field ≥ another field |
lt_field | field_ref | field less than another field |
lte_field | field_ref | field ≤ another field |
Validation is strict: value operators must include value and must not
include field_ref; field operators the reverse. Anything else returns
400.
Response shape
Rows are arrays in the same order as columns — compact to transfer and cheap to feed straight into a table or chart:
{
"columns": ["underlying_ticker", "strike_price", "implied_volatility"],
"rows": [
["GME", 20.0, 2.41],
["MARA", 15.0, 1.98]
],
"row_count": 2,
"truncated": false,
"elapsed_ms": 87
} Limits at a glance
| Constraint | Limit |
|---|---|
| Columns | 32 max (min 1) |
| Filters | 16 max (0 allowed) |
| Sort keys | 4 max |
| Rows returned | default 100, max 500 (truncated flags overflow) |
Need more than 500 rows or GROUP BY-style aggregation? Use SQL queries instead.
Prefer a working interface first? Start with the custom options screener and its curated templates.
Get example prompts & new data guides
Occasional emails with prompts worth trying and what’s new in the data.