Skip to main content

2026-06-17: annual-only foreign private issuers never serve a bare-empty quarter view

Correctness release across /v2/fundamentals and /v2/snapshot; two response shapes gain a value-or-envelope variant and a new field:
  • New top-level reporting_cadence on /v2/fundamentals ('quarterly' | 'annual'). It labels the issuer’s statement filing cadence. The universe default is 'quarterly' — domestic issuers and foreign filers that report quarterly (e.g. SHOP, SHEL) are unchanged. An annual-only foreign private issuer (20-F / IFRS filer with no quarterly statements — e.g. TSM, SAP) reports 'annual'. Branch on this before assuming quarterly rows exist.
  • The DEFAULT view (no ?period=) now resolves to the rich annual statements for an annual-only filer. Previously these filers returned a bare-empty quarterly view. The default now serves the native-currency ANNUAL income statement, balance sheet, and cash flow, the ttm block is computed off the latest fiscal year (reason ttm_basis_latest_fiscal_year_annual_filer, never the misleading insufficient_quarterly_history), and forensics returns {available: false, reason: "annual_only_filer_no_quarterly_forensics"}. Request ?period=annual for the same statements explicitly.
  • An explicit ?period=quarter for an annual-only filer returns a quarterly_view notice instead of empty rows. The response carries quarterly_view: {available: false, reason: "annual_only_filer_use_period_annual"}, the quarterly statement blocks are OMITTED (not bare-empty), and the ttm block is still served (latest fiscal year). quarterly_view is absent for every quarterly filer.
  • /v2/snapshot fundamentals_quick gains an optional reporting_cadence: 'annual' present ONLY for an annual-only filer, whose ttm_* figures there are taken from the latest fiscal year. Absent for the quarterly universe. These filers are no longer marked degraded for lacking quarterly history.
  • Cross-currency refusals are unchanged. For a non-USD foreign private issuer the ttm_*_usd magnitudes still refuse value_in_native_currency_see_fundamentals; the annual cadence change serves correctly-labeled native statements, never native magnitudes under a USD label.
  • schema_version bumped to 2026-06-17.6 to mark the new reporting_cadence field and quarterly_view value-or-envelope variant. Starter and Builder plans.

2026-06-17: leaner per-row provenance (derivable filing URL dropped)

Payload-size release (/v2/fundamentals):
  • Per-row provenance no longer ships filing_url. Each income-statement, balance-sheet, and cash-flow row’s provenance block now carries {accession, filed, form} only. The archive index URL is fully derivable from the accession — its leading 10-digit block IS the filer CIK — as https://www.sec.gov/Archives/edgar/data/{cik}/{accession-without-dashes}/{accession}-index.htm (taught in the accession field description). This matches the /v2/facts?provenance=full per-cell shape (which already omitted the URL) and removes a ~80-character derivable string that was triplicated across the three statement rows of every period. Provenance integrity is unchanged: every row is still independently citable by accession, and the vendor / unresolved value-or-envelope refusals are unchanged.
  • schema_version bumped to 2026-06-17.5 to mark the field removal. Starter and Builder plans.

2026-06-17: foreign-flip cross-surface currency, sign, and cash-flow safety

