Scanning/How Scanning Works

    Scanning

    How Scanning Works

    A scan asks one question of the whole market: which stocks match these conditions right now? The conditions are a scan payload. You get a payload, send it to POST /api/v2/scan, and get back every matching ticker in a single response. There is no pagination and no per-result cost: one scan is one request, whether it matches 3 stocks or 3,000.

    Scanning is the core of the scanr.ai API. Everything else (relative strength, patterns, themes, indicators) either feeds a scan as a filter or enriches its results.

    Get a payload

    Start from a payload someone, or something, already wrote. In order of how often you'll want them:

    1. From a sentence. POST /api/v2/scan/natural (the natural_scan tool over MCP) turns "large caps above the 200-day with RSI under 40" into a payload, with an explanation of each filter. Change it with follow-up sentences through POST /api/v2/scan/refine. See Natural-Language Scans.
    2. From the scanr.ai scanner. Build or open a scan in the scanner, click Filters → Export filters (Ctrl+Shift+E), and copy or download the JSON. For a scan you've saved, POST /api/v2/scan/myscans returns the same payload to code. See Saved Scans.
    3. By hand, from Building Scan Payloads and the catalog. Best for small edits to a payload you already have, or when a screen must never drift.

    All three produce the same JSON, and you can move between them: generate a payload from a sentence, tweak it by hand, save it, open it in the scanner, export it again. Store the payloads you use. Running a stored payload costs one request and no AI credits; generating it again costs credits and can come back slightly different.

    Generated and exported payloads are the bare payload, the object with Universe and All. To run one, send it as instructions:

    text
    POST /api/v2/scan    {"instructions": <payload>}

    The request

    The body has one required key, instructions, which holds the scan payload. Written out, a payload looks like this:

    json
    {  "instructions": {    "Universe": {      "Exchange": ["nasdaq", "nyse", "amex", "arca", "bats", "bx"],      "Type": ["cs", "os", "adrc"]    },    "All": [      {        "Stock": {          "MarketCap": [            { "State": { "Value": { "Lower": { "Operator": "gte", "Value": 2000000000 } } } }          ]        },        "Indicator": {          "RelativeStrengthMkt": [            { "Returns": { "Want": { "Value": { "GreaterThanOrEqual": 80 } } } }          ]        }      }    ],    "Sort": { "field": "market_cap", "direction": "desc" }  }}

    That payload reads: of the common stocks and ADRs listed on the major U.S. exchanges, return every company worth at least $2B whose relative strength against the market is in the top 20%, largest first.

    A payload has four parts:

    KeyWhat it does
    UniverseWhich securities are eligible at all: exchanges, security types, countries, themes.
    All, Any, ExcludeGroups of filters, and how their matches combine.
    SortThe order of the returned tickers.
    instructions siblingssave_args attaches the run to one of your saved scans.

    Universe

    The universe narrows the market before any filter runs. Within one key, values are alternatives (nasdaq or nyse); across keys, they all apply (an exchange and a type).

    KeyValues
    Exchangenasdaq, nyse, amex, arca, bats, bx, otc
    TypeSecurity types: cs common stock, os ordinary shares, adrc ADR (common), etf, etn, etv, fund, pfd preferred, warrant, right, unit, and more. See the UniverseFilter schema in the API Reference.
    CountryCountry of domicile, as lower-case ISO codes (us, ca, il), plus unknown. List them with GET /api/v2/scan/universe-countries.
    ThemeMarket themes by key, for example silver-miners. List them with GET /api/v2/scan/universe-themes. See Track Theme Rotation.
    ThemeMaxTierHow deep into each theme to go: 1 core members only, 2 core and satellite members (the default), 3 every member.

    Always set Exchange and Type

    An empty Exchange admits OTC listings, and an empty Type falls back to a default that includes ETFs. Unless you want those, send the explicit list shown above. Every scanr.ai preset does.

    Sector, industry and market cap are not universe keys; they are Stock filters (see Building Scan Payloads).

    Filters and groups

    Filters live inside groups, and each group sits in one of three arrays:

    • All: a stock matches the group when it passes every filter in it.
    • Any: a stock matches the group when it passes at least one filter in it.
    • Exclude: stocks that match the group are removed from the result.

    The final result is:

    text
    (matches of the All groups) ∪ (matches of the Any groups) − (matches of the Exclude groups)

    Note the union: an All group and an Any group at the same level widen the result rather than narrow it. Most scans need a single All group, optionally with an Exclude group.

    Inside a group, filters are organized by category. Each category key holds a map of filter name → list of filter rows:

    CategoryScreens onExample filters
    StockQuote and profile dataMarketCap, PrevDayClose, PrevDayVolume, ChangePercent, Sector, Industry, Week52High, Earnings
    Technical100+ price and volume studies on any timeframeSMA, EMA, RSI, MACD, ATR, BBANDS, ADX, RELVOL_STDDEV
    Indicatorscanr.ai's pre-computed scoresRelativeStrengthMkt, RelativeStrengthSector, RelativeStrengthIndustry, GroupStrength, TrendEfficiency, RegimeExtension
    Fundamental300+ metrics from quarterly and annual filingsEpsgrowth, Revenuegrowth, Dilutedeps, Netincome
    CandlestickPattern60+ candlestick patternsCDLENGULFING, CDLHAMMER, CDLMORNINGSTAR
    ChartPattern17 chart patternsCupAndHandle, BullFlag, AscendingTriangle, DoubleBottom
    ZoneSupply and demand zonesInside a demand or supply zone
    InsiderTransactions, ShortInsider activity and short data

    The full, current list of every filter, with its parameters, defaults and allowed values, is served by GET /api/v2/scan/instructions (below). Building Scan Payloads shows the shape of each category with worked examples.

    Timeframes

    Technical studies, candlestick patterns and chart patterns run on a timeframe, which is required on each of those filters:

    KindValues
    Intraday1m 2m 3m 4m 5m 10m 15m 20m 30m 1hr 2hr 4hr
    Daily and longer1d 2d 3d 4d 1wk 1mo

    The values are exact: 1w or 1h is a 400. Filters in one scan can use different timeframes, so "daily trend up, 15-minute RSI oversold" is a single payload.

    The response

    json
    {  "tickers": ["NVDA", "AVGO", "ANET", "APP"],  "count": 4,  "cached": false,  "end_time": "2026-09-29T20:05:12.418Z",  "scan_id": 918273,  "universe_size": 5874}
    FieldMeaning
    tickersEvery matching ticker, in Sort order. null when nothing matched.
    countHow many tickers matched.
    cachedtrue when an identical payload ran recently and its result was reused (see Caching).
    scan_idThe run's scan record. For a run attached to a saved scan, that scan's id.
    universe_sizeHow many securities were evaluated after the universe was applied.

    Caching

    An identical payload run again within two minutes is answered from cache, with "cached": true. To choose that window, send cache_ttl_seconds in the request body next to instructions: 0 always recomputes, and the most is 900 (15 minutes). During regular market hours a scan on live data is never reused for more than 5 minutes, whatever you ask for. A cached answer still counts as a request.

    A scan returns tickers, not rows of data. To show why each stock matched, or to rank the matches, enrich them with the data endpoints, for example POST /api/v2/stocks/get-stock-indicators for relative-strength scores. Run an End-of-Day Screen does exactly that.

    When data updates

    A scan reads the latest data at the moment it runs:

    • Price and volume studies include the current session's in-progress bar during market hours. A daily RSI at 11:00 is computed from today's partial candle; the same scan after the close sees the settled day.
    • Relative strength and regime scores are recomputed about once a minute during the session and settle after the close.
    • Fundamentals reflect the most recent filing.

    Run the same scan at 16:30 ET and at 11:00 ET the next morning and you may get different results; both are correct for their moment. For a stable daily list, run after the close. See Coverage & Freshness for each dataset's schedule.

    Discovering filters

    Three read-only endpoints describe what a payload can contain. The catalog and the country list answer without a token, so you can explore before you subscribe; the theme list needs one.

    EndpointReturns
    GET /api/v2/scan/instructionsThe full filter catalog: every category, filter, parameter (with default, min and max), input series, output plot name, timeframe and operator.
    GET /api/v2/scan/universe-themesEvery scannable theme, with its key, label and member counts.
    GET /api/v2/scan/universe-countriesEvery selectable country code.

    The catalog is large (hundreds of KB). Fetch it once and cache it; it changes when new filters ship, not between requests.

    bash
    curl -s https://scanr.ai/api/v2/scan/instructions \  | jq '.Technical.RSI[0] | {Params, Returns, Inputs}'

    Limits

    • Every API plan gets the full scanner: every timeframe, OTC and ETF universes, themes and every filter category. Plans differ in request volume, not in what a scan may contain. See Plans & Rate Limits.
    • A payload may hold up to 200 filter rows and 1 MiB of JSON.
    • Every scan counts as one request against your rate limits and is recorded in your scan history for 30 days.