Valuation
GET/api/v1/families/valuation/symbols
A daily cheap-to-expensive rating and the latest P/E for listed US stocks, sectors, industries, and indices. Pro and Unlimited.
Description
Returns the day’s valuation for each requested key: a rating from Bargain to Extremely expensive, measured against that key’s own P/E range, plus the latest P/E. A rating is published only when every data-quality check passes (complete and fresh trailing earnings, a clean price history, a P/E consistent with market cap over net income, enough history for the bands, common stock only; sectors, industries, and indices also need at least 60% of member market cap reporting). Otherwise valuation_label is null, verdict_status is withheld, and dq.reasons lists the failing checks. Keys are listed tickers (IBM, BRK.B), SECTOR:name, INDUSTRY:name, or INDEX:SPY, INDEX:QQQ, and INDEX:DIA for the S&P 500, Nasdaq-100, and Dow Jones. Sector and industry names follow the current classification (for example SECTOR:consumer-discretionary, SECTOR:consumer-staples, SECTOR:communication, SECTOR:finance, INDUSTRY:software-infrastructure). Earlier sector keys still work: SECTOR:consumer-cyclical, SECTOR:consumer-defensive, SECTOR:communication-services, SECTOR:financial-services, and SECTOR:telecommunications return the current sector. Earlier industry keys work where one successor holds most of the old group. The response lists each one under aliases. With asof, a sector is answered under the name that day used. Retired keys return 404 with a hint. Full table: GET /api/v1/families/us-equities/fundamentals/groups/aliases. An industry with fewer than 5 common stocks is not a peer group: its stocks are listed under the industry Others (INDUSTRY:others), keep their own ratings, and still count in their sector. INDUSTRY:others has no P/E, rating, chart, or statements of its own; it is served with available false and reason others-not-a-group, and the industry keys it replaced resolve to it (named in aliases). Tickers are normalized (BRK.B becomes BRK-B) and the response is keyed by the normalized form. Unknown keys come back null. POST the same path with {"symbols": [...]} for up to 5,000 keys. One key: GET /api/v1/families/valuation/symbols/{key}. The whole day in one call: GET /api/v1/families/valuation/catalog, with optional kind=ticker,sector,industry,index. Values refresh once a day.
Authentication
v1 is client_id plus client_secret on every protected GET. A browser session is not enough. Google sign-in is for the website only — do not send a session cookie to v1.
- HTTP Basic —
Authorization: Basic base64(client_id:client_secret) - Headers —
X-Client-IdandX-Client-Secret
Create or rotate credentials on Account. Full notes are on Authentication.
Path parameters
This path has no parameters.
Query parameters
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
symbols | query | string | Yes | Comma-separated keys (max 500 on GET). Keys are listed tickers (IBM, BRK.B), SECTOR:name, INDUSTRY:name, or INDEX:SPY, INDEX:QQQ, and INDEX:DIA for the S&P 500, Nasdaq-100, and Dow Jones. Sector and industry names follow the current classification (for example SECTOR:consumer-discretionary, SECTOR:consumer-staples, SECTOR:communication, SECTOR:finance, INDUSTRY:software-infrastructure). Earlier sector keys still work: SECTOR:consumer-cyclical, SECTOR:consumer-defensive, SECTOR:communication-services, SECTOR:financial-services, and SECTOR:telecommunications return the current sector. Earlier industry keys work where one successor holds most of the old group. The response lists each one under aliases. With asof, a sector is answered under the name that day used. Retired keys return 404 with a hint. Full table: GET /api/v1/families/us-equities/fundamentals/groups/aliases. An industry with fewer than 5 common stocks is not a peer group: its stocks are listed under the industry Others (INDUSTRY:others), keep their own ratings, and still count in their sector. INDUSTRY:others has no P/E, rating, chart, or statements of its own; it is served with available false and reason others-not-a-group, and the industry keys it replaced resolve to it (named in aliases). Example: IBM,SECTOR:technology. |
asof | query | string | No | Past session, YYYY-MM-DD. Omit for the latest day. |
Example request
curl -sS -u "$CLIENT_ID:$CLIENT_SECRET" \
https://barquant.dev/api/v1/families/valuation/symbols?symbols=IBM,SECTOR:technologyResponse attributes
| Field | Type | Description |
|---|---|---|
family | string | Always valuation. |
as_of | string | null | Session the values describe, YYYY-MM-DD. |
computed_at | string | null | When that day’s values were produced. |
universe_fold | object | null | Catalog only: the small industries that day's run folded into INDUSTRY:others (threshold, and folded_industries: old key to name, sectors, and members). The universe routes use exactly this list. Null before 2026-10. |
requested | string[] | Normalized keys, in request order. |
aliases | object | Older sector or industry keys you asked for, mapped to the key served in symbols. Empty when none applied. Full table: GET /api/v1/families/us-equities/fundamentals/groups/aliases. |
symbols | object | One entry per requested key, or null when the key is unknown. |
symbols[key].kind | "ticker" | "sector" | "industry" | "index" | What the key names. |
symbols[key].name | string | null | Company, sector, industry, or index name. |
symbols[key].valuation_label | string | null | Bargain, Very cheap, Relatively cheap, Relatively expensive, Very expensive, or Extremely expensive. Published only when every data-quality check passes; otherwise null (show a dash). Null when available is false. |
symbols[key].latest_pe | number | null | Latest P/E. Null when available is false. |
symbols[key].available | boolean | false when there is not enough trustworthy price or earnings data to compute a P/E. |
symbols[key].reason | string | null | Why available is false: no-price-history, no-eps-history, no-ttm, loss-making, stale-eps, ticker-reuse, non-common-equity, pe-out-of-bounds, cap-pe-mismatch, fx-unavailable, insufficient-coverage, no-members-with-data, insufficient-reporters, insufficient-pe-history, earnings-yield-cap (sectors, industries, indices: every reporting member's earnings are at the 25% earnings-yield cap, so the P/E would be the cap, 4.0, not a measurement), earnings-near-zero (sectors, industries, indices: the members' combined earnings are positive but too small for a meaningful P/E; loss-making when they are a loss), stale-label (sectors, industries, indices: the last P/E is older than two completed quarters), others-not-a-group (INDUSTRY:others, industries with fewer than 5 common stocks: not a peer group). |
symbols[key].verdict_status | "ok" | "withheld" | ok when valuation_label passed every data-quality check. withheld when the rating is not published; dq.reasons says why. |
symbols[key].dq | object | Data-quality result: status (ok or withheld), reasons (every failing check, for example short-history, stale-eps, cap-pe-mismatch, degenerate-bands, stale-price, price-split-step, price-step-after-eps (the price moved more than 2.5x in one session, not a split, after the last reported quarter, as in a spin-off: the P/E stays, the rating returns with the next quarter), price-implausible, insufficient-coverage, index-level-jump, index-collapse, unconfirmed-dominance, single-reporter (a sector, industry, or index whose rating would rest on one company: the P/E stays, the rating does not; checked on the quarter the rating is read from, and chart points resting on one company carry no rating either), reporters-unknown (the number of reporting members behind the rating is not known: the P/E stays, the rating does not), held-label-fails-gate (sectors, industries, and indices: today's recomputed chart would have lost published history, so the key keeps its previous chart, P/E, and as_of, and the rating of that previous object fails today's checks; listed first, followed by the failing checks: the P/E and the chart stay, the rating and bands do not), duplicate-quarter and placeholder-quarter (stocks: one of the last four quarters is a vendor copy of another quarter, or a placeholder, and was left out; listed first, and given as reason when the estimate is what makes the P/E a loss or out of range), share-basis-break and guarded-eps (stocks: the trailing EPS behind the P/E is an estimate, because the share count jumped more than 2x inside the four quarters with no stock split on record, or one quarter's EPS was unusable and the other three were scaled up; the P/E stays, the rating does not), outlier-driver), coverage (sectors, industries, and indices: reporting share of member market cap), and quarantined_members (members kept out of the aggregate). |
symbols[key].label_pe | number | null | The P/E the rating was read from, set exactly when valuation_label is. Equal to latest_pe; label_as_of says which day it describes. Archived sessions from before 2026-10 carry a rating with label_pe and label_as_of null (the field did not exist yet). |
symbols[key].label_as_of | string | null | Day label_pe describes: the last price session when today's P/E exists, otherwise the last quarter that had one (a sector or industry whose latest earnings are a loss). Null without a rating. |
symbols[key].tip_reason | string | null | Sectors, industries, and indices: why today's P/E is missing, from the members' combined trailing earnings: aggregate-loss (a loss), earnings-near-zero (too small for a meaningful P/E), or tip-unpublished (not enough members reporting). No P/E or rating is served then; older P/Es stay in the chart. Null when today's P/E exists. |
pending | string[] | Keys whose day is not published yet. Retry later. |
Sample response
{
"family": "valuation",
"as_of": "2026-09-11",
"computed_at": "2026-09-12T03:04:11Z",
"requested": [
"IBM",
"SECTOR:technology"
],
"aliases": {},
"symbols": {
"IBM": {
"kind": "ticker",
"name": "International Business Machines",
"valuation_label": "Relatively expensive",
"latest_pe": 24.6,
"available": true,
"reason": null,
"as_of": "2026-09-11",
"computed_at": "2026-09-12T03:04:11Z",
"verdict_status": "ok",
"dq": {
"status": "ok",
"reasons": [],
"coverage": null,
"quarantined_members": []
}
},
"SECTOR:technology": {
"kind": "sector",
"name": "Technology",
"valuation_label": null,
"latest_pe": 33.6,
"available": true,
"reason": null,
"as_of": "2026-09-11",
"computed_at": "2026-09-12T03:04:11Z",
"verdict_status": "withheld",
"dq": {
"status": "withheld",
"reasons": [
"short-history"
],
"coverage": 0.97,
"quarantined_members": []
}
}
},
"pending": []
}Errors
| Status | When |
|---|---|
| 400 | symbols is missing or over the key limit, or asof is not YYYY-MM-DD. |
| 401 | Missing or wrong client_id / client_secret. |
| 403 | Authenticated, but this plan does not include valuation. It starts on Pro. |
| 404 | The single-key path names a key that is not in that day’s valuation, or the catalog path names an asof day that was never published. A retired sector or industry key also carries a hint. |
| 429 | Daily quota or per-minute plan quota. Read Retry-After and X-RateLimit-* headers. |
401 body:
{
"error": "Unauthorized"
}403 body:
{
"error": "This plan does not include that family.",
"plan": "basic",
"requiredPlan": "pro"
}429 body (per-minute / daily):
{
"error": "Too many requests."
}Plan access
Pro and Unlimited. Free and Basic receive 403. Every request counts as one API request against the plan quota, however many keys it names.
Daily and per-minute quotas live on Plans and limits.
© 2026–2035 Barquant