---
title: "Screen with a free-form query"
method: POST
path: "/screen/query"
tags: ["Screening"]
---

# Screen with a free-form query

`POST /screen/query`

## Request

- Base URL: `https://mcp.dalalos.in/v1`
- URL: `https://mcp.dalalos.in/v1/screen/query`
- Auth: HTTP bearer

Screen the universe with a Screener.in-style expression instead of a fixed filter key set: `Return on capital employed > 22% AND Market Capitalization > 500`. Metric names come from `GET /v1/ratios`; `dialect` selects whether they are Screener.in phrases and surface units (`screener`, the default) or canonical DalalOS metric ids and storage units (`dalalos`). Results are paginated against ONE published metrics generation: pass the `snapshot_id` a page returned back on the next page, and a refresh in between answers 409 `snapshot_expired` rather than silently mixing two generations. Missing values follow SQL three-valued logic -- a bare comparison against an unknown value does not match, `COALESCE(...)` and `OR` behave as they do in SQL. A query that cannot be parsed or resolved returns 400 `bad_request` naming the metric or position at fault.

## Request body

- object
  - `columns` string[]: Extra values to return per row: a metric name, a custom ratio's name, or a bracketed `[expression]`. At most 20. Each is described in `data.columns` with a stable id, and each row carries its value under `columns` keyed by that id.
  - `definitions` object[]: Inline custom ratios usable anywhere a metric name is, in the query, in `columns`, and in each other. Each is `{name, expression, dialect}`. At most 20; a name may not shadow a canonical metric id or a Screener ratio name, and the references between them may not form a cycle.
  - `dialect` string: `screener` (Screener.in names and surface units) or `dalalos` (canonical metric ids and storage units).
  - `limit` integer: Rows per page (1..100).
  - `offset` integer: Rows to skip (0..5000).
  - `only_latest_results` boolean: Keep only companies that have filed the current results season -- the most recent quarter-end at least 50 companies have reported. `data.latest_results` names that quarter. See GET /screen/latest-results.
  - `order` string: asc or desc.
  - `query` string, required: The screen expression, e.g. `Return on capital employed > 22%`.
  - `scope` object: Exact-match classification filters AND-ed with the query, because the grammar has no string literal: an object with any of `sector`, `industry`, `igroup`, `isubgroup`, `company_type` (equality on the securities master) and `index` (membership of the named index). Echoed back as `data.scope`.
  - `snapshot_id` integer, nullable: Metrics generation to pin this page to, from a previous page's `pagination.snapshot_id`. Omit on the first page.
  - `sort_by` string: Sortable metric id to order by.

## Response `200`

Success (or success-with-empty when nothing is cached).

- Envelope: Standard DalalOS response envelope (src/models.py). `source` is a per-tool provenance tag; `stale`/`data_age_seconds` describe cache freshness.
  - `cached_at` string, nullable: ISO timestamp the served data was refreshed.
  - `data` unknown
  - `data_age_seconds` number: Present only when cached_at is set.
  - `error` string, nullable
  - `reason_code` string, nullable: Stable machine-readable category (no_data, not_found, bad_request, ...).
  - `resolved_via` string: Present only when a query resolved via a rename/merger alias.
  - `source` string, nullable
  - `stale` boolean, required
  - `status` 'success' | 'error', required

## Other responses

- `400`: Malformed request (reason_code=bad_request).
- `401`: Missing/invalid API key (reason_code=unauthorized).
- `402`: Monthly quota exhausted (reason_code=quota_exceeded).
- `403`: Account or plan is not permitted to use this route.
- `404`: Identifier resolves to nothing (reason_code=not_found).
- `409`: The pinned metrics generation was replaced by a refresh (reason_code=snapshot_expired); restart from page 1.
- `429`: Rate or concurrency limit exceeded.
- `503`: No metrics generation is published yet (reason_code=snapshot_unavailable).

---

[API](https://skmtc.dev/dalalos/apis/dalalos-indian-stock-rest-api.md) · [All operations](https://skmtc.dev/dalalos/apis/dalalos-indian-stock-rest-api/llms.txt) · [OpenAPI document](https://skmtc.dev/dalalos/apis/dalalos-indian-stock-rest-api/revisions/b13d59d2b300?raw)