Correctness release across the price-derived surfaces, ahead of foreign issuers flipping to the SEC-native (native-currency) store:
  • Cross-currency multiples and enterprise value refuse instead of mixing currencies. For a foreign private issuer reporting in a non-USD functional currency (e.g. EUR for SAP, TWD for TSM), a multiple whose denominator is a native-currency statement value — pe_ttm, ps_ttm, pb, ev_ebitda_ttm, ev_ebit_ttm, ev_sales_ttm — and enterprise_value_usd (a USD market cap minus native net debt) now return {available: false, reason: "cross_currency_multiple_unavailable"} on /v2/snapshot and /v2/valuation rather than dividing a USD-quote market cap by a native denominator. The reciprocal yields (earnings_yield_pct, fcf_yield_pct) refuse the same way. Market cap itself still servesprice (USD) × shares is genuinely USD — as do currency-invariant ratios (dividend/buyback/total-payout yields, returns on capital, growth %). The correctly-labeled native statements live on /v2/fundamentals and /v2/facts.
  • Native magnitudes are never served under a _usd label. The TTM _usd-suffixed figures on /v2/snapshot (ttm_revenue_usd, ttm_net_income_usd, ttm_eps_diluted) and /v2/brief (revenue_ttm_usd, net_income_ttm_usd, total_debt_usd, free_cash_flow_usd, …), and /v2/earnings eps_actual/revenue_actual, return {available: false, reason: "value_in_native_currency_see_fundamentals"} for a flipped foreign issuer. /v2/brief identity.currency reports the statements’ native currency.
  • /v2/earnings currency widens from Literal["USD"] to a free string — the issuer’s native functional currency for SEC-native foreign filers, still "USD" otherwise.
  • /v2/priced-in refuses the reverse-DCF for a cross-currency issuer with {available: false, reason: "reverse_dcf_cross_currency_unavailable"} (a USD market cap cannot anchor a native-currency cash-flow path), rather than implying a fair value off mixed currencies.
  • The shared TTM aggregator now applies the impossible-sign refusal. An impossible-negative revenue/COGS/opex in any contributing quarter refuses the TTM magnitude (and therefore ps_ttm, ev_sales_ttm, revenue_ttm_usd, and the brief) — previously the per-row guard caught the presentation layer but the canonical TTM sum bypassed it. Sign-meaningful fields (net income, FCF, equity) are unaffected.
  • Cash-flow articulation is now enforced surface-wide. A period whose operating + investing + financing + FX-on-cash fails to reconcile to the filed net change in cash refuses fcf_yield_pct ({available: false, reason: "cf_articulation_unverified"}) on /v2/snapshot and /v2/valuation, refuses the /v2/priced-in reverse-DCF, and nulls the operating/free cash-flow cells on the /v2/facts grid (registered in the block unavailable registry) — matching the guard already on /v2/fundamentals.
  • schema_version bumped to 2026-06-17.4 to mark these new value-or-envelope variants and the earnings currency widening. Starter and Builder plans.

2026-06-17: no-weirdness gaps — supported-symbol earnings + impossible-sign refusal

Data-quality release; two response shapes gain a value-or-envelope variant:
  • /v2/earnings never walls a supported symbol. A supported issuer whose SEC filings carry no discrete fiscal quarters (foreign private issuers filing annual 20-F / semiannual 6-K, and early SPACs — e.g. RIO, SHEL, KB) previously returned a retryable 503 UPSTREAM_UNAVAILABLE. It now returns 200 with last as a value-or-envelope ({available: false, reason: "no_quarterly_statements_filed"}) — the symbol is supported, there is simply no quarterly row to report. A true statements outage (no data at all) still returns 503. /v2/coverage no longer advertises earnings as quote-blocked: earnings reads only filed statements (never a live quote).
  • /v2/fundamentals refuses impossible-sign magnitudes. income_statement.revenue, cost_of_revenue, and operating_expense are magnitudes that cannot be negative. A served negative (an EDGAR de-cumulation FY−9M derivation artifact, or a vendor sign error) is now refused as {available: false, reason}decumulation_sign_implausible for a derived quarter, reported_value_implausible otherwise — instead of being served bare. Sign-meaningful fields (net_income, operating_income, free cash flow, equity) can legitimately be negative and are unchanged.
  • /v2/facts mirrors the sign-sanity refusal. An impossible-negative magnitude cell is nulled and explained in the grid’s unavailable registry with the same reason tokens.
  • schema_version bumped to 2026-06-17.3. Starter and Builder plans (/v2/coverage is free-tier).

2026-06-17: one-call analyst brief (the front door)

Additive release (one new route); no existing response shape changes:
  • New GET /v2/brief?symbol=. One compact response (~6-8KB) that composes the headline of every analyst surface, so an agent can start reasoning from a single call instead of fanning out across seven. Sections: identity (name, exchange, sector/SIC, CIK); price (quote, seven-window performance, 52-week range); ttm (revenue / net income / EPS, gross / operating / net margins, cash, total_debt, net_debt, total_equity, operating and free cash flow); valuation (market cap, EV, and P/E and EV/EBITDA each with their own-history band, z-score, and price-vs-fundamental driver); capital_allocation (dividend yield + payer flag, FCF yield, TTM buybacks and dividends paid); events (the latest three classified SEC events); insider_90d (Form 4 open-market net); segment (top business segment by revenue); and next_earnings (projected from filing cadence, never issuer-confirmed).
  • Pure composition — no new data, no extra freshness surface. The brief reads the same warm caches the dedicated endpoints read; the numbers match them exactly (same assemblers). It performs zero EDGAR or vendor-fundamentals fetches on the request path.
  • Every section is value-or-envelope and the route never fails for a supported symbol. An unavailable input returns {available: false, reason} (e.g. segments_store_not_built, not_applicable_for_etf, price_quote_unavailable) — never a bare null, and one missing section never turns into a route-level error. The response header carries statements_source (sec_edgar | vendor) and a coverage_hint (sec_native | vendor_fallback | statements_unavailable | etf_market_data_only) so a thin payload still says where its numbers came from. ETFs envelope the stock-only sections.
  • MCP: new tool stockcontext_brief — the recommended first call for any single symbol.
  • schema_version bumped to 2026-06-17.2 to mark the new route. Starter and Builder plans.

