/screener/metrics
Return filings that match a DSL filter tree, grouped by company (default) or flattened.
Query the universe of US-listed filers by composing metric conditions ("ROE > 20% for the last 5 years AND PE < 20"). Supports OR/NOT, time-window modifiers (for_latest / for_consecutive / for_at_least), 1–120 period lookback, USD-normalized values for ADR foreign filers, and paging up to 500 cumulative results.
Plan-tier gate: POST /screener/metrics, POST /screener/ownership, POST /screener/initial-holdings, POST /screener/institutional-holdings and POST /screener/events require the Pro plan or higher; Free / Starter callers receive 403 PLAN_TIER_INSUFFICIENT (see API key, account, and plan errors). GET /screener/metrics/filters requires the Starter plan or higher.
Pricing note: Filters that touch price-sensitive metrics (market_cap, enterprise_value, all 13 valuation ratios) use the price observed on each filer's filing date; these dates differ across filers.
Request body (unknown fields return 422):
as_of_dateISO dateMust be ≤ today. Filings with filing_date > as_of_date are excluded.
lookbackint 1–120Most recent N filings per company within scope.
include_quarterlyboolfalse → annual only (10-K / 20-F / 40-F). true adds 10-Q.
tickersstring[]Whitelist, max 100. Case-insensitive (normalized to upper). Empty or omitted = full universe.
exclude_tickersstring[]Blacklist, max 100.
usd_onlyboolWhen true, exclude foreign-currency reporters.
sectorsstring[]Restrict the universe to these canonical sector buckets (the 12 in Industry classification (Pro+)). Omitted = no sector restriction.
where.filterDSL treeSee Filter DSL (/screener/metrics). Leaf count 1–10, nesting depth ≤ 4.
where.sort_bystringMetric name, "ticker", "period_end", "filing_date", or "match_count".
where.sort_order"asc" | "desc"include_metrics_using_filing_date_priceboolfalse rejects price-sensitive metrics in filter / sort_by / include_metrics.
exclude_derivationsstring[]Subset of derived, as_reported, composite, class_sum, segment_sum, company_override, proxy_substituted, TTM_rollforward.
include_metricsstring[]Extra metric names (≤ 10) to include in the response beyond filter-referenced ones.
group_by_tickerbooltrue → grouped by company with nested filings[]. false → flat per-filing rows.
pageint ≥ 11-indexed.
page_sizeint 1–100Counts companies (when grouped) or filings (when flat).
detailstring"light" leaves out each company's classification.source.url and the lookback_applied and include_quarterly_applied echoes. See Response detail.
Pagination cap: page × page_size ≤ 500 (422 above it). When the next page would pass the cap, has_more is false, next_page is null, and _warnings says the limit was reached.
Response (group_by_ticker=true, default):
{
"page": 1, "page_size": 50,
"has_more": true,
"next_page": 2,
"as_of_date_applied": "2024-12-31",
"lookback_applied": 5,
"include_quarterly_applied": false,
"results": [
{
"ticker": "AAPL",
"match_count": 5,
"filings": [
{
"metric_id": 46,
"form_type": "10-K",
"fiscal_year": 2024, "quarter": "FY",
"period_end": "2024-09-28",
"filing_date": "2024-11-01",
"reporting_currency": "usd",
"metrics": {
"return_on_equity": {"value": 1.5774, "derivation": "derived", "unit": "ratio"},
"pe_ratio": {"value": 33.21, "derivation": "derived", "unit": "ratio", "price_date": "2024-11-01"},
"market_cap": {"value": 3.37e12, "derivation": "as_reported", "unit": "usd", "price_date": "2024-11-01"}
}
}
/* T-1, T-2, … up to lookback filings within company */
]
}
],
"credits_used": 242
}Response (group_by_ticker=false): identical envelope, but results[] is a flat list of {ticker, metric_id, form_type, fiscal_year, quarter, period_end, filing_date, reporting_currency, metrics} — one row per matching filing.
For Pro+ callers each results[] entry (grouped or flat) also carries an industry classification block when the company has one — see Industry classification (Pro+).
match_count is the number of filings within lookback that satisfy the whole filter tree on a per-filing basis (using each filing's own metric values).
Foreign-currency filers (ADRs) carry fx_rate_used + currency on FX-converted metric entries:
"market_cap": {
"value": 2.42e11, // USD-converted from JPY
"derivation": "as_reported",
"unit": "usd",
"currency": "jpy",
"fx_rate_used": 145.2,
"price_date": "2024-06-30"
}All screener filtering, sorting, and comparison use the USD-converted value. USD reporters omit fx_rate_used and currency.
Within-company filings[] ordering is filing_date DESC, period_end DESC (newest first). For time-series ordering, use group_by_ticker=false with sort_by="period_end" or "filing_date".
Errors: 422 VALIDATION_ERROR (schema; a metric name outside the catalog also returns _supported_metric_names), 402 CREDITS_INSUFFICIENT, 403 PLAN_TIER_INSUFFICIENT below Pro, 504 QUERY_TIMEOUT when the query exceeds the 30-second server timeout (charged).
#Filter DSL (/screener/metrics)
#Leaf node
{"metric": "<name>", "op": "<operator>", "value": <number | [lo, hi]>,
"for_latest": <N> | "for_consecutive": <N> | "for_at_least": <N>}| Operator | Value shape | Notes |
|---|---|---|
>, >=, <, <= | single number | |
between | [lo, hi] (lo ≤ hi) | Inclusive on both ends. |
= and != are not supported.
value must be numeric. null is rejected. Filings where the metric value is missing are excluded from filter comparisons (no synthetic match).
#Temporal modifiers (mutually exclusive, at most one per leaf)
| Modifier | Meaning |
|---|---|
| (none) | Latest filing in lookback must satisfy. Equivalent to for_latest: 1. |
for_latest: N | Most recent N filings (right-anchored) all satisfy. |
for_consecutive: N | Some N adjacent filings within lookback all satisfy (sliding window over filing_date). |
for_at_least: N | At least N filings within lookback satisfy (any positions). |
N ≥ 1 and N ≤ lookback. Tickers without enough filings in lookback to evaluate the modifier are filtered out.
#Composite nodes
{"and": [<node>, <node>, …]}
{"or": [<node>, <node>, …]}
{"not": <node>}where.filter may itself be a bare leaf (no wrapper required for single-condition queries).
#Limits
- Leaf nodes total: 1–10 (0 → rejected as "filter required"; >10 → rejected as "too complex")
- Nesting depth: ≤ 4
include_metricslength: ≤ 10tickers,exclude_tickers: each ≤ 100 entries
#Credit formula (/screener/metrics)
POST /screener/metrics charges per call (paginate ⇒ each page bills independently):
credits = max(65, 425
− tickerDiscount // ceil(200 × (100 − n_tickers) / 100); 0 (whole universe, or ≥ 100 tickers) … 198 (1 ticker)
− lookbackDiscount // 0 (lookback ≥ 30) … 78 (lookback = 1)
− quarterlyDiscount // 60 when include_quarterly=false, else 0
+ lookbackSurcharge // 0 (lookback ≤ 30) … 240 (lookback = 120)
+ filterSurcharge // 40 × (leaves − 1), 0 … 360
+ temporalSurcharge // per-leaf 60 (for_latest / for_at_least) or 100 (for_consecutive), capped 600
+ includeMetricsSurcharge) // 20 × |include_metrics \ filter_metrics|, 0 … 200Examples:
| Scenario | Credits |
|---|---|
| 1 ticker, lookback=1, annual only, 1 leaf (best case) | 89 |
| Whole universe, lookback=30, quarterly+annual, 1 leaf | 425 |
2 tickers, lookback=5, annual, 2 leaves, 1 for_latest, 2 extra include_metrics | 242 |
Whole universe, lookback=120 (Business or Enterprise plan), 10 leaves all for_consecutive, 10 extra include_metrics | 1825 (worst case) |
lookback is priced after it is clamped to your plan's history window.
Charge applies even when results is empty, and on 504 QUERY_TIMEOUT. Errors returned before the charge (422, 402, 403, authentication errors, 429) are not charged.
GET /screener/metrics/filters is free.