Scanning/Natural-Language Scans

    Scanning

    Natural-Language Scans

    Writing a scan payload by hand means knowing the filter names, plot names and comparators. Two endpoints do that part for you:

    • POST /api/v2/scan/natural turns a sentence into a scan payload.
    • POST /api/v2/scan/refine changes an existing payload with a follow-up sentence, leaving the filters you didn't mention alone.

    Neither endpoint runs the scan. They return a payload, with an explanation of each filter, and you send it to POST /api/v2/scan when you're happy with it. That split is deliberate: you can check, store and re-run the payload without paying for the language model again.

    This is the usual first step of any scan: sentence → payload → scan. The other way to get a payload is to export one from the scanr.ai scanner (Filters → Export filters). An exported payload can be refined here exactly like a generated one. See Get a payload.

    Generate a payload

    bash
    curl https://scanr.ai/api/v2/scan/natural \  -H "Authorization: Bearer $SCANR_API_TOKEN" \  -H "Content-Type: application/json" \  -d '{"query": "profitable mid-cap stocks above their 200-day moving average with RSI under 40"}'

    The response looks like this (abridged; the wording of the reasoning varies from run to run):

    json
    {  "conversion_success": true,  "generated_payload": { "Universe": { "...": "..." }, "All": [ { "...": "..." } ] },  "reasoning": {    "summary": "Profitable mid-cap companies in a long-term uptrend that have pulled back to a low RSI.",    "filters": [      { "filter": "Market cap $2B–$10B", "reason": "\"Mid-cap\" is conventionally $2B to $10B." },      { "filter": "Net income above 0", "reason": "\"Profitable\" means positive earnings in the latest filing." },      { "filter": "Price above SMA(200)", "reason": "Stated directly: above the 200-day moving average." },      { "filter": "RSI(14) below 40", "reason": "Stated directly: RSI under 40, on the default 14-day period." }    ]  },  "retry_count": 0,  "conversion_time_taken_ms": 5210}
    FieldMeaning
    conversion_successWhether a valid payload was produced. When false, read validation_errors.
    generated_payloadThe scan payload. Send it as instructions to /api/v2/scan.
    reasoning.summaryOne sentence describing the screen as built. Show it to your user before running.
    reasoning.filtersOne entry per filter, in payload order: how a person would name it, and why it follows from your query.
    retrieved_examplesSimilar known scans the model drew on.
    validation_errorsWhy a payload was rejected, when it was.

    Refine it

    Refinement edits a payload in place. Send the payload and the change you want:

    json
    {  "existing_payload": {    "Universe": {      "Exchange": ["nasdaq", "nyse", "amex", "arca", "bats", "bx"],      "Type": ["cs", "os", "adrc"]    },    "All": [      {        "Technical": {          "RSI": [            {              "Timeframe": "1d",              "Inputs": ["bar_close"],              "Params": { "Period": { "Value": 14 } },              "Returns": { "Want": { "RSI": { "Value": { "LessThan": 40 } } } }            }          ]        }      }    ]  },  "refinement_query": "only stocks with relative strength above 70, and drop anything under $10"}

    The response has the same shape as /scan/natural, with refinement_success and refined_payload in place of conversion_success and generated_payload. The RSI filter above survives; an RS filter and a price floor are added.

    Refinement is the right tool for conversations: "now only large caps", "make it weekly", "exclude biotech". It keeps the parts of the screen the user already agreed to.

    Run it

    Send the payload to the scan endpoint as instructions:

    bash
    # natural.json is the saved /scan/natural responsejq '{instructions: .generated_payload}' natural.json \  | curl https://scanr.ai/api/v2/scan \      -H "Authorization: Bearer $SCANR_API_TOKEN" \      -H "Content-Type: application/json" \      -d @-

    Store the payload if you'll run the screen again. Re-running a stored payload costs one request and no AI credits; regenerating it from the sentence costs credits and may produce a slightly different payload.

    Writing good queries

    The model maps words to filters, so concrete words produce precise payloads:

    Instead ofSay
    "strong stocks""relative strength above 80"
    "cheap""P/E under 15" or "price under $20"
    "big volume today""relative volume above 3 standard deviations"
    "breaking out""within 5% of the 52-week high" or "crossed above the 50-day moving average in the last 3 days"
    "recently""in the last 5 trading days"

    Name the timeframe when it matters ("weekly RSI", "15-minute chart"); daily is the default. Put hard requirements in the first request and use refinement for adjustments. The query can be up to 20,000 characters.

    Cost

    Both endpoints draw on your daily AI credit budget (see Plans & Rate Limits); running the resulting payload doesn't. Generation usually takes a few seconds, so use a timeout of a minute or more.

    Next