2026-06-17: reference catalogs for cold discovery

Additive release (three new free-tier routes); no existing response shape changes:
  • New GET /v2/reference/fact-concepts. Lists every concept name accepted by /v2/facts?concepts= — each entry carries the stable public name, its unit, a human label, and the aliases (the SEC XBRL tags and common GAAP-longhand spellings) that resolve to it. Fetch this once to discover the vocabulary instead of guessing a name and getting not_in_catalog.
  • New GET /v2/reference/event-labels. Lists the full classified-event label taxonomy /v2/events emits — each entry gives the machine label, its SEC classification source (8k_item, form, or xbrl), and the exact item codes / form types behind it (the valid labels= filter values).
  • New GET /v2/reference/segment-axes. Lists the segment dimensions /v2/segments populates (business, geography) with their SEC XBRL axes and the revenue/profit concepts read per member.
  • /v2/facts resolves common GAAP-longhand concept names. The obvious snake_case guess now resolves to the cataloged concept (research_and_development_expense -> rnd_expense, net_income_loss -> net_income, cost_of_goods_sold -> cost_of_revenue, and more) and serves real data, in addition to the existing exact-name, case-insensitive, and XBRL-tag resolution.
  • /v2/facts never returns a bare not_in_catalog. An unresolved concept that shares a word with a real concept now always carries did_you_mean suggestions (typos, partial names, and longhand guesses), so a miss points somewhere instead of dead-ending.
  • MCP: new resources stockcontext://reference/fact-concepts, stockcontext://reference/event-labels, and stockcontext://reference/segment-axes mirror the routes for in-tool discovery.
  • schema_version bumped to 2026-06-17.1 to mark the new routes. All three are free-tier accessible like /v2/coverage.

2026-06-16: foreign-issuer native currency and per-row SEC provenance

Additive SEC-data release (/v2/fundamentals):
  • Foreign private issuers now serve their native reporting currency. currency widens from a fixed "USD" to the filer’s own functional currency for SEC-native foreign private issuers reporting under IFRS (e.g. "EUR" for SAP, "TWD" for TSM), matching the currency already served on /v2/facts for the same symbol. Domestic issuers and the vendor fallback remain "USD". Every monetary field in the response is denominated in this currency.
  • Every statement row carries its SEC filing citation. Income-statement, balance-sheet, and cash-flow rows served from the EDGAR-native store gain a provenance block: the period’s primary filing as {accession, filing_url, filed, form} (a bare value, no available: true wrapper — value-or-envelope), where filing_url is a resolvable https://www.sec.gov/Archives/... index URL built from the filer CIK and accession (the same shape /v2/facts?provenance=full exposes per cell). Vendor-sourced rows carry {available: false, reason: "vendor_sourced_no_sec_provenance"} (the price vendor has no SEC filing to cite); the rare EDGAR row whose filing identity is unrecoverable carries {available: false, reason: "sec_filing_url_unresolved"}. Never a bare null.
  • Foreign issuers with coherent IFRS facts now serve sec_edgar. The SEC coherence flip referee no longer carves out foreign issuers wholesale: a foreign filer whose ifrs-full facts pass the full hard-gate identity battery (balance-sheet A = L + E, gross profit, EPS, facts-vs-fundamentals TTM) flips to SEC-native serving exactly like a domestic issuer, now that native currency and per-row provenance make the payload citable. Foreign issuers whose facts do not pass remain on the vendor fallback. (IFRS total_equity is pinned to the including-NCI total with parent-only book value served as total_equity_parent, and net income is served on the owners-of-parent basis so EPS reconciles — the same conventions domestic issuers already follow.)
  • schema_version bumped to 2026-06-16.2 to mark the payload-shape change.
  • Token budgets: fundamentals raised 7,195 -> 9,367 because the published example now carries a per-row provenance block on all three statement blocks (G-BUDGET +10% headroom rule).

