Guide · July 24, 2026

Options screener API with Python: a complete request

Written and reviewed by ConvexValue · Updated July 24, 2026

cvforge’s /screen endpoint applies constrained filters and sorts across the current U.S. options snapshot. It is useful when your Python program needs a shortlist, not a full-market data transfer.

External API-key access is included with Go and Research. Inside a cvforge app, use window.cvApi.screen() instead; cvforge injects the key outside the page.

The Python request

Create a personal key in your cvforge account, put it in the CVFORGE_API_KEY environment variable, and install requests. Do not paste a real key into source control.

import os
import requests

api_key = os.environ["CVFORGE_API_KEY"]

request_body = {
    "columns": [
        "underlying_ticker",
        "ticker",
        "contract_type",
        "expiration_date",
        "strike_price",
        "fair_market_value",
        "day_volume",
        "open_interest",
        "implied_volatility",
    ],
    "filters": [
        {
            "field": "day_volume",
            "op": "gt_field",
            "field_ref": "open_interest",
        },
        {"field": "open_interest", "op": "gte", "value": 100},
        {"field": "day_volume", "op": "gte", "value": 100},
    ],
    "sort": [{"field": "day_volume", "direction": "desc"}],
    "limit": 100,
}

response = requests.post(
    "https://tap.convexvalue.com/api/data/screen",
    headers={
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json",
    },
    json=request_body,
    timeout=30,
)
response.raise_for_status()

payload = response.json()
columns = payload["columns"]
records = [dict(zip(columns, row, strict=True)) for row in payload["rows"]]

for record in records[:10]:
    oi = record.get("open_interest") or 0
    record["volume_oi"] = record["day_volume"] / oi if oi > 0 else None
    print(record)

if payload.get("truncated"):
    print("More contracts matched than the requested row limit.")

gt_field performs the volume/open-interest comparison on each contract before rows are returned. Literal comparisons use operators such as gt, gte, lt, and lte with a value instead.

fair_market_value is Massive’s proprietary valuation estimate. cvforge does not provide option bids, asks, midpoint, quote sizes, NBBO, or last trades, so FMV must not be presented as an executable quote or used to infer a quoted spread.

Response shape

The response contains an ordered columns list and compact row arrays in that same order, plus row_count, truncated, and elapsed_ms. Zipping the two arrays produces dictionaries without hard-coding column positions.

The API allows 1–32 columns, up to 16 filters, up to 4 sort keys, and at most 500 returned rows. If truncated is true, tighten the filters or split the research question; do not assume the visible rows are the entire match set.

Cadence and errors

The serving snapshot refreshes about once a minute. Session volume changes intraday; open interest updates daily after the close. Common responses are:

  • 400 for an unknown field, invalid operator, or malformed request;
  • 401 for a missing or revoked key;
  • 429 when the plan’s hourly request limit is exhausted.

The Free plan includes the screener inside cvforge but not a personal key for external Python. Go adds the personal API key and 1,000 requests per hour; Research adds historical options bars and a higher request limit. Confirm the current package on plans and limits.

For the full operator contract, see Options Screener API — Filter Every U.S. Contract. For agent access, use the Stock Market Data MCP Server for Options & Fundamentals. For a no-code build, start at the custom options screener.

The returned data is for research and education, not investment advice or order execution.