2026-06-16: quote-miss safety and honest coverage

Reliability/contract correction:
  • /v2/snapshot now degrades when a stock’s live quote is unavailable. The route keeps serving the rest of the snapshot and returns quote: {available: false, reason: "price_quote_unavailable"} instead of turning a quote miss into a route-level 404/503.
  • /v2/valuation and /v2/priced-in no longer value from fallback closes after a live quote miss. Market cap and EV fields that require the quote basis return unavailable envelopes with share_price_basis_unverified; /v2/priced-in refuses the reverse-DCF as shape_kind: "not_applicable" with the same reason rather than silently computing from historical bars.
  • Vendor fundamentals/history walls now degrade instead of sinking M0 routes. Snapshot, valuation, priced-in, and fundamentals read the requested symbol’s own warm SEC stores when available; if neither vendor nor store data is available, they return degraded payloads with unavailable fields instead of a route-level provider error. No endpoint relabels a sibling share class’s vendor bars or statements.
  • /v2/coverage is more honest for known unquoted share classes. Routes that still require a live quote now report available_now: false with share_class_quote_unmapped; M0 routes that can degrade remain available.
  • /v2/fundamentals no longer serves a consolidated net income beside per-class EPS/shares. For multi-class issuers (GOOGL/BRK class), a quarter that carries the quoted class’s own per-class eps_diluted/shares_diluted but no reconciling per-class net-income allocation now withholds net_income as {available: false, reason: "class_basis_net_income_unavailable"} instead of leaving the consolidated total (which broke eps_diluted x shares_diluted = net_income by ~13% on GOOGL Q1-2026). This is the same guard /v2/facts already applied, now ported to the statements store; clean single-class symbols and reconciling annual periods are unchanged.
  • /v2/fundamentals cash-flow section totals are now value-or-envelope when a period does not articulate. When a period’s operating_cash_flow + investing_cash_flow + financing_cash_flow + FX-on-cash fails to reconcile to the filed net change in cash (typically an untagged FX line modern filers fold into the cash total), those three section totals — and the operating-cash-flow-derived free_cash_flow, fcf_margin_pct, ocf_yoy_pct, fcf_yoy_pct — return {available: false, reason: "cf_articulation_unverified"} instead of an internally inconsistent set of totals. This pairs with a change in the SEC coherence flip referee that no longer benches an entire dollar-correct symbol (income statement and balance sheet still serve from SEC) over a single cash-flow articulation miss, so more symbols serve SEC-native statements while a non-articulating cash flow is honestly refused.
  • schema_version bumped to 2026-06-16.1 to mark the payload-shape change.

2026-06-15: public analyst core positioning

Product-surface change, no REST route deletion:
  • Public core: docs, MCP, endpoint chooser, and agent recipes now position StockContext as a bounded analyst-grade core for active US-listed stocks and ETFs: search, coverage, snapshot, profile, price history, technicals, price action, compare, fundamentals, facts, valuation, priced-in growth, earnings actuals and company-stated guidance, dividends, filings, filing sections/diffs, insider Form 4/Form 144, SEC-derived events, and calendar.
  • Private beta: segments, ownership/13F/13D-G, and governance remain REST-callable for explicitly enabled integrations, but are removed from public MCP tool discovery and default public docs navigation until their coverage gates are strong enough.
  • Coverage contract: /v2/coverage now carries public_visibility so agents can distinguish public_core, private_beta, and internal_only from quality_grade and available_now.
  • Coverage source labels: public coverage contract output uses vendor-neutral source labels such as market_data, market_metadata, and price_history; internal contracts can stay provider-specific.
  • MCP: public tool discovery now exposes 21 tools instead of 24.
  • Token budgets: coverage raised 464 -> 3,732 and coverage-etf raised 670 -> 3,539 because the published coverage examples now include the full production contract fields plus public_visibility, and live coverage can carry larger availability state. Live G-BUDGET now gates public-core routes by default; private-beta route budgets remain available with an explicit opt-in check.

2026-06-14: segmented financials and coverage data-state

Additive SEC-data release:
  • New endpoint: GET /v2/segments?symbol=AAPL serves the precomputed multi-period SEC XBRL segment grid (business/geographic members, revenue, operating profit, accessions, filed dates, recast flags, and G-SEG reconciliation) on Starter and Builder plans. The route is cache-only: no request-path EDGAR fetch. A missing bootstrap returns segments: {available: false, reason: "segments_store_not_built"}; a built store with no usable breakout returns segment_data_not_disclosed.
  • Coverage honesty: /v2/coverage now includes the segments family and documents data-state fields for store-backed SEC families. Branch on support[family].available_now; supported remains route-level/back-compat support.
  • MCP: new tool stockcontext_segments was added at release time; see 2026-06-15 for the later public-core/private-beta split.
  • schema_version bumped to 2026-06-14.4 to mark the segmented-financials and coverage data-state shape.
  • Token budgets: segments budget added at 497 tokens. Raised coverage 161 -> 464 and coverage-etf 279 -> 670 for the richer route/data-state support map; raised ownership 1,339 -> 1,509 and ownership-13f 1,535 -> 1,830 from recaptured fixtures under the G-BUDGET +10% headroom rule.

2026-06-13: external-audit resolution — correctness, provenance & coverage

A trust pass clearing an external audit. Consumer-facing changes:
  • /v2/facts revenue is the statement total, never a subset. For issuers that tag a contract-revenue component (ASC-606) alongside the Revenues total (e.g. BRK-B), /v2/facts previously served the smaller component as revenue; it now applies the same dominated-component drop /v2/fundamentals uses and serves the total.
  • /v2/facts multi-class EPS/WASO. For multi-class issuers (GOOGL/GOOG, BRK) the grid serves the quoted ticker’s own share-class eps_basic/eps_diluted/shares_*_weighted (filed two-class-method values) for the periods a per-class filing was captured, and the consolidated companyfacts figure otherwise — provenance (the exact XBRL tag) distinguishes a class value from the consolidated one. The per-class overlay is point-in-time safe: an as_of query only applies a per-class value the filing date proves was filed on or before that date (no look-ahead leak).
  • /v2/facts semiannual cadence. Foreign filers that report half-yearly (live 6-K H1 facts) now serve their H1 periods with cadence: "semiannual" instead of being collapsed to annual (which dropped every interim row). The cadence enum is widened to quarterly | annual | semiannual (a semiannual response previously failed response validation).
  • /v2/fundamentals statements_source (additive). Every response now carries statements_source: "sec_edgar" | "vendor", labelling whether the statement rows came from the EDGAR-native store (per-value SEC provenance) or the price-vendor migration fallback for a not-yet-reconciled symbol. Treat vendor as lower-provenance.
  • /v2/fundamentals piotroski_f_score is value-or-envelope. When the F-Score can’t be computed it is now {available: false, reason: "insufficient_statement_history"} in the field itself — the old piotroski_f_score: null + sibling piotroski_status pair is gone (one field, one shape).
  • /v2/profile description is SEC-sourced or omitted. The business description is the SEC 10-K Item 1 first paragraph; the price vendor’s company/fund text is no longer substituted (prices-only). When no SEC description exists (ETFs, foreign issuers, pre-IPO) the field is omitted entirely (never a vendor substitute, never an empty string).
  • /v2/coverage support map now reports the four W6–W12 SEC families — events, ownership, governance, facts — each {supported: true} for an EDGAR-covered stock, not_applicable_for_etf for ETFs, symbol_does_not_file_us_domestic_forms for foreign issuers on events, no_sec_filer_match without a CIK.
  • Supported universe adds three multi-class tickers that were curated but unresolvable: GOOG (Alphabet Class C), RUSHB, WLYB.
  • Smaller default payloads: /v2/ownership beneficial_ownership.history and /v2/price-action fails_to_deliver.rows are now windowed to a recent default (the full series stays in the store) so the blocks can’t grow past their token budgets. coverage/coverage-etf budgets rose to fit the four new families (133 → 161, 206 → 279).
  • Public OpenAPI spec no longer lists the internal /version and /ops/freshness routes.
  • schema_version bumped to 2026-06-13.1 to mark the wire-shape changes in this pass.
Internal reliability (no wire change): the in-flight parse recovery and retry-requeue now fail loud (a Redis drop preserves the batch instead of losing a filing) — and the initial parse enqueue now fails loud the same way, so a Redis blip can no longer mark a filing warmed while its durable parse work was silently dropped; a facts-only fundamentals rebuild now tombstones any stale statements doc instead of leaving it readable behind a freshness-epoch bump; an Unkey valid=false verdict now purges the last-known-good cache so a revoked key can’t be resurrected via LKG during an upstream outage; bulk SEC downloads (companyfacts/submissions/FSDS) draw a fleet request slot and trip the 403/429 breaker; the stale 4.5 GB bootstrap memory guard now reads the env-tunable 18 GiB alarm; G-OWN’s expected-red coverage gap now expires; G-GOV and G-GUID fail on a silently-empty store/blind sample (and G-GUID refuses to seed its drift baseline from a degenerate near-zero parse rate); and repeated invalid API keys are negative-cached so they can’t force unbounded auth round-trips.

2026-06-13: /v2/facts — foreign-filer currency & cadence (fixes)

Two corrections for non-US (IFRS) filers on /v2/facts:
  • Native reporting currency. currency_unit now carries the filer’s functional currency (e.g. EUR, TWD, DKK) for foreign issuers instead of mislabeling them USD; US-GAAP filers stay USD. (This also fixes a regression where a non-USD currency_unit could 503.)
  • Reporting cadence. Foreign issuers that report only annually/semiannually now serve flow concepts (revenue, net_income, …) at their actual cadence on any request — a default quarterly request previously returned empty rows because these filers have no quarterly periods. The response’s cadence field reflects the cadence actually served.

2026-06-13: production-hardening pass — contract corrections & SEC-safety

A trust/hardening sweep over the EDGAR surfaces. Consumer-facing contract corrections:
  • /v2/events labels filter now documents the correct rejection: an unknown label returns 400 / PARAM_INVALID (the OpenAPI parameter description previously said 422; the behavior was always 400). A doc/spec correction, no behavior change.
  • /v2/facts currency_unit now reflects the filer’s native functional currency for IFRS issuers (it was hardcoded USD). US-GAAP filers are unaffected (still USD).
  • net_debt envelope now distinguishes a genuinely debt-free issuer (no_debt) from one whose debt component is absent from the filing (missing_balance_sheet_components) — previously both read as no_debt, which a consumer could misread as a debt-free balance sheet.
  • roic_pct description clarified: computed on a pre-tax operating-income basis, not after-tax NOPAT (the value was always operating-income-based; the description claimed after-tax).
  • dividends_paid sign normalized to a negative cash outflow (consistent with capex and the cash-flow statement face). The EDGAR-native path was the lone outlier — it served the XBRL PaymentsOfDividends magnitude as positive while the vendor path already served it negative, so the same field disagreed in sign depending on which path served a symbol. Now consistent across /v2/fundamentals and /v2/facts. All payout-ratio derivations take the absolute value, so they are unaffected. For symbols served from the EDGAR-native store the flip goes live as the nightly companyfacts rebuild repopulates the store; vendor-served symbols were already negative.
  • Insider cross-references corrected to “Form 4 + Form 144” (the endpoint never served Forms 3/5).
Internal reliability (no wire change): every direct SEC HTTP read now draws from the shared fleet rate budget and trips the 403/429 breaker; the API binds that budget on startup; the edgartools rate partition default dropped 9 → 4 to keep the fleet under SEC’s 10/s cliff; the parse queue’s pop + in-flight stash is one atomic operation; ingest store writes fail loud (requeue/dead-letter) instead of silently dropping; the G-OWN 13F-plausibility and G-NPORT coverage gates now actually fail on bad/missing data; /v2/history consults the derived-flip approval set like the rest of the surface; and insider cache invalidation now covers every limit variant via the per-symbol freshness epoch.

2026-06-12: the extended filing-detail catalog (opt-in)

/v2/fundamentals?blocks=statement_detail serves 50 additional filing fields per period — dividends per share (declared and paid, separate concepts), interest and taxes paid, the bank statement block (net interest income, noninterest income/expense, credit-loss provisions, loans, allowance), equity accounts (common stock, APIC, treasury value/shares, shares issued/authorized), working-capital changes, pensions, buyback detail, remaining performance obligation, and the year-by-year debt-maturity ladder. OPT-IN only — the default response is unchanged. annual_only_fields lists the fields that are 10-K cadence by construction (null on quarterly rows is filing reality, not staleness). Symbols whose statements are still vendor-sourced get {available: false, reason: "edgar_native_statements_only"}.

2026-06-12: dual-class EPS, foreign-issuer statements, ADR-safe market caps

  • Dual-class issuers serve the quoted ticker’s own class EPS and share counts (filed two-class-method results recovered from the filing instance — e.g. GOOG vs GOOGL diluted EPS are different numbers; BRK has no consolidated EPS at all). Provenance cites the filing accession and the class member.
  • Foreign private issuers (20-F filers) are served from their own ifrs-full XBRL with a pinned functional currency and a measured reporting cadence (annual or semiannual) recorded on the statement store. Native-currency fundamentals; USD multiples remain refused until an FX source is decided.
  • ADR market caps verify through a curated SEC-provenance ratio table (20-F cover titles and F-6 deposit agreements, every row accession-cited): share_count_basis: "adr_ratio" converts a verified ordinary-share count onto the quoted ADS basis. Unverifiable bases keep refusing — never a wrong market cap.

2026-06-12: filing-to-served freshness ≤ 15 minutes

A new SEC filing now propagates to every cached API surface within minutes: the 5-minute poller verifies the filing actually landed in the SEC’s structured-data API (retrying with backoff when it lags), rebuilds the statement store AND the derived daily history, and rolls a per-symbol cache epoch that invalidates fundamentals, snapshot, valuation, compare, priced-in, and history payloads at once. Previously assembled payloads could serve up to 12–24 hours behind a fresh filing.

2026-06-12: presentation conventions on /v2/fundamentals (breaking)

Three owner-decided conventions ship together. When filed data admits multiple legitimate presentations, StockContext serves the convention most consumers expect — documented here — and preserves the filed components so the filing is always recoverable.
  • total_debt is now lease-inclusive on EDGAR-native rows: borrowings plus finance-lease plus operating-lease liabilities (the dominant screener composition). New fields carry the filed split: debt_borrowings, operating_lease_liabilities, finance_lease_liabilities (null on vendor-sourced rows). net_debt and derived enterprise value follow the same convention on every surface (fundamentals, valuation, snapshot, compare, priced-in, history).
  • Renamed balance_sheet[].common_shares_outstandingshares_outstanding_cover_page: the count is the filing’s dei cover-page stamp, dated 3–5 weeks after the period end — the old name implied a period-end balance. The weighted-average shares_basic/shares_diluted (the EPS denominators) are the primary share fields.
  • ebitda gains a bottom-up fallback for issuers that file no operating-income line (REITs, financials, homebuilders): net income + taxes + interest + D&A, all filed inputs, provenance-labeled bottom_up. Refuses (null) when any input is missing.
  • gross_profit envelopes for banks and insurers (reason financial_company_metric_not_meaningful) — no cost-of-revenue concept applies to those statements; previously a bare null.

2026-06-12: statement-engine correctness (values only, no shape change)

Three correctness fixes to the EDGAR-native statements engine (the source for symbols flipped to EDGAR-native fundamentals; vendor-path symbols unaffected):
  • Per-share fields are never derived by subtraction. Quarterly EPS gaps (the derived fiscal Q4, or filers reporting only year-to-date EPS) now derive as the quarter’s own income-available-to-common ÷ weighted-average shares (provenance derived: "ratio"), or stay honestly absent. The old FY−ΣQ subtraction mixed share bases across split-restated filings and could print catastrophically wrong Q4 EPS. Derived weighted-average share counts now refuse when their inputs span share bases.
  • Fiscal calendars reject rolling 12-month windows. Some filers tag rolling twelve-month durations in 10-Qs; these could be mislabeled as fiscal years and shift the entire annual history (e.g. a phantom FY ending at a quarter date). True fiscal years tile; overlapping windows are rejected.
  • Revenue tag disqualification now sunsets. When an issuer stops tagging the Revenues total, the ASC-606 contract-revenue concept serves again as the top line from that point (previously such issuers could show no revenue at all after the switch).
  • Derived fiscal-Q4 values now also require all three prior quarters to be present — a gap no longer folds the missing quarter into Q4 silently.
  • Statement-engine coverage and correctness (same wave): short-term borrowings no longer double-count inside derived total debt when the current-debt aggregate already contains them; LongTermNotesPayable, long-term borrowing classes (FHLB advances, convertible notes, senior notes, LT credit lines, summed when no aggregate exists), E&P and software capex legs, PaymentsToAcquireOtherProductiveAssets, continuing-operations EPS variants, and the discontinued-ops-inclusive cash tag are now read; equity buyback flows are an additive composition over the filed financing legs; parent-only equity and attributable net income derive from filed NCI lines when the parent tag is absent; bank top-line revenue composes from the filed interest-income-after-provision and noninterest-income lines.
  • /v2/search token budget raised 106 → 133: the universe expansion (2026-06-12, 5,628 → 5,625 symbols) added a fourth live match for the documented query=apple example. Data growth, not a shape change.

2026-06-11: payout verdict and trailing PEG removed

schema_version is now 2026-06-11.
  • /v2/dividends: removed dividend_health.payout_safety; StockContext no longer ships a payout-safety letter grade. The underlying facts remain under dividend_health.track_record and dividend_health.payout_components. Renamed dividend_health.grade_components to dividend_health.payout_components.
  • /v2/snapshot: removed fundamentals_quick.peg_1y for stocks and ETFs.
  • /v2/valuation: removed multiples.peg_1y.
  • /v2/compare: removed peg_1y from the allowed fields list. Defaults are unchanged, but fields=peg_1y now returns 400 PARAM_INVALID.

2026-06-10: value-or-envelope consolidation, honest freshness

schema_version is now 2026-06-10.
  • Renamed the /v2/technicals relative_strength keys: vs_spy_1m_pctvs_spy_pct_1m, vs_spy_3m_pctvs_spy_pct_3m, vs_spy_1y_pctvs_spy_pct_1y, vs_sector_1y_pctvs_sector_pct_1y. On /v2/snapshot, performance.vs_sector_1y_pctvs_sector_pct_1y.
  • Removed the vs_sector_status and ratio_to_sector_status sibling objects everywhere. vs_sector_pct_1y (snapshot, technicals) and volume.ratio_to_sector_avg (price action) are now value-or-envelope: a number, or { available: false, reason: "not_applicable_for_etf" | "sector_benchmark_unavailable" }. On snapshot/technicals a bare null means only one thing: insufficient trading history for the window.
  • /v2/dividends: new current.yield_basis ("forward_annualized" | "trailing_12m"), always present when yield_pct is numeric, labels which convention produced the yield. Irregular payers now get { available: false, reason } envelopes — never bare null — on annual_rate, annual_rate_forward_estimated, next_ex_date_estimated, and next_payment_amount_estimated (reasons irregular_cadence_no_annual_rate, irregular_cadence_no_estimate); lapsed payers envelope the projection fields with reason dividend_lapsed. Removed payout_safety.rationale (a static string): payout_safety is now { grade } or an unavailable envelope.
  • /v2/earnings: eps_actual, revenue_actual, and the vs_trend baseline fields are now value-or-envelope (reasons not_reported_in_filed_statements, insufficient_reported_history). YoY comparisons state why they are unavailable: no_prior_period, not_reported_in_filed_statements (current quarter unreported), or missing_prior_quarter_value.
  • Freshness contract tightened: earnings, insider, calendar, filings, dividends, and priced-in never report freshness: "intraday" — they are end_of_day (or degraded/unsupported). The price-flavored endpoints (snapshot, valuation, technicals, price-action, history, compare) keep their freshness behavior — intraday-capable where they were before (/v2/history stays end_of_day-only) — and cached serves now re-stamp freshness truthfully at serve time: a body baked intraday can serve as end_of_day or stale once it ages. market_status is always the serve-time market state.

2026-06-06: contract corrections

  • /v2/compare now accepts 2–12 symbols per request (was 2–4). 13 or more returns 400 PARAM_INVALID; one returns 400 PARAM_INVALID.
  • PARAM_INVALID messages now name the offending parameter and, for enum/range errors, list the allowed values, so you can branch on the message instead of re-deriving the contract.
  • Documented the NOT_FOUND (404) error code returned for unmatched routes (a typo or wrong base path), distinct from SYMBOL_UNKNOWN.
  • Rate-limit headers (X-RateLimit-*) are now confirmed on every post-auth response, including 400, 403, and 404 SYMBOL_UNKNOWN; only a pre-auth 401 and an unmatched-route 404 NOT_FOUND omit them.
  • Snapshot/technicals expose vs_sector_1y_pct (1-year return versus the symbol’s sector benchmark ETF), with a vs_sector_status envelope when unavailable.
  • GET /version (root, not under /v2) returns the running build (commit, branch, built).

2026-06-05: v2 reference rebuilt

  • Every response example in these docs is now a captured production payload, not a hand-written sample.
  • Every response field is documented.
  • The error envelope schema is published: see response model and error codes.
  • Request and response samples ship in both Python and TypeScript.

How we ship changes

Additive changes (new response fields, new endpoints) arrive without notice and without a version bump. Parse defensively: ignore fields you do not recognize and never fail on an unexpected key. A client that tolerates unknown fields keeps working as the API grows. Breaking changes (removing or renaming a field, changing a type, narrowing behavior) get a dated entry here and advance the version. If it is not written on this page, it did not break.