# TGMCharts developer documentation > Every topic page of the TGMCharts developer docs (https://tgmcharts.com/developers/docs) as markdown, generated from the same source as the pages. Documentation updated 2026-10-10. Index and policy: https://tgmcharts.com/llms.txt · OpenAPI: https://tgmcharts.com/api/v1/openapi.json · MCP server: https://tgmcharts.com/api/v1/mcp Pages: - Stock summary endpoint: https://tgmcharts.com/developers/docs/summary.md - Metric series endpoint: https://tgmcharts.com/developers/docs/series.md - Chart image endpoint: https://tgmcharts.com/developers/docs/charts.md - Financial statements endpoint: https://tgmcharts.com/developers/docs/statements.md - MCP server for AI agents: https://tgmcharts.com/developers/docs/mcp.md - Authentication, rate limits and pricing: https://tgmcharts.com/developers/docs/authentication-and-limits.md - Data quality and lineage: https://tgmcharts.com/developers/docs/data-quality.md - Quickstarts: https://tgmcharts.com/developers/docs/quickstarts.md - Connect TGMCharts to Claude: https://tgmcharts.com/developers/docs/connect-claude.md - Connect TGMCharts to ChatGPT: https://tgmcharts.com/developers/docs/connect-chatgpt.md - Connect TGMCharts to Cursor: https://tgmcharts.com/developers/docs/connect-cursor.md - Connect TGMCharts to VS Code: https://tgmcharts.com/developers/docs/connect-vscode.md - Connect TGMCharts to Claude Code: https://tgmcharts.com/developers/docs/connect-claude-code.md # Stock summary endpoint > Compact JSON summary of a stock's fundamentals: latest close, valuation ratios, margins, dividends, growth CAGRs, as-of dates, honest nulls. Keyless, CORS-open. Page: https://tgmcharts.com/developers/docs/summary · Documentation updated 2026-10-10 · All docs as one file: https://tgmcharts.com/llms-full.txt ## Endpoint `GET https://tgmcharts.com/api/v1/summary/{symbol}` returns a compact (~5 KB) JSON view of one US-listed stock or ETF: identity, latest end-of-day close, valuation, profitability, financial health, dividends, growth CAGRs, provenance dates, and page links. No key is required; responses are CORS-open and edge-cached. Symbols are 1–10 characters (letters, digits, dot, dash) and are matched case-insensitively. A malformed symbol answers `400`; an uncovered symbol answers `404` with an onboarding hint (see below). **curl** ``` curl -s https://tgmcharts.com/api/v1/summary/AAPL ``` **Response headers (keyless)** ``` Content-Type: application/json Cache-Control: public, s-maxage=3600, stale-while-revalidate=86400 Access-Control-Allow-Origin: * ``` ## Fields Every scalar is `number | null`. Percent fields carry a `Percent` suffix and are expressed in percentage points (a 2.9% yield is `2.9`). Fundamentals are trailing-twelve-month unless a field name says otherwise; prices are official end-of-day closes. | Field | Contents | |---|---| | symbol, name, sector, industry | Identity as stored; `name`/`sector`/`industry` are null when not stored. | | currency, reportedCurrency | `currency` is always USD. `reportedCurrency` names the filer's own currency for foreign filers whose statements were converted at per-date FX; null otherwise. | | asOf | `dataUpdatedAt` — the ISO time the symbol was last precomputed — plus a fixed basis note (end-of-day closes; TTM fundamentals unless suffixed). | | price | Latest official close, day change, market cap, 52-week high/low, YTD and 1-year returns (percent). | | valuation | P/E (trailing and forward), P/S, P/B, P/FCF, PEG, EV/EBITDA, EV/Sales, earnings yield, FCF yield. P/B divides market cap by the book value attributable to common shareholders (total equity minus preferred stock). FCF- and EV-family fields are null when not meaningful for the company type, P/S and P/B are null for a fund, and the P/E family (`peRatio`, `peRatioForward`, `pegRatio`, `earningsYieldPercent`) is null for a fund and while the company's category is still being prepared (see `applicability`). | | profitability | Gross, operating and net margin, ROE, ROA, ROIC — percent. | | financialHealth | Current ratio, quick ratio, debt-to-equity, interest coverage. | | dividends | Yield (percent), payout ratio (percent), dividend per share, consecutive years of increases. | | growthCagrPercent | 3-, 5- and 10-year CAGRs for revenue, gross profit, net income, EPS, free cash flow, dividends and total return — null where the window is not covered. | | applicability | Whether the free-cash-flow (`freeCashFlow`), enterprise-value (`enterpriseValue`) and P/E-family (`earnings`) metrics are `applicable`, secondary context, or intentionally withheld; a withheld metric carries the reason (not meaningful for this company type, not yet verified, or the company's category still being prepared). | | classification | The company type that decides which metrics apply: `type` is one of operating, bank, insurer, capital_markets, reit_equity, reit_mortgage, real_estate_operating or fund, and `flags` gives adr, foreignFiler, semiannualReporter and fund as booleans. The whole key is null while the symbol's stored data carries no classification; a flag that is not stored is null, never false. | | links | The stock's overview, metrics and financials pages, plus llms.txt. | ## Response shape The skeleton below is produced by the same builder the endpoint runs, given no stored data — so every value reads `null`. A live response has the identical keys with the stored numbers filled in. It is shown this way on purpose: the docs never print numbers that were not read from the data store. **GET /api/v1/summary/AAPL — shape (all values null here)** ``` { "symbol": "AAPL", "name": null, "sector": null, "industry": null, "currency": "USD", "reportedCurrency": null, "asOf": { "dataUpdatedAt": null, "note": "lastClose is the verified official regular-session close; latestPrice is a regular-session quote and may be delayed. Fundamentals are trailing-twelve-month unless suffixed otherwise." }, "price": { "lastClose": null, "lastCloseDate": null, "latestPrice": null, "priceSource": null, "change": null, "changePercent": null, "marketCap": null, "high52Week": null, "low52Week": null, "returnYtdPercent": null, "return1YPercent": null }, "valuation": { "peRatio": null, "peRatioForward": null, "psRatio": null, "pbRatio": null, "pfcfRatio": null, "pegRatio": null, "evToEbitda": null, "evToSales": null, "earningsYieldPercent": null, "fcfYieldPercent": null }, "profitability": { "grossMarginPercent": null, "operatingMarginPercent": null, "netMarginPercent": null, "roePercent": null, "roaPercent": null, "roicPercent": null }, "financialHealth": { "currentRatio": null, "quickRatio": null, "debtToEquity": null, "interestCoverage": null }, "dividends": { "yieldPercent": null, "payoutRatioPercent": null, "dividendPerShare": null, "consecutiveYears": null }, "growthCagrPercent": { "revenue": { "y3": null, "y5": null, "y10": null }, "grossProfit": { "y3": null, "y5": null, "y10": null }, "netIncome": { "y3": null, "y5": null, "y10": null }, "eps": { "y3": null, "y5": null, "y10": null }, "freeCashFlow": { "y3": null, "y5": null, "y10": null }, "dividends": { "y3": null, "y5": null, "y10": null }, "totalReturn": { "y3": null, "y5": null, "y10": null } }, "links": { "overview": "https://tgmcharts.com/stocks/AAPL", "metrics": "https://tgmcharts.com/stocks/AAPL/metrics", "financials": "https://tgmcharts.com/stocks/AAPL/financials", "docs": "https://tgmcharts.com/llms.txt" }, "applicability": { "freeCashFlow": "Unavailable for now: this company's category is being prepared.", "enterpriseValue": "Unavailable for now: this company's category is being prepared.", "earnings": "Unavailable for now: this company's category is being prepared." }, "classification": null } ``` ## Honest states - `null` means the value is not stored or not meaningful for the company type — it is never a zero standing in for missing data. A stored zero (for example a zero dividend per share) is served as `0`. - Free-cash-flow and enterprise-value metrics are withheld (`null`) for banks, insurers, REITs and funds, where the definitions are not meaningful, and the P/E family is withheld for funds and while a company's category is still being prepared; `applicability` says which and why. - An uncovered symbol answers `404` with a short negative cache (`s-maxage=120`) so coverage onboarding — started when a person asks for the symbol on its stock page, about two minutes — is not outlived by a cached miss. Fetching the page does not start it. **404 — symbol not covered** ``` { "error": "Symbol not covered", "symbol": "ZZZQ", "hint": "If this is a real ticker, coverage onboarding (~2 minutes) starts when a person asks for it with one click at https://tgmcharts.com/stocks/ZZZQ. Fetching that page does not start it." } ``` ## Caching and keys Data changes at most once a day (after the US close), so cache responses for at least an hour — the headers above do it for you. With an API key the same request is metered at one unit and answered with `Cache-Control: private` plus `X-RateLimit-*` headers; see [authentication and limits](https://tgmcharts.com/developers/docs/authentication-and-limits). ## Frequently asked questions ### What does the stock summary endpoint return? A compact JSON object with the stock's identity, latest end-of-day close and market cap, valuation ratios (P/E, P/S, P/B, P/FCF, PEG, EV/EBITDA, EV/Sales, earnings and FCF yield), margins and returns, financial-health ratios, dividend record, 3/5/10-year growth CAGRs, as-of dates, and page links. ### Why is a value null? Because it is not stored, or because it is not meaningful for the company type (free-cash-flow and enterprise-value metrics for banks, insurers, REITs and funds). The applicability block explains the withheld families. Nothing is zero-filled. ### Do I need an API key for the summary endpoint? No. It is keyless and CORS-open with attribution. A key adds exact metering, per-account quotas and X-RateLimit headers. # Metric series endpoint > Metric history as JSON or CSV: daily 20-year valuation lines, rolling TTM flows, quarterly margins, SEC-filed statement metrics. Methodology on every response. Page: https://tgmcharts.com/developers/docs/series · Documentation updated 2026-10-10 · All docs as one file: https://tgmcharts.com/llms-full.txt ## Endpoint `GET https://tgmcharts.com/api/v1/series/{symbol}/{metric}` returns one metric's stored history for one symbol. One slug is one series with one basis (daily, monthly, annual, quarterly, or TTM — the catalogue below states each one; a series is never described as denser than it is stored). Keyless and CORS-open; unknown query keys answer `400`. | Query parameter | Values | Behavior | |---|---|---| | years | integer 2–20 | Trailing window ending at the last stored point. Omitted: the full stored history. | | format | json (default) \| csv | CSV is a `date,value` table with `#` provenance comments (below). | | period | annual \| quarterly \| ttm \| daily | Basis alias: `revenue?period=ttm` answers `308` to the canonical sibling `revenue-ttm`. A basis the metric does not have answers `400` listing the available ones. | **curl · 10 years of daily P/E** ``` curl -s "https://tgmcharts.com/api/v1/series/KO/pe-ratio?years=10" ``` **curl · the same series as CSV** ``` curl -s "https://tgmcharts.com/api/v1/series/KO/pe-ratio?years=10&format=csv" -o ko-pe-ratio.csv ``` **curl · annual revenue as filed with the SEC** ``` curl -s https://tgmcharts.com/api/v1/series/AAPL/revenue ``` ## Response shape A type sketch, not a live response — the docs do not print numbers that were not read from the data store. `methodology` is the registry's computation note for the slug, served verbatim; `source` appears only on the EDGAR-lane metrics. **GET /api/v1/series/{symbol}/{metric} — shape** ``` { "symbol": "KO", "name": string | null, "metric": "pe-ratio", "label": "P/E Ratio", "unit": "usd" | "usdPerShare" | "percent" | "ratio", "basis": "daily" | "monthly" | "annual" | "quarterly" | "ttm", "methodology": string, // the registry's computation note, verbatim "source": "sec-edgar-companyfacts", // present on EDGAR-lane metrics only "asOf": ISO date-time | null, // when the series was last recomputed; the last point's date is the last close or period it covers "years": integer | null, // the ?years= you asked for "points": [ { "date": "YYYY-MM-DD", "value": number }, … ] | null, "applicability": "applicable" | { "tone": "hard" | "soft", "message": string }, "note": string, // present when points is null or [] "links": { "chart": string | null, "page": string, "docs": string, "openapi": string } } ``` ## Honest states - `points: null` with `applicability: { tone: "hard", … }` — the metric is intentionally withheld for the company type (EV and FCF families on banks, insurers, REITs and funds). The message says why. - `points: []` with a `note` — the symbol is covered but no history is stored for this metric yet (or, on the EDGAR lane, no SEC XBRL fact maps to it). An honest gap, not a zero. - EDGAR-lane metrics on a symbol whose SEC data is still being ingested answer `200`, `points: []`, a preparing note, and a short `s-maxage=120` cache so the state is not outlived by the edge. - `404` for an uncovered symbol (onboarding hint), and `404` for a slug that is not in the series tier — the body lists every valid `seriesMetrics` slug and links the OpenAPI document. ## Metric catalogue Generated from the same registry the endpoint reads, so a slug listed here resolves. Series-tier slugs (JSON/CSV): pe-ratio, ps-ratio, pb-ratio, pfcf-ratio, pocf-ratio, ev-ebitda, ev-ebit, ev-sales, ev-fcf, ev-assets, earnings-yield, fcf-yield, ebitda-yield, ocf-yield, dividend-yield, total-return, roic, revenue-ttm, net-income-ttm, fcf-ttm, ebitda-ttm, capex-ttm, buybacks-ttm, sbc-ttm, rd-ttm, gross-margin-quarterly, operating-margin-quarterly, net-margin-quarterly, revenue, net-income, capex, buybacks, stock-based-comp, r-and-d, revenue-quarterly, net-income-quarterly. Chart-only slugs (PNG via [the charts endpoint](https://tgmcharts.com/developers/docs/charts), JSON pending EDGAR coverage): eps, free-cash-flow, ebitda, gross-margin, operating-margin, profit-margin, roe, roa, eps-quarterly, fcf-quarterly. Source: TGMCharts-computed series are derived by TGMCharts from licensed end-of-day market data and reported statements (daily valuation and yield lines, rolling TTM flows, quarterly margins, ROIC, total return). SEC EDGAR entries (revenue, net-income, capex, buybacks, stock-based-comp, r-and-d, revenue-quarterly, net-income-quarterly) are as filed in XBRL company facts, public domain, and carry `source: "sec-edgar-companyfacts"`. See [data quality and lineage](https://tgmcharts.com/developers/docs/data-quality). | Metric | Slug | Unit | Basis | Source | Series (JSON/CSV) | Chart (PNG) | |---|---|---|---|---|---|---| | P/E Ratio | pe-ratio | ratio (×) | daily | TGMCharts-computed | yes | yes | | P/S Ratio | ps-ratio | ratio (×) | daily | TGMCharts-computed | yes | yes | | P/B Ratio | pb-ratio | ratio (×) | daily | TGMCharts-computed | yes | yes | | P/FCF Ratio | pfcf-ratio | ratio (×) | daily | TGMCharts-computed | yes | yes | | P/OCF Ratio | pocf-ratio | ratio (×) | daily | TGMCharts-computed | yes | yes | | EV/EBITDA | ev-ebitda | ratio (×) | daily | TGMCharts-computed | yes | yes | | EV/EBIT | ev-ebit | ratio (×) | daily | TGMCharts-computed | yes | yes | | EV/Sales | ev-sales | ratio (×) | daily | TGMCharts-computed | yes | yes | | EV/FCF | ev-fcf | ratio (×) | daily | TGMCharts-computed | yes | yes | | EV/Assets | ev-assets | ratio (×) | daily | TGMCharts-computed | yes | yes | | Earnings Yield | earnings-yield | percent | daily | TGMCharts-computed | yes | yes | | FCF Yield | fcf-yield | percent | daily | TGMCharts-computed | yes | yes | | EBITDA Yield | ebitda-yield | percent | daily | TGMCharts-computed | yes | yes | | OCF Yield | ocf-yield | percent | daily | TGMCharts-computed | yes | yes | | Dividend Yield | dividend-yield | percent | monthly | TGMCharts-computed | yes | yes | | Total Return | total-return | USD | daily | TGMCharts-computed | yes | yes | | ROIC | roic | percent | annual | TGMCharts-computed | yes | yes | | Revenue (TTM) | revenue-ttm | USD | ttm | TGMCharts-computed | yes | yes | | Net Income (TTM) | net-income-ttm | USD | ttm | TGMCharts-computed | yes | yes | | Free Cash Flow (TTM) | fcf-ttm | USD | ttm | TGMCharts-computed | yes | yes | | EBITDA (TTM) | ebitda-ttm | USD | ttm | TGMCharts-computed | yes | yes | | Capital Expenditure (TTM) | capex-ttm | USD | ttm | TGMCharts-computed | yes | yes | | Buybacks (TTM) | buybacks-ttm | USD | ttm | TGMCharts-computed | yes | yes | | Stock-Based Compensation (TTM) | sbc-ttm | USD | ttm | TGMCharts-computed | yes | yes | | R&D Expense (TTM) | rd-ttm | USD | ttm | TGMCharts-computed | yes | yes | | Gross Margin (Quarterly) | gross-margin-quarterly | percent | quarterly | TGMCharts-computed | yes | yes | | Operating Margin (Quarterly) | operating-margin-quarterly | percent | quarterly | TGMCharts-computed | yes | yes | | Net Margin (Quarterly) | net-margin-quarterly | percent | quarterly | TGMCharts-computed | yes | yes | | Revenue | revenue | USD | annual | SEC EDGAR company facts (as filed) | yes | yes | | Net Income | net-income | USD | annual | SEC EDGAR company facts (as filed) | yes | yes | | EPS | eps | USD per share | annual | TGMCharts-computed | no — chart only | yes | | Free Cash Flow | free-cash-flow | USD | annual | TGMCharts-computed | no — chart only | yes | | EBITDA | ebitda | USD | annual | TGMCharts-computed | no — chart only | yes | | Capital Expenditure | capex | USD | annual | SEC EDGAR company facts (as filed) | yes | yes | | Buybacks | buybacks | USD | annual | SEC EDGAR company facts (as filed) | yes | yes | | Stock-Based Compensation | stock-based-comp | USD | annual | SEC EDGAR company facts (as filed) | yes | yes | | R&D Expense | r-and-d | USD | annual | SEC EDGAR company facts (as filed) | yes | yes | | Gross Margin | gross-margin | percent | annual | TGMCharts-computed | no — chart only | yes | | Operating Margin | operating-margin | percent | annual | TGMCharts-computed | no — chart only | yes | | Profit Margin | profit-margin | percent | annual | TGMCharts-computed | no — chart only | yes | | Return on Equity | roe | percent | annual | TGMCharts-computed | no — chart only | yes | | Return on Assets | roa | percent | annual | TGMCharts-computed | no — chart only | yes | | Revenue (Quarterly) | revenue-quarterly | USD | quarterly | SEC EDGAR company facts (as filed) | yes | yes | | Net Income (Quarterly) | net-income-quarterly | USD | quarterly | SEC EDGAR company facts (as filed) | yes | yes | | EPS (Quarterly) | eps-quarterly | USD per share | quarterly | TGMCharts-computed | no — chart only | yes | | Free Cash Flow (Quarterly) | fcf-quarterly | USD | quarterly | TGMCharts-computed | no — chart only | yes | ## CSV format `?format=csv` answers `text/csv` with the same content: leading `#` comment lines carry the metric, as-of date, methodology, any applicability/note honest-state signal, and the terms line, followed by a `date,value` header and one row per stored point at full precision. Readers that honor a comment character (pandas `comment="#"`, R `comment.char="#"`) load it directly. **CSV layout** ``` # TGMCharts — KO P/E Ratio (pe-ratio) # as of: # methodology: # terms: https://tgmcharts.com/terms — attribution required (data by TGMCharts, tgmcharts.com) date,value , … ``` ## Frequently asked questions ### Which metrics are available as JSON series? The series tier serves 36 slugs: TGMCharts-computed daily valuation and yield lines, rolling TTM flows, quarterly margins, ROIC and total return, plus SEC-EDGAR-sourced statement metrics (revenue, net-income, capex, buybacks, stock-based-comp, r-and-d, revenue-quarterly, net-income-quarterly). The remaining statement metrics are chart renders until EDGAR coverage extends to them. ### What does points: null mean? The metric is intentionally withheld because it is not meaningful for the company type — for example EV/EBITDA on a bank or FCF yield on a REIT. The applicability object carries the explanation. An empty array means the symbol is covered but nothing is stored for the metric yet. ### How far back does the history go? As far as the stored history reaches: daily valuation lines run up to 20 years for companies with that much price and filing history, and EDGAR statement series cover the fiscal years the company has filed in XBRL. The years parameter trims the window; it never pads it. # Chart image endpoint > Embed 1600×900 PNG charts of stock fundamentals with one URL: revenue, EPS, margins, daily P/E and other valuation lines, attribution and as-of date in frame. Page: https://tgmcharts.com/developers/docs/charts · Documentation updated 2026-10-10 · All docs as one file: https://tgmcharts.com/llms-full.txt ## Endpoint `GET https://tgmcharts.com/api/v1/charts/{symbol}/{metric}` renders a 1600×900 PNG (`image/png`) of the metric's stored history in TGMCharts' own chart style: line charts for daily valuation and yield series, bars for annual, quarterly and TTM statement series. The TGMCharts wordmark and the data-as-of footer are part of the frame — they are the attribution required by the [API terms](https://tgmcharts.com/terms) and no parameter removes them. | Query parameter | Values | Behavior | |---|---|---| | years | integer 2–20 | Trailing window. Defaults by basis: 20 years for daily and monthly lines, 10 for annual bars, 3 for quarterly and TTM bars. | | compare | a second ticker | Grouped comparison bars, bar-chart metrics only. When either series has a negative value the render falls back to the primary series and says so in the subhead. | | period | annual \| quarterly \| ttm \| daily | Basis alias — `308` to the canonical per-basis slug, like the series endpoint. | **HTML embed** ``` AAPL annual revenue — data by TGMCharts ``` **Markdown (README, issue, newsletter)** ``` ![KO dividend yield, 20 years](https://tgmcharts.com/api/v1/charts/KO/dividend-yield?years=20) ``` **Comparison bars** ``` https://tgmcharts.com/api/v1/charts/KO/revenue?compare=PEP ``` ## What is in the frame - Line series are downsampled to at most 300 evenly spaced points; bar series show the most recent 22 periods of the window. - The headline shows the latest value in the window; the subhead states the basis (daily series, sampled about monthly, by fiscal year, by fiscal quarter, rolling trailing-twelve-month) and the year span; the footer carries the data-as-of date. - A metric that is not meaningful for the company type, or a symbol with no stored history for it, renders an explanation card at `200` — an `` embed degrades into a readable reason, never blank space or an invented series. - Renders read stored, precomputed data only; no request waits on a live market-data call. ## Chart metrics Generated from the registry the endpoint reads. `?compare=` is accepted on bar charts only. | Metric | Slug | Basis | Chart | Default window | ?compare= | |---|---|---|---|---|---| | P/E Ratio | pe-ratio | daily | line | 20 years | no (line) | | P/S Ratio | ps-ratio | daily | line | 20 years | no (line) | | P/B Ratio | pb-ratio | daily | line | 20 years | no (line) | | P/FCF Ratio | pfcf-ratio | daily | line | 20 years | no (line) | | P/OCF Ratio | pocf-ratio | daily | line | 20 years | no (line) | | EV/EBITDA | ev-ebitda | daily | line | 20 years | no (line) | | EV/EBIT | ev-ebit | daily | line | 20 years | no (line) | | EV/Sales | ev-sales | daily | line | 20 years | no (line) | | EV/FCF | ev-fcf | daily | line | 20 years | no (line) | | EV/Assets | ev-assets | daily | line | 20 years | no (line) | | Earnings Yield | earnings-yield | daily | line | 20 years | no (line) | | FCF Yield | fcf-yield | daily | line | 20 years | no (line) | | EBITDA Yield | ebitda-yield | daily | line | 20 years | no (line) | | OCF Yield | ocf-yield | daily | line | 20 years | no (line) | | Dividend Yield | dividend-yield | monthly | line | 20 years | no (line) | | Total Return | total-return | daily | line | 20 years | no (line) | | ROIC | roic | annual | bars | 10 years | yes | | Revenue (TTM) | revenue-ttm | ttm | bars | 3 years | yes | | Net Income (TTM) | net-income-ttm | ttm | bars | 3 years | yes | | Free Cash Flow (TTM) | fcf-ttm | ttm | bars | 3 years | yes | | EBITDA (TTM) | ebitda-ttm | ttm | bars | 3 years | yes | | Capital Expenditure (TTM) | capex-ttm | ttm | bars | 3 years | yes | | Buybacks (TTM) | buybacks-ttm | ttm | bars | 3 years | yes | | Stock-Based Compensation (TTM) | sbc-ttm | ttm | bars | 3 years | yes | | R&D Expense (TTM) | rd-ttm | ttm | bars | 3 years | yes | | Gross Margin (Quarterly) | gross-margin-quarterly | quarterly | bars | 3 years | yes | | Operating Margin (Quarterly) | operating-margin-quarterly | quarterly | bars | 3 years | yes | | Net Margin (Quarterly) | net-margin-quarterly | quarterly | bars | 3 years | yes | | Revenue | revenue | annual | bars | 10 years | yes | | Net Income | net-income | annual | bars | 10 years | yes | | EPS | eps | annual | bars | 10 years | yes | | Free Cash Flow | free-cash-flow | annual | bars | 10 years | yes | | EBITDA | ebitda | annual | bars | 10 years | yes | | Capital Expenditure | capex | annual | bars | 10 years | yes | | Buybacks | buybacks | annual | bars | 10 years | yes | | Stock-Based Compensation | stock-based-comp | annual | bars | 10 years | yes | | R&D Expense | r-and-d | annual | bars | 10 years | yes | | Gross Margin | gross-margin | annual | bars | 10 years | yes | | Operating Margin | operating-margin | annual | bars | 10 years | yes | | Profit Margin | profit-margin | annual | bars | 10 years | yes | | Return on Equity | roe | annual | bars | 10 years | yes | | Return on Assets | roa | annual | bars | 10 years | yes | | Revenue (Quarterly) | revenue-quarterly | quarterly | bars | 3 years | yes | | Net Income (Quarterly) | net-income-quarterly | quarterly | bars | 3 years | yes | | EPS (Quarterly) | eps-quarterly | quarterly | bars | 3 years | yes | | Free Cash Flow (Quarterly) | fcf-quarterly | quarterly | bars | 3 years | yes | ## Caching PNG responses carry `Cache-Control: public, max-age=3600, s-maxage=21600, stale-while-revalidate=86400`, so a URL that has been requested once is served from the edge; the render refreshes with the daily data update. Do not cache-bust the URL — the same URL is the point. ## Render limit Keyless callers may start up to 30 new (uncached) renders per minute per IP address; cached URLs are not counted. Past the limit the endpoint answers `429` with `Retry-After: 60` and the body below. A keyed request is exempt from this limiter and metered at 5 units per render against the account's tier quota instead — see [authentication and limits](https://tgmcharts.com/developers/docs/authentication-and-limits). **429 — keyless render limit** ``` { "error": "Render rate limit reached — cached chart URLs are unlimited; new renders are capped per minute. API keys lift this to tier quotas: https://tgmcharts.com/developers/keys", "upgradeUrl": "https://tgmcharts.com/developers/keys", "docs": "https://tgmcharts.com/developers/docs/authentication-and-limits" } ``` ## Errors - `400` — unknown query key, out-of-range `years`, `compare` on a line metric, or `compare` equal to the primary symbol. - `404` — symbol not covered (onboarding hint), or a slug outside the chart tier (the body lists every `chartMetrics` slug). - Error bodies are JSON; only successful renders are `image/png`. ## Frequently asked questions ### Can I embed the chart image in a README, newsletter or app? Yes. The URL is the image: put it in an \ tag or a Markdown image. The frame carries the TGMCharts attribution and the data-as-of date, which satisfies the attribution requirement of the API terms. Keep the frame intact. ### How often do chart images update? With the daily data refresh after the US market close. The edge caches a rendered URL for six hours and serves it stale for up to a day while it re-renders, so an embedded chart follows the data within a day. ### Can I remove the TGMCharts wordmark from the chart? No. The wordmark and as-of footer are the attribution the API terms require, and no parameter hides them. # Financial statements endpoint > Income statement, balance sheet and cash flow as filed with the SEC: JSON or CSV from EDGAR XBRL company facts with per-value provenance (tag, accession, date). Page: https://tgmcharts.com/developers/docs/statements · Documentation updated 2026-10-10 · All docs as one file: https://tgmcharts.com/llms-full.txt ## Endpoint `GET https://tgmcharts.com/api/v1/statements/{symbol}/{statement}` serves raw, as-filed statement rows from SEC EDGAR XBRL company facts — public-domain lineage end to end. `{statement}` is one of `income-statement`, `balance-sheet`, `cash-flow`. Keyless and CORS-open. | Query parameter | Values | Behavior | |---|---|---| | period | annual (default) \| quarterly | Quarterly serves the as-filed discrete quarters plus disclosed derived ones (see provenance). | | years | integer 1–30 (default 10) | Trailing fiscal years of rows; quarterly serves 4 × years rows, capped at 120. Out of range answers `400` — never clamped. | | format | json (default) \| csv | CSV: one row per fiscal period, one column per concept, `#` provenance comments. | **curl · five annual income statements** ``` curl -s "https://tgmcharts.com/api/v1/statements/AAPL/income-statement?years=5" ``` **curl · quarterly cash flow as CSV** ``` curl -s "https://tgmcharts.com/api/v1/statements/KO/cash-flow?period=quarterly&years=3&format=csv" -o ko-cash-flow-quarterly.csv ``` ## Response shape A type sketch. Rows are newest first; every catalogue concept appears on every row, with `null` where the filer tagged nothing for that period — never a zero. **GET /api/v1/statements/{symbol}/{statement} — shape** ``` { "symbol": "AAPL", "entityName": string | null, "cik": string | null, "statement": "income-statement" | "balance-sheet" | "cash-flow", "period": "annual" | "quarterly", "currency": "USD", "source": "SEC EDGAR XBRL company facts (public domain)", "asOf": ISO date-time | null, // last EDGAR ingestion for this symbol "methodology": string, "status": "preparing" | "unavailable", // ABSENT when rows are served "reason": string, // with status: unavailable "note": string, // honest-state explanation "concepts": [ { "key": string, "label": string, "unit": "USD" | "USD/shares" | "shares", "tags": string[] }, … ], "rows": [ // newest first; null while status is set { "fiscalYear": integer, "fiscalPeriod": "FY" | "Q1" | "Q2" | "Q3" | "Q4", "periodStart": "YYYY-MM-DD" | null, // null for balance-sheet instants "periodEnd": "YYYY-MM-DD", "form": "10-K" | "10-Q" | … | null, // the most recently filed fact on the row "filed": "YYYY-MM-DD" | null, "metrics": { "": number | null, … }, "provenance": { "": { "tag": string, "accn": string, "form": string, "filed": "YYYY-MM-DD", "derived": "ytd-differencing", "inputs": [accn, accn] } // derived/inputs on derived quarters only } } ], "links": { "page": string, "docs": string, "openapi": string } } ``` ## Per-value provenance - `provenance[key].tag` — the us-gaap tag that produced the value (one winning tag per concept per symbol; the priority lists are below). - `provenance[key].accn`, `form`, `filed` — the accession number, form type and filing date of the filing the value was taken from. Latest-filed wins per period, so a restated figure supersedes the original. - `provenance[key].derived: "ytd-differencing"` with `inputs: [accn, accn]` — a quarter the filer did not tag discretely (Q4 generally; Q2–Q3 for cash-flow items, which 10-Qs tag year-to-date) was derived by differencing two same-tag, same-fiscal-year facts, and both source accessions are disclosed. Derivation is withheld when a surrounding filing restates prior periods. - Per-share values and share counts are never derived, and per-share values are as filed — not adjusted for later stock splits. ## Preparing and unavailable states - `status: "preparing"` (HTTP `200`, `rows: null`, short `s-maxage=120` cache) — the symbol is covered by the site but its SEC EDGAR data has not been ingested yet. No value is substituted from any other source in the meantime. - `status: "unavailable"` with a `reason` (HTTP `200`, daily cache) — the security has no usable us-gaap/USD company facts: typically an ETF or trust, or a filer reporting under IFRS or in a non-USD currency. This is a stable, periodically re-checked state, not a pending one. - `404` — the symbol is not covered at all (onboarding hint), or the statement slug is unknown (the body lists the three valid ones). - `rows: []` with a `note` — ingested, but no XBRL fact mapped to this statement's concepts. ## Methodology (served verbatim on every response) Values as filed with the SEC (XBRL company facts, public domain), selected latest-filed per period; the winning us-gaap tag, accession number, and filing date are recorded per value in `provenance`. Quarters not filed discretely (Q4 generally; Q2-Q3 for cash-flow items, which 10-Qs tag year-to-date only) are derived solely by differencing two same-tag, same-fiscal-year facts and are marked derived with both source accessions; derivation is withheld when a surrounding filing restates prior periods. Per-share values are as filed and NOT adjusted for subsequent stock splits. Missing data is null — never zero-filled, never backfilled from any other source. ## Income statement concepts The `metrics` keys served for `income-statement`, with the us-gaap tags tried in priority order. Generated from the concept catalogue the ingestion lane uses. For revenue the priority is applied per period (`Revenues` first, then the ASC 606 tags), so filers that tag both never have the narrower contract-revenue subset served as total revenue. | Key | Label | Unit | us-gaap tags (priority order) | |---|---|---|---| | revenue | Revenue | USD | Revenues, RevenueFromContractWithCustomerExcludingAssessedTax, RevenueFromContractWithCustomerIncludingAssessedTax, SalesRevenueNet, SalesRevenueGoodsNet, SalesRevenueServicesNet | | costOfRevenue | Cost of Revenue | USD | CostOfRevenue, CostOfGoodsAndServicesSold | | grossProfit | Gross Profit | USD | GrossProfit | | operatingExpenses | Operating Expenses | USD | OperatingExpenses | | researchAndDevelopmentExpenses | Research & Development Expense | USD | ResearchAndDevelopmentExpense, ResearchAndDevelopmentExpenseExcludingAcquiredInProcessCost | | sellingGeneralAndAdministrativeExpenses | Selling, General & Administrative Expense | USD | SellingGeneralAndAdministrativeExpense | | operatingIncome | Operating Income | USD | OperatingIncomeLoss | | interestExpense | Interest Expense | USD | InterestExpense, InterestExpenseNonoperating | | pretaxIncome | Pre-Tax Income | USD | IncomeLossFromContinuingOperationsBeforeIncomeTaxesExtraordinaryItemsNoncontrollingInterest, IncomeLossFromContinuingOperationsBeforeIncomeTaxesMinorityInterestAndIncomeLossFromEquityMethodInvestments | | incomeTaxExpense | Income Tax Expense | USD | IncomeTaxExpenseBenefit | | netIncome | Net Income | USD | NetIncomeLoss, ProfitLoss | | epsBasic | EPS (Basic) | USD/shares | EarningsPerShareBasic | | epsDiluted | EPS (Diluted) | USD/shares | EarningsPerShareDiluted | | weightedAverageShsOut | Weighted Average Shares (Basic) | shares | WeightedAverageNumberOfSharesOutstandingBasic | | weightedAverageShsOutDil | Weighted Average Shares (Diluted) | shares | WeightedAverageNumberOfDilutedSharesOutstanding | ## Balance sheet concepts The `metrics` keys served for `balance-sheet`, with the us-gaap tags tried in priority order. Generated from the concept catalogue the ingestion lane uses. | Key | Label | Unit | us-gaap tags (priority order) | |---|---|---|---| | cashAndCashEquivalents | Cash & Cash Equivalents | USD | CashAndCashEquivalentsAtCarryingValue, CashCashEquivalentsRestrictedCashAndRestrictedCashEquivalents | | shortTermInvestments | Short-Term Investments | USD | ShortTermInvestments, MarketableSecuritiesCurrent, AvailableForSaleSecuritiesCurrent | | netReceivables | Receivables (Net) | USD | AccountsReceivableNetCurrent, ReceivablesNetCurrent | | inventory | Inventory | USD | InventoryNet | | totalCurrentAssets | Total Current Assets | USD | AssetsCurrent | | propertyPlantEquipmentNet | Property, Plant & Equipment (Net) | USD | PropertyPlantAndEquipmentNet | | goodwill | Goodwill | USD | Goodwill | | intangibleAssets | Intangible Assets (ex. Goodwill) | USD | IntangibleAssetsNetExcludingGoodwill, FiniteLivedIntangibleAssetsNet | | totalAssets | Total Assets | USD | Assets | | accountPayables | Accounts Payable | USD | AccountsPayableCurrent, AccountsPayableAndAccruedLiabilitiesCurrent | | totalCurrentLiabilities | Total Current Liabilities | USD | LiabilitiesCurrent | | shortTermDebt | Short-Term Debt | USD | DebtCurrent, ShortTermBorrowings, LongTermDebtCurrent | | longTermDebt | Long-Term Debt | USD | LongTermDebtNoncurrent, LongTermDebt | | totalLiabilities | Total Liabilities | USD | Liabilities | | totalStockholdersEquity | Total Stockholders' Equity | USD | StockholdersEquity, StockholdersEquityIncludingPortionAttributableToNoncontrollingInterest | | retainedEarnings | Retained Earnings | USD | RetainedEarningsAccumulatedDeficit | | commonSharesOutstanding | Common Shares Outstanding | shares | CommonStockSharesOutstanding, CommonStockSharesIssued | ## Cash-flow statement concepts The `metrics` keys served for `cash-flow`, with the us-gaap tags tried in priority order. Generated from the concept catalogue the ingestion lane uses. | Key | Label | Unit | us-gaap tags (priority order) | |---|---|---|---| | operatingCashFlow | Operating Cash Flow | USD | NetCashProvidedByUsedInOperatingActivities, NetCashProvidedByUsedInOperatingActivitiesContinuingOperations | | capitalExpenditure | Capital Expenditure | USD | PaymentsToAcquirePropertyPlantAndEquipment, PaymentsToAcquireProductiveAssets, PaymentsForCapitalImprovements | | depreciationAndAmortization | Depreciation & Amortization | USD | DepreciationDepletionAndAmortization, DepreciationAndAmortization, DepreciationAmortizationAndAccretionNet | | stockBasedCompensation | Stock-Based Compensation | USD | ShareBasedCompensation | | investingCashFlow | Investing Cash Flow | USD | NetCashProvidedByUsedInInvestingActivities, NetCashProvidedByUsedInInvestingActivitiesContinuingOperations | | acquisitionsNet | Acquisitions (Net of Cash) | USD | PaymentsToAcquireBusinessesNetOfCashAcquired | | financingCashFlow | Financing Cash Flow | USD | NetCashProvidedByUsedInFinancingActivities, NetCashProvidedByUsedInFinancingActivitiesContinuingOperations | | dividendsPaid | Dividends Paid | USD | PaymentsOfDividends, PaymentsOfDividendsCommonStock | | commonStockRepurchased | Common Stock Repurchased | USD | PaymentsForRepurchaseOfCommonStock | | debtIssuance | Long-Term Debt Issued | USD | ProceedsFromIssuanceOfLongTermDebt | | debtRepayment | Long-Term Debt Repaid | USD | RepaymentsOfLongTermDebt, RepaymentsOfDebt | | netChangeInCash | Net Change in Cash | USD | CashCashEquivalentsRestrictedCashAndRestrictedCashEquivalentsPeriodIncreaseDecreaseIncludingExchangeRateEffect, CashAndCashEquivalentsPeriodIncreaseDecrease | ## CSV format Empty cells are nulls. A `# status:` comment line appears on preparing/unavailable bodies so a downloaded file is never mistaken for data. **CSV layout** ``` # TGMCharts — AAPL income-statement (annual, SEC EDGAR XBRL) # source: SEC EDGAR XBRL company facts (public domain) # as of: # methodology: # terms: https://tgmcharts.com/terms — attribution required (data by TGMCharts, tgmcharts.com; underlying facts: SEC EDGAR, public domain) fiscalYear,fiscalPeriod,periodEnd,form,filed,revenue,costOfRevenue,grossProfit,… ,FY,,10-K,,,… ``` ## Frequently asked questions ### Can I get SEC financial statements as JSON? Yes. GET /api/v1/statements/{symbol}/{statement} returns the income statement, balance sheet or cash-flow statement as filed with the SEC, from EDGAR XBRL company facts, as JSON (or CSV with ?format=csv), annual or quarterly, up to 30 fiscal years, with the us-gaap tag, accession number and filing date recorded on every value. ### Are the statement values split-adjusted or restated? Values are as filed. For each period the latest-filed fact wins, so a company's own restatement supersedes the original figure. Per-share values are not adjusted for later stock splits. ### Why is a statement value null? The filer tagged no us-gaap fact for that concept and period (or none of the catalogue's tags). Nothing is backfilled from another source and nothing is zero-filled — null is the honest answer. ### Can I redistribute the statement data? The underlying XBRL facts are public-domain SEC data. Use of this API is governed by the API terms: name TGMCharts and link tgmcharts.com where the data is shown, and do not re-serve the API in bulk as a standalone data feed. # MCP server for AI agents > Connect Claude Code or any MCP client to stock fundamentals: seven tools for summaries, metric histories, chart URLs, SEC statements, comparisons and screening. Page: https://tgmcharts.com/developers/docs/mcp · Documentation updated 2026-10-10 · All docs as one file: https://tgmcharts.com/llms-full.txt ## What it is `POST https://tgmcharts.com/api/v1/mcp` is a Model Context Protocol server over streamable HTTP: JSON-RPC 2.0, one JSON response per POST and no server-initiated streams (`GET` and `DELETE` answer `405`, as the streamable-HTTP specification allows). A keyless `initialize` answers an `Mcp-Session-Id` header that only counts the free trial; clients send it back on their own, and a keyed connection gets none. Protocol versions `2025-06-18`, `2025-03-26` and `2024-11-05` are negotiated on `initialize`. Methods: `initialize`, `ping`, `tools/list`, `tools/call`, `prompts/list`, `prompts/get`, `resources/list`, `resources/templates/list`, `resources/read`, and notifications (acknowledged with `202`). Batches are accepted up to 20 messages. Every response is `Cache-Control: no-store`. The tools are thin wrappers over the same builders the REST endpoints use — MCP and REST cannot disagree — and read stored, precomputed data only. ## Connect Discovery (`initialize`, `tools/list`, `ping`) needs no key. `tools/call` is free to try without one: about 40 calls per connection, counted against the `Mcp-Session-Id` the server issues at `initialize`. After that each call returns a result that says how to add a free key — no card — sent as `Authorization: Bearer tgm_live_…`. Your agent can ask for one itself and you approve it with one click ([how](https://tgmcharts.com/developers/docs/authentication-and-limits#agent-keys)), or mint one at [/developers/keys](https://tgmcharts.com/developers/keys). One step per client: - **Claude (claude.ai and the desktop app):** Open **Customize > Connectors** (on Team and Enterprise plans an Owner adds it under **Organization settings > Connectors**). Click **Add custom connector**, name it TGMCharts and enter `https://tgmcharts.com/api/v1/mcp`. For authentication choose **Sign in when needed** (keep the default OAuth client), then **Add**. Every plan can add one, the Free plan one custom connector. No key needed: the free trial runs at once, and when it ends Claude asks you to sign in to TGMCharts once with a free account. - **ChatGPT:** Turn on **Developer mode** in ChatGPT's settings, under Apps & Connectors (the menu names and the plans that have it vary). Create a connector with the URL `https://tgmcharts.com/api/v1/mcp` and **OAuth** authentication, then sign in to TGMCharts when asked (a free account). In a chat, pick TGMCharts from the tools menu. No key needed: the connector signs in to your TGMCharts account. - **Cursor:** [Install in Cursor](cursor://anysphere.cursor-deeplink/mcp/install?name=tgmcharts&config=eyJ1cmwiOiJodHRwczovL3RnbWNoYXJ0cy5jb20vYXBpL3YxL21jcCJ9). Click **Install in Cursor** and confirm, or add the entry below to `~/.cursor/mcp.json`. With a key: add `"headers": { "Authorization": "Bearer tgm_live_YOUR_KEY" }` to the entry. - **VS Code:** [Install in VS Code](vscode:mcp/install?%7B%22name%22%3A%22tgmcharts%22%2C%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Ftgmcharts.com%2Fapi%2Fv1%2Fmcp%22%7D). Click **Install in VS Code** and confirm, or save the config file as `.vscode/mcp.json`: VS Code asks for the key once and stores it. The install link sets up the trial; the config file asks for the key once. - **Claude Code:** Run the command below in a terminal. With a key: `claude mcp remove tgmcharts`, then add it again with `--header "Authorization: Bearer tgm_live_YOUR_KEY"`. **Cursor · ~/.cursor/mcp.json** ``` { "mcpServers": { "tgmcharts": { "url": "https://tgmcharts.com/api/v1/mcp" } } } ``` **VS Code · .vscode/mcp.json** ``` { "inputs": [ { "type": "promptString", "id": "tgmcharts-key", "description": "TGMCharts API key", "password": true } ], "servers": { "tgmcharts": { "type": "http", "url": "https://tgmcharts.com/api/v1/mcp", "headers": { "Authorization": "Bearer ${input:tgmcharts-key}" } } } } ``` **Claude Code · Terminal** ``` claude mcp add --transport http tgmcharts https://tgmcharts.com/api/v1/mcp ``` **Claude Code · with a key** ``` claude mcp add --transport http tgmcharts https://tgmcharts.com/api/v1/mcp \ --header "Authorization: Bearer tgm_live_YOUR_KEY" ``` **.mcp.json (project scope)** ``` { "mcpServers": { "tgmcharts": { "type": "http", "url": "https://tgmcharts.com/api/v1/mcp", "headers": { "Authorization": "Bearer tgm_live_YOUR_KEY" } } } } ``` **Raw JSON-RPC · list the tools (no key)** ``` curl -s https://tgmcharts.com/api/v1/mcp \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' ``` ## Sign in from an AI app (OAuth) The MCP server is also an OAuth 2.1 resource server with its own authorization server, following the MCP authorization specification (2025-11-25), so claude.ai, ChatGPT, Claude Code, Cursor and VS Code can sign a person in instead of asking for a key. Redirect URIs may be https, http to this computer (any port), or a native app's own scheme in reverse-domain form (Cursor's `cursor://` is accepted too). When the trial ends, or a token is missing, expired or revoked, the server answers `401` with `WWW-Authenticate: Bearer resource_metadata="https://tgmcharts.com/.well-known/oauth-protected-resource/api/v1/mcp", scope="mcp"`; the app then offers the sign-in. Discovery: protected-resource metadata (RFC 9728) at `/.well-known/oauth-protected-resource` and `/.well-known/oauth-protected-resource/api/v1/mcp`; authorization-server metadata (RFC 8414) at `/.well-known/oauth-authorization-server`. Apps identify themselves with a client ID metadata document (an https URL) or register at `POST /api/v1/oauth/register` (RFC 7591, public clients). The person approves at `/oauth/authorize`; PKCE with S256 is required and `resource` must name the MCP server. `POST /api/v1/oauth/token` returns an access token valid for 1 hour at the MCP server only (the REST endpoints take an API key) and a refresh token that changes on every use; presenting a used refresh token again ends the connection, so refresh one request at a time. `POST /api/v1/oauth/revoke` (RFC 7009) disconnects; access ends within a minute. Each connection shows on the person's [keys page](https://tgmcharts.com/developers/keys) as a connected app, counts against the 5-key limit until it is disconnected or goes 60 days unused, is metered on their account like a key, and can be disconnected there. ## The seven tools Results carry the machine shape in `structuredContent` and the same JSON serialized in `content[0].text`. Honest states — symbol not covered, a metric outside the tier, `compare` on a line chart — come back as readable text with `isError: true`; argument-schema violations are JSON-RPC `-32602` errors. Every tool is annotated read-only, non-destructive and idempotent, and `tools/list` carries an `outputSchema` for each one, so a client can validate `structuredContent`. The schemas are open: v1 grows by adding fields, never by renaming or removing them. Short answers: pass `format: "markdown"` to `get_stock_summary`, `list_metrics`, `get_metric_series`, `get_financial_statement`, `compare_stocks` or `screen_stocks` and `content[0].text` becomes a compact table instead of the JSON — fewer tokens for a model to read. `structuredContent` is the full JSON either way, and a gap still reads `n/a`, never zero. | Tool | Purpose | Inputs (required in bold) | Notes | |---|---|---|---| | get_stock_summary | Compact fundamentals summary for one ticker — the same body as GET /api/v1/summary. | **symbol** — string: Ticker symbol, e.g. AAPL
format — enum: json \| markdown: markdown: a compact table in the text instead of JSON (default json) | Null values are honest gaps or sector-inappropriate metrics — never zeros. Unknown symbols return an isError result with the onboarding hint. | | list_metrics | The metric catalogue: slug, label, description, unit, basis, and whether each metric is a JSON series and/or a chart render. | format — enum: json \| markdown: markdown: a compact table in the text instead of JSON (default json) | Mirrors the x-tgmcharts-metrics catalogue in the OpenAPI document. | | get_metric_series | Historical series for a series-tier metric, even-time downsampled to stay token-frugal. | **symbol** — string: Ticker symbol, e.g. KO
**metric** — enum (series-tier slugs): One of the series-tier slugs on the series page
years — integer 2–20: Trailing window (default: full stored history)
max_points — integer 10–500: Downsample cap (default 120)
format — enum: json \| markdown: markdown: a compact table in the text instead of JSON (default json) | points: null = intentionally withheld (sector-inappropriate, message included); [] = no stored history. Full density lives at GET /api/v1/series/{symbol}/{metric}. | | get_chart | The canonical PNG chart URL for a chart-tier metric — a resource_link the agent can embed or fetch. | **symbol** — string: Ticker symbol, e.g. AAPL
**metric** — enum (chart-tier slugs): One of the chart-tier slugs on the charts page
years — integer 2–20: Trailing window
compare — string: Second ticker for grouped comparison bars (bar metrics only) | Returns a URL, never inline pixels. compare is refused on line metrics and when it equals symbol. | | get_financial_statement | Raw as-filed statement rows (income statement, balance sheet, or cash flow) from SEC EDGAR XBRL company facts. | **symbol** — string: Ticker symbol, e.g. AAPL
**statement** — enum: income-statement \| balance-sheet \| cash-flow: Which statement
period — enum: annual \| quarterly: Default annual
years — integer 1–10: Trailing fiscal years of rows (default 5; quarterly serves 4×years)
include_provenance — boolean: Per-value us-gaap tag, accession and filing date (default false)
format — enum: json \| markdown: markdown: a compact table in the text instead of JSON (default json) | Token-frugal by default (5 years, no provenance, concept catalogue trimmed to key/label/unit). Full depth (30 years, CSV) lives at GET /api/v1/statements. | | compare_stocks | Side-by-side headline fundamentals for 2–4 tickers: market cap, close, P/E, P/S, margins, ROE, dividend yield, 5-year revenue and EPS CAGRs. | **symbols** — string[] (2–4): Two to four ticker symbols
format — enum: json \| markdown: markdown: a compact table in the text instead of JSON (default json) | Uncovered symbols are reported with covered: false, never dropped silently. peRatio is null for a fund or while the company's category is being prepared, and grossMarginPercent is null for banks, insurers, mortgage REITs and funds (no cost of goods sold), the same as in get_stock_summary. | | screen_stocks | Filter and rank the covered universe on fundamental fields. | filters — array (≤ 5) of { field, operator, value }: operator ∈ gt, gte, lt, lte, eq, neq; field ∈ the screener field list below
sortBy — enum (screener field): Default marketCap
sortOrder — enum: asc \| desc: Default desc
limit — integer 1–25: Rows to return (default 10)
includeEtfs — boolean: Include ETFs (default false)
format — enum: json \| markdown: markdown: a compact table in the text instead of JSON (default json) | At most 25 rows — the MCP tier's cap; the full screener is at /screener. | ## Ready prompts and the metric dictionary `prompts/list` offers 3 task templates a client can show its user: `analyze_company` (symbol), `compare_companies` (symbol_a, symbol_b), `dividend_safety` (symbol). `prompts/get` returns the user message, which tells the model which tools to call and to report a gap as unavailable rather than estimate it. `resources/read` with `tgmcharts://metrics` returns the metric dictionary: every slug with its label, unit, sampling basis, methodology and whether it is a JSON series or a chart render. `tgmcharts://metrics/{slug}` returns one entry. It is built from the same registry as `list_metrics` and the OpenAPI catalog. Prompts and resources are static: free, keyless and outside the trial count. **Raw JSON-RPC · read the metric dictionary (no key)** ``` curl -s https://tgmcharts.com/api/v1/mcp \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","id":1,"method":"resources/read","params":{"uri":"tgmcharts://metrics"}}' ``` ## Screener fields `screen_stocks` filters and sorts on: symbol, name, sector, marketCap, peRatio, dividendYield, consecutiveYears, netProfitMargin, grossMargin, revenueGrowth, debtToEquity, priceChange1Y, percentFrom52WeekHigh, percentFrom52WeekLow, revenueCagr5y, netIncomeCagr5y, epsCagr5y, fcfCagr5y, dividendsCagr5y. ## A keyed tools/call Each `tools/call` in the body is metered at 2 units against the key's tier quota; keyed responses carry `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Window`. **curl · tools/call with a key** ``` curl -s https://tgmcharts.com/api/v1/mcp \ -H "Content-Type: application/json" \ -H "Authorization: Bearer tgm_live_YOUR_KEY" \ -d '{"jsonrpc": "2.0","id": 1,"method": "tools/call","params": {"name": "get_metric_series","arguments": { "symbol": "KO", "metric": "pe-ratio", "years": 10, "max_points": 60 }}}' ``` **Request body** ``` { "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "get_metric_series", "arguments": { "symbol": "KO", "metric": "pe-ratio", "years": 10, "max_points": 60 } } } ``` **Result shape** ``` { "jsonrpc": "2.0", "id": 1, "result": { "content": [ { "type": "text", "text": "" } ], "structuredContent": { …series body…, "points": [ … ≤ max_points … ], "downsampledTo": integer | null }, "isError": false // true + a readable text explanation for honest states (symbol not covered, non-series metric) } } ``` ## The trial, 401 and 429 A keyless `tools/call` runs under the trial: 40 units per connection, 400 per hour per network, and a cap per server. A call costs 1 unit; `compare_stocks` costs 1 per symbol and `screen_stocks` 5. Each trial result carries the units left in `_meta["tgmcharts/trial"]`, and once 10 or fewer are left each result adds a short notice. When the trial refuses a call (used up on the connection, or its per-network or per-server limit reached) the response answers HTTP `401` with `WWW-Authenticate: Bearer resource_metadata=…`, the MCP sign-in challenge: Claude, ChatGPT, Cursor and VS Code then offer their user the TGMCharts sign-in (a free account). The body still carries the tool result, with `isError: true` and the steps to a free key, for clients that show it. A malformed, unknown or revoked key answers `401` with `{ "error": "Invalid API key", … }` and a `WWW-Authenticate` challenge carrying `error="invalid_token"`, which prompts a signed-in app to sign in again. An exhausted quota answers `429` with `Retry-After` — the same body as the REST endpoints, shown on [authentication and limits](https://tgmcharts.com/developers/docs/authentication-and-limits). **401 body — tools/call after the trial is used up** ``` { "jsonrpc": "2.0", "id": 7, "result": { "content": [ { "type": "text", "text": "This connection has used its 40 free trial units. To keep going, sign in: your AI app (claude.ai, ChatGPT, Claude Code, Cursor, VS Code and others) offers a TGMCharts sign-in now; approve it once with a free account (no card) and the app connects with it. Or get a free API key (1,000 units a day, no card). An agent can ask for a key itself: POST https://tgmcharts.com/api/v1/keys/device (optionally with client_name), show the person the returned verification_uri_complete link and user_code, then POST grant_type=urn:ietf:params:oauth:grant-type:device_code and the device_code to https://tgmcharts.com/api/v1/keys/device/token every 5 seconds until it returns api_key. Or the person opens https://tgmcharts.com/developers/keys, signs in and creates a key. Then reconnect with the header Authorization: Bearer tgm_live_… (Claude Code: claude mcp add --transport http tgmcharts https://tgmcharts.com/api/v1/mcp --header \"Authorization: Bearer tgm_live_…\"). The REST endpoints (https://tgmcharts.com/api/v1/openapi.json) need no key at all." } ], "isError": true, "_meta": { "tgmcharts/trial": { "exhausted": "session", "limit": 40, "keyUrl": "https://tgmcharts.com/developers/keys" } } } } ``` ## Not using MCP? Frameworks that build tools from an OpenAPI document can use [/api/v1/openapi.json](https://tgmcharts.com/api/v1/openapi.json) — every metric slug is enumerated in the path parameters, and the `x-tgmcharts-metrics` extension carries the full catalogue in one fetch. A worked example is in the [quickstarts](https://tgmcharts.com/developers/docs/quickstarts). ## Frequently asked questions ### Is there an MCP server for stock fundamentals? Yes — POST https://tgmcharts.com/api/v1/mcp is a streamable-HTTP Model Context Protocol server with seven read-only tools: get_stock_summary, list_metrics, get_metric_series, get_chart, get_financial_statement, compare_stocks and screen_stocks, covering about 4,000 US-listed stocks and ETFs. Add it to Claude Code with: claude mcp add --transport http tgmcharts https://tgmcharts.com/api/v1/mcp ### Does the MCP server need an API key? Not to try it. Discovery (initialize, tools/list, ping) never does, and the first 40 or so tool calls on a connection run without one. After that, add a free key (no card): mint one at tgmcharts.com/developers/keys and send it as Authorization: Bearer tgm_live_…; each keyed tool call is metered at 2 units. ### Which MCP clients can connect? Any client that speaks MCP over streamable HTTP — Claude Code (claude mcp add --transport http), Claude Desktop, and other clients that accept an HTTP MCP URL plus an Authorization header. # Authentication, rate limits and pricing > API keys, request units, tier quotas, X-RateLimit headers and the 401/429 bodies, with free and paid tiers, included units, prices and attribution rules. Page: https://tgmcharts.com/developers/docs/authentication-and-limits · Documentation updated 2026-10-10 · All docs as one file: https://tgmcharts.com/llms-full.txt ## Keyless and keyed access - REST reads — summary, series, statements, charts, the OpenAPI document — are keyless and CORS-open on the free tier, governed by edge fair-use rules and the chart render limiter. - MCP `tools/call` responses cannot be edge-cached, so it has a short keyless trial (about 40 calls per connection) and then takes a key. The free tier works there; discovery methods stay keyless. - A key adds exact per-account metering, tier quotas, `X-RateLimit-*` headers, and paid tiers — on every endpoint. A presented key that is malformed, unknown or revoked answers `401`; it is never silently downgraded to anonymous. ## API keys Mint keys in the developer console at [/developers/keys](https://tgmcharts.com/developers/keys) (sign-in required). Keys look like `tgm_live_` followed by 40 hex characters, are shown once at creation, and are stored hashed. An account holds up to 5 active keys; quotas are per account, so rotating or adding keys never multiplies a tier's allowance. Revocations and tier changes take effect within about a minute. Send the key as `Authorization: Bearer tgm_live_…` or as an `x-api-key` header. Keyed responses are `Cache-Control: private, max-age=3600` — they bypass the shared edge cache so accounting is exact. **Bearer header** ``` curl -s -D - https://tgmcharts.com/api/v1/summary/AAPL \ -H "Authorization: Bearer tgm_live_YOUR_KEY" ``` **x-api-key header** ``` curl -s https://tgmcharts.com/api/v1/series/KO/dividend-yield?years=5 \ -H "x-api-key: tgm_live_YOUR_KEY" ``` ## A key for an agent, without a browser An AI agent or script can ask for a free key itself and receive it once its person approves, the way a TV app signs in (the OAuth 2.0 device authorization grant, RFC 8628). No key is pasted by hand. 1. `POST https://tgmcharts.com/api/v1/keys/device`, optionally with `client_name` (shown to the person). The answer has `device_code` (keep it secret), `user_code`, `verification_uri_complete`, `expires_in` (600 seconds) and `interval` (5 seconds). 2. Show the person the link and the code. They sign in at [/connect](https://tgmcharts.com/connect), check that the code matches, and approve or deny. 3. Every 5 seconds, `POST https://tgmcharts.com/api/v1/keys/device/token` with `grant_type=urn:ietf:params:oauth:grant-type:device_code` and the `device_code`. Until approval it answers `400 {"error":"authorization_pending"}` (or `slow_down` if polled faster); then exactly one poll returns `api_key`. `access_denied` means no key was issued: the person declined, the account already has 5 active keys, or it is no longer active (the `error_description` says which); `expired_token` means start again. The key appears on the person's [keys page](https://tgmcharts.com/developers/keys) labelled `agent: `, where it can be revoked like any other. **curl · ask, then poll** ``` curl -s -X POST https://tgmcharts.com/api/v1/keys/device -H "Content-Type: application/json" \ -d '{"client_name":"my-research-agent"}' # → {"device_code":"…","user_code":"BCDF-GHJK","verification_uri_complete":"https://tgmcharts.com/connect?code=BCDF-GHJK", …} curl -s -X POST https://tgmcharts.com/api/v1/keys/device/token \ -d grant_type=urn:ietf:params:oauth:grant-type:device_code -d device_code=DEVICE_CODE # → 400 {"error":"authorization_pending"} until approved, then {"api_key":"tgm_live_…", …} ``` ## Request units Quotas are counted in request units, weighted by what a request costs to serve. | Request | Units | |---|---| | JSON call — summary, series, statements (JSON or CSV) | 1 | | Chart render — one PNG | 5 | | MCP tools/call — per call in the body | 2 | ## Tiers and pricing Prices are monthly list prices in US dollars. Upgrades are started from the developer console at [/developers/keys](https://tgmcharts.com/developers/keys); if checkout is not yet open for your account, the console says so and the [contact page](https://tgmcharts.com/contact) waitlist (mention "API waitlist") gets you in first. | Tier | Price | Included request-units | Window | Over the cap | |---|---|---|---|---| | Free | $0 | 1,000 | per day | 429 until the day resets | | Builder | $19/mo | 100,000 | per month | 429 until the month resets | | Pro | $49/mo | 1,000,000 | per month | 429 until the month resets | | Scale | $199/mo | 10,000,000 | per month | metered overage: $0.10 per 1,000 units | - Free: 1,000 units per day with or without a key, attribution required, chart renders carry the TGMCharts frame; commercial use at this volume is allowed under the [API terms](https://tgmcharts.com/terms). - Keyless free use is governed by edge fair-use limits rather than exact metering; a free key gives you exact accounting and headers. - Scale is the metered tier: its cap is soft, and units past 10,000,000 per month are billed at $0.10 per 1,000 units rather than refused. ## Rate-limit headers | Header | Meaning | |---|---| | X-RateLimit-Limit | Units included in the account's window. | | X-RateLimit-Remaining | Approximate units left in the window after this request (exact within about a minute across instances). | | X-RateLimit-Window | `day` (free) or `month` (paid). | | Retry-After | On `429` only: seconds until the window resets (keyed), or `60` for the keyless chart render limit. | ## 401 and 429 bodies Error bodies are JSON, `Cache-Control: no-store`, CORS-open. The `upgradeUrl` and `docs` fields point at the console and this page. **401 — invalid key** ``` { "error": "Invalid API key", "reason": "Unknown API key.", "docs": "https://tgmcharts.com/developers/docs/authentication-and-limits" } ``` **429 — keyed quota exhausted (Retry-After = seconds to window reset)** ``` { "error": "free tier daily quota reached (1000 units). Upgrade at https://tgmcharts.com/developers/keys or retry after the window resets.", "tier": "free", "upgradeUrl": "https://tgmcharts.com/developers/keys", "docs": "https://tgmcharts.com/developers/docs/authentication-and-limits" } ``` **429 — keyless chart render limit (Retry-After: 60)** ``` { "error": "Render rate limit reached — cached chart URLs are unlimited; new renders are capped per minute. API keys lift this to tier quotas: https://tgmcharts.com/developers/keys", "upgradeUrl": "https://tgmcharts.com/developers/keys", "docs": "https://tgmcharts.com/developers/docs/authentication-and-limits" } ``` **200 — MCP tools/call after the keyless trial is used up** ``` { "jsonrpc": "2.0", "id": 7, "result": { "content": [ { "type": "text", "text": "This connection has used its 40 free trial units. To keep going, sign in: your AI app (claude.ai, ChatGPT, Claude Code, Cursor, VS Code and others) offers a TGMCharts sign-in now; approve it once with a free account (no card) and the app connects with it. Or get a free API key (1,000 units a day, no card). An agent can ask for a key itself: POST https://tgmcharts.com/api/v1/keys/device (optionally with client_name), show the person the returned verification_uri_complete link and user_code, then POST grant_type=urn:ietf:params:oauth:grant-type:device_code and the device_code to https://tgmcharts.com/api/v1/keys/device/token every 5 seconds until it returns api_key. Or the person opens https://tgmcharts.com/developers/keys, signs in and creates a key. Then reconnect with the header Authorization: Bearer tgm_live_… (Claude Code: claude mcp add --transport http tgmcharts https://tgmcharts.com/api/v1/mcp --header \"Authorization: Bearer tgm_live_…\"). The REST endpoints (https://tgmcharts.com/api/v1/openapi.json) need no key at all." } ], "isError": true, "_meta": { "tgmcharts/trial": { "exhausted": "session", "limit": 40, "keyUrl": "https://tgmcharts.com/developers/keys" } } } } ``` ## Attribution and use - Name TGMCharts as the data source and link to tgmcharts.com wherever API data or charts are displayed ("data by TGMCharts"). Chart images carry the attribution in the frame; do not remove, obscure or crop it. - Do not redistribute or resell API data in bulk or as a standalone dataset or feed, and do not circumvent limits or access controls. Full text: [Terms §19, API Terms](https://tgmcharts.com/terms). - Please cache: data changes at most daily, and every endpoint sends cache headers that do this for you. ## Frequently asked questions ### Do I need an API key to use the TGMCharts API? Not for the REST endpoints — summary, series, statements, charts and the OpenAPI document are keyless and CORS-open on the free tier with attribution. MCP tool calls are free to try without a key (about 40 per connection), then take a free key. Keys add exact metering, per-account quotas and X-RateLimit headers on every endpoint. ### What happens when I exceed my quota? A keyed request past a hard cap answers 429 with Retry-After set to the seconds until the window resets, plus upgradeUrl and docs links; no usage is recorded for the refused request. The Scale tier's cap is soft: overage is metered and billed instead of refused. Keyless chart renders past 30 new renders per minute answer 429 with Retry-After: 60. ### How much does the API cost? The free tier is $0 with 1,000 request-units per day. Paid tiers: Builder $19/mo for 100,000 units per month, Pro $49/mo for 1,000,000 units per month, Scale $199/mo for 10,000,000 units per month. A JSON call is 1 unit, a chart render 5, an MCP tool call 2. # Data quality and lineage > Where each API value comes from: valuation series precomputed daily from licensed market data, statements from SEC EDGAR XBRL as filed. Null vs zero, freshness. Page: https://tgmcharts.com/developers/docs/data-quality · Documentation updated 2026-10-10 · All docs as one file: https://tgmcharts.com/llms-full.txt ## Two lineages - TGMCharts-computed series — the daily valuation and yield lines, rolling TTM flows, quarterly margins, ROIC and total return — are computed by TGMCharts from licensed end-of-day market data and reported financial statements, precomputed daily after the US close, and stored. The summary endpoint's scalars come from the same daily precompute. Every request reads the stored result; no request ever waits on, or varies with, a live vendor call. - Statements and the EDGAR-lane metrics (revenue, net-income, capex, buybacks, stock-based-comp, r-and-d, revenue-quarterly, net-income-quarterly) come from SEC EDGAR XBRL company facts — public domain, as filed, latest-filed per period, with the winning us-gaap tag, accession number and filing date recorded on every value. The statements endpoint reads this lineage exclusively; nothing is backfilled from the market-data lineage. - Chart renders are derived works drawn from the site's stored series. For the EDGAR-lane metrics a chart can therefore differ from the JSON series in restatement vintage; the JSON is the as-filed record. ## null versus 0 - `null` — not stored, not filed, not covered by the window, or intentionally withheld because the metric is not meaningful for the company type. The payload says which: `applicability` on summary/series, `status`/`note` on statements. - `0` — a stored or filed zero. Nothing is zero-filled to make a table look complete, and no value is estimated or interpolated. - `points: []` and `rows: []` — covered, but nothing stored for that metric or statement; a `note` explains. - `status: "preparing"` — covered by the site, SEC ingestion pending (transient, short cache). `status: "unavailable"` — a stable terminal state with a `reason` (ETF/trust, IFRS or non-USD filer). ## Methodology on every series Each series response carries the computation note of its slug. The distinct notes, generated from the registry: - `pe-ratio`, `ps-ratio`, `pb-ratio`, `pfcf-ratio`, `pocf-ratio`, `ev-ebitda`, `ev-ebit`, `ev-sales`, `ev-fcf`, `ev-assets`: Daily valuation history computed by TGMCharts using supplied filing versions, eligible from the trading session after their publication day. Market-cap and enterprise-value histories use statement-period weighted-share estimates; current quote-based valuations have a separate basis. Missing inputs and undelivered historical filing versions cannot be reconstructed. - `earnings-yield`, `fcf-yield`, `ebitda-yield`, `ocf-yield`: Daily inverse-multiple history computed from supplied filing versions, eligible after their publication day. Capitalization-based yields use statement-period weighted-share estimates. Current quote-based yields are calculated separately; unavailable inputs remain gaps. - `dividend-yield`: Computed by TGMCharts from the dividend event history: dividends are summed per calendar year and divided by the close sampled every 21st trading day; a year with no payments yet uses the prior year's total. Points exist only where both a price and a positive annual dividend are known. - `total-return`: Total-return index computed by TGMCharts from daily closes. Each dividend buys more shares at the first close on or after its ex-dividend date. The value is an index level, not a dollar amount (the unit field reads usd): it is 100 at the first close of the stock's full history, not at the start of a `years` window, so only ratios between points are meaningful (end / start - 1 is the return). A history longer than 1,000 closes is thinned to every n-th close (n = closes / 1,000, rounded up) plus the latest one, so points can be several trading days apart. - `roic`: TGMCharts in-house ROIC from annual statements: after-tax operating profit over invested capital (total assets less non-interest-bearing current liabilities), one value per fiscal year; sector-gated where the definition is not meaningful. - `revenue-ttm`, `net-income-ttm`, `fcf-ttm`, `ebitda-ttm`, `capex-ttm`, `buybacks-ttm`, `sbc-ttm`, `rd-ttm`: Rolling four-quarter sum computed by TGMCharts from as-reported quarters; a point exists only when four contiguous quarters are available. Outflow metrics store the absolute net four-quarter sum. - `gross-margin-quarterly`, `operating-margin-quarterly`, `net-margin-quarterly`: Computed by TGMCharts per fiscal quarter from statement line items (profit measure over revenue); sign preserved for loss quarters. - `revenue`, `net-income`, `capex`, `buybacks`, `stock-based-comp`, `r-and-d`: Annual fiscal-year values as filed with the SEC (XBRL company facts, public domain), selected latest-filed per period from the company's own filings; missing periods are honest gaps, never zero-filled or vendor-backfilled. Full per-value provenance (us-gaap tag + accession) at /api/v1/statements. Chart renders of this metric draw from the site's precomputed statement history and can differ in restatement vintage. - `eps`, `free-cash-flow`, `gross-margin`, `operating-margin`, `profit-margin`, `roe`, `roa`: Annual fiscal-year values from company financial statements (vendor-sourced). Available as chart renders; JSON egress arrives as the EDGAR-sourced fundamentals lane extends to this metric. - `ebitda`: Annual clean-EBITDA series computed by TGMCharts (operating income plus depreciation & amortization — never the vendor's derived EBITDA field). - `revenue-quarterly`, `net-income-quarterly`: Single-quarter values as filed with the SEC (XBRL company facts, public domain), latest-filed per period. Quarters not filed discretely (typically Q4) are derived only by differencing two same-tag, same-fiscal-year filed facts and are withheld when a filing restates history — honest gaps, never plugs. Full per-value provenance at /api/v1/statements. Chart renders of this metric draw from the site's precomputed statement history and can differ in restatement vintage. - `eps-quarterly`, `fcf-quarterly`: Single-quarter as-reported values from company financial statements (vendor-sourced). Available as chart renders; JSON egress arrives as the EDGAR-sourced fundamentals lane extends to this metric. ## Restatements and derived quarters - On the EDGAR lane the latest filing wins per period, so a company's restated figure supersedes the original and the `provenance` block names the filing it came from. - Quarters that filers do not tag discretely are derived only by differencing two same-tag, same-fiscal-year facts, are marked `derived: "ytd-differencing"` with both source accessions, and are withheld when a surrounding filing restates prior periods. - Per-share values are as filed and not split-adjusted; share counts and per-share values are never derived. ## Freshness Every covered symbol is recomputed daily after the US market close, and every payload carries its as-of date (`asOf.dataUpdatedAt` on summaries, `asOf` on series and statements, the footer of every chart). The public probe [/api/health/freshness](https://tgmcharts.com/api/health/freshness) reports the oldest covered symbol's age against a 26-hour SLA, so staleness is never silent. `severity` grades it: `warning` names a few symbols past the SLA (`staleSymbols`) while the rest refresh on time, and `outage` (many symbols late, as when the daily refresh stalls) also answers `503`. **GET /api/health/freshness — shape** ``` { "ok": boolean, "slaHours": 26, "totalCovered": integer, "excluded": integer, // stubs with no real quote, excluded from the SLO and reported "oldestSymbol": string, "oldestAgeHours": number, "countOverSla": integer, "newestAgeHours": number | null, // the most recently refreshed symbol "severity": "ok" | "warning" | "outage", "severityReason": string, "staleSymbols": string[], // oldest first, at most 10 "checkedAt": ISO date-time } ``` ## Coverage - About 4,000 US-listed stocks and ETFs. A real ticker that is not yet covered is added when a person asks for it on its stock page (one click, about two minutes); fetching the page does not add it. Until then the API answers `404` with that hint. - ETFs and trusts have summaries, price-based series and charts, but no SEC statements (`status: "unavailable"`). Filers reporting under IFRS or in a non-USD currency are likewise `unavailable` on the statements lane. - Foreign filers with USD-converted statements carry `reportedCurrency` on the summary so the conversion is visible. ## Frequently asked questions ### Does the API ever return estimated, interpolated or backfilled values? Historical capitalization-based ratios use estimates from statement-period weighted-average shares. Current ratios use a separately dated quote and retained financial inputs. Historical calculations use only the filing versions supplied to the computation; missing older versions cannot be reconstructed. Missing inputs stay null, and empty histories stay empty. ### How do I tell a missing value from a zero? A missing value is null and comes with an explanation — applicability on summaries and series, status and note on statements. A zero is a stored or filed zero. The API never zero-fills. ### How fresh is the data? Refreshed daily after the US market close; every payload carries its as-of date. The public probe at /api/health/freshness reports the oldest covered symbol's age against a 26-hour SLA; a few late symbols are a named warning, and an outage (many late, as when the refresh stalls) answers 503. # Quickstarts > Copy-paste examples for the stock fundamentals API: curl, Python requests and pandas, Node fetch, a Claude Code MCP walkthrough, an OpenAI tool from OpenAPI. Page: https://tgmcharts.com/developers/docs/quickstarts · Documentation updated 2026-10-10 · All docs as one file: https://tgmcharts.com/llms-full.txt ## curl **Terminal** ``` # Per-stock summary (JSON, keyless) curl -s https://tgmcharts.com/api/v1/summary/AAPL # 10 years of daily P/E as CSV curl -s "https://tgmcharts.com/api/v1/series/KO/pe-ratio?years=10&format=csv" -o ko-pe-ratio.csv # Five annual income statements as filed with the SEC curl -s "https://tgmcharts.com/api/v1/statements/AAPL/income-statement?period=annual&years=5" # A chart PNG curl -s -o aapl-revenue.png https://tgmcharts.com/api/v1/charts/AAPL/revenue # With a key: metered, X-RateLimit-* headers on the response curl -s -D - -o /dev/null https://tgmcharts.com/api/v1/summary/AAPL \ -H "Authorization: Bearer tgm_live_YOUR_KEY" ``` ## Python `requests` for JSON, `pandas` straight from the CSV. Handle the honest states — `points` can be `null`, and a statement can carry a `status` instead of rows. **Python 3 · requests + pandas** ``` import requests import pandas as pd BASE = "https://tgmcharts.com/api/v1" HEADERS = {"User-Agent": "my-app/1.0 (data by TGMCharts)"} # Summary summary = requests.get(f"{BASE}/summary/AAPL", headers=HEADERS, timeout=30).json() print(summary["name"], summary["valuation"]["peRatio"], summary["asOf"]["dataUpdatedAt"]) # Daily P/E history, 10 years series = requests.get(f"{BASE}/series/KO/pe-ratio", params={"years": 10}, headers=HEADERS, timeout=30).json() if series["points"] is None: print("withheld:", series["applicability"]["message"]) # not meaningful for the company type else: for point in series["points"][-3:]: print(point["date"], point["value"]) # The same series as a DataFrame (the '#' lines are provenance comments) df = pd.read_csv(f"{BASE}/series/KO/pe-ratio?years=10&format=csv", comment="#", parse_dates=["date"]) print(df.tail()) # Annual cash-flow statement as filed with the SEC, with per-value provenance stmt = requests.get(f"{BASE}/statements/AAPL/cash-flow", params={"period": "annual", "years": 5}, headers=HEADERS, timeout=30).json() if stmt.get("status"): # "preparing" or "unavailable" — rows is null print(stmt["status"], stmt.get("note")) else: for row in stmt["rows"]: prov = row["provenance"].get("operatingCashFlow") print(row["fiscalYear"], row["metrics"]["operatingCashFlow"], prov["accn"] if prov else "not filed") ``` ## Node.js **Node 18+ · fetch** ``` const BASE = "https://tgmcharts.com/api/v1"; const summary = await fetch(`${BASE}/summary/AAPL`).then((r) => r.json()); console.log(summary.name, summary.valuation.peRatio, summary.asOf.dataUpdatedAt); // Balance sheet as filed with the SEC (JSON); rows is null while status is set const statement = await fetch(`${BASE}/statements/AAPL/balance-sheet?period=annual&years=3`).then((r) => r.json()); if (statement.status) { console.log(statement.status, statement.note); // "preparing" | "unavailable" } else { for (const row of statement.rows) { console.log(row.fiscalYear, row.metrics.totalAssets, row.provenance.totalAssets?.tag ?? "not filed"); } } // Keyed call: metered, X-RateLimit-* headers on the response const keyed = await fetch(`${BASE}/series/KO/dividend-yield?years=5`, { headers: { Authorization: `Bearer ${process.env.TGMCHARTS_API_KEY}` }, }); console.log(keyed.status, keyed.headers.get("x-ratelimit-remaining")); const series = await keyed.json(); console.log(series.methodology, series.points?.length ?? "withheld"); ``` ## Claude Code and the MCP server Register the server and ask; no key is needed to try it. When the trial ends, add a free key. Claude picks the tool — `compare_stocks` for a side-by-side, `get_metric_series` for a history, `get_chart` for an embeddable PNG URL — and the results carry as-of dates and honest nulls it can cite. Details on the [MCP page](https://tgmcharts.com/developers/docs/mcp). **Terminal** ``` # 1. Register the server (no key needed to try: about 40 tool calls) claude mcp add --transport http tgmcharts https://tgmcharts.com/api/v1/mcp # 2. When the trial ends, mint a free key (sign in, "Create key"): https://tgmcharts.com/developers/keys # and register the server again with it in the Authorization header: claude mcp remove tgmcharts claude mcp add --transport http tgmcharts https://tgmcharts.com/api/v1/mcp \ --header "Authorization: Bearer tgm_live_YOUR_KEY" # In Claude Code, ask, for example: # "Compare KO and PEP on operating margin and dividend yield, # then give me KO's 10-year P/E chart." # -> compare_stocks, then get_chart returns # https://tgmcharts.com/api/v1/charts/KO/pe-ratio?years=10 ``` **Same call over raw JSON-RPC** ``` curl -s https://tgmcharts.com/api/v1/mcp \ -H "Content-Type: application/json" \ -H "Authorization: Bearer tgm_live_YOUR_KEY" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"compare_stocks","arguments":{"symbols":["KO","PEP"]}}}' ``` ## OpenAI tool definition from the OpenAPI document The OpenAPI document enumerates every series slug, so a function tool can be built from it instead of hand-typing the enum. The example defines one tool for the series endpoint and executes the model's call against the API. **Python 3 · openai + requests** ``` import json import requests from openai import OpenAI BASE = "https://tgmcharts.com/api/v1" spec = requests.get(f"{BASE}/openapi.json", timeout=30).json() series_slugs = [m["slug"] for m in spec["x-tgmcharts-metrics"] if m["series"]] tools = [{ "type": "function", "function": { "name": "get_metric_series", "description": spec["paths"]["/api/v1/series/{symbol}/{metric}"]["get"]["summary"], "parameters": { "type": "object", "properties": { "symbol": {"type": "string", "description": "Ticker symbol, e.g. AAPL"}, "metric": {"type": "string", "enum": series_slugs}, "years": {"type": "integer", "minimum": 2, "maximum": 20}, }, "required": ["symbol", "metric"], }, }, }] def get_metric_series(symbol: str, metric: str, years: int | None = None) -> dict: params = {"years": years} if years else {} return requests.get(f"{BASE}/series/{symbol}/{metric}", params=params, timeout=30).json() client = OpenAI() messages = [{"role": "user", "content": "How has KO's P/E ratio moved over the last 10 years?"}] first = client.chat.completions.create(model="gpt-4o", messages=messages, tools=tools) call = first.choices[0].message.tool_calls[0] result = get_metric_series(**json.loads(call.function.arguments)) messages += [ first.choices[0].message, {"role": "tool", "tool_call_id": call.id, "content": json.dumps(result)}, # carries methodology + asOf ] answer = client.chat.completions.create(model="gpt-4o", messages=messages, tools=tools) print(answer.choices[0].message.content) ``` ## Attribution Wherever the data or charts appear, name TGMCharts and link tgmcharts.com — "data by TGMCharts". Chart PNGs carry it in the frame already. Cache responses for at least an hour; the data changes at most daily. See [authentication and limits](https://tgmcharts.com/developers/docs/authentication-and-limits) for keys, quotas and the [API terms](https://tgmcharts.com/terms). Ideally link the page of the data you show, for example `Data by TGMCharts`. Keyless callers: name your program and a contact URL in the `User-Agent` (for example `my-app/1.0 (+https://example.com)`), so we can reach you if something changes. ## Frequently asked questions ### Is there a Python example for the stock fundamentals API? Yes — the quickstart uses requests for the summary, series and statements endpoints and pandas.read_csv with comment="#" for the CSV series. No SDK is needed; every endpoint is plain HTTPS returning JSON, CSV or PNG. ### How do I give an AI agent access to the data? Two ways: connect the MCP server (claude mcp add --transport http tgmcharts https://tgmcharts.com/api/v1/mcp; no key needed to try, then a free key in the Authorization header), or build tool definitions from the OpenAPI document at /api/v1/openapi.json for OpenAI-style function calling. # Connect TGMCharts to Claude > Add TGMCharts to claude.ai or the Claude desktop app as a custom connector: SEC statements, valuation history and screens in chat, free to try. Page: https://tgmcharts.com/developers/docs/connect-claude · Documentation updated 2026-10-10 · All docs as one file: https://tgmcharts.com/llms-full.txt ## Set up in Claude (claude.ai and the desktop app) The server: `https://tgmcharts.com/api/v1/mcp` (streamable HTTP). No key is needed to try: about 40 tool calls per connection. Then a free key, no card: your agent can ask for one and you approve it with one click ([how](https://tgmcharts.com/developers/docs/authentication-and-limits#agent-keys)), or create one at [/developers/keys](https://tgmcharts.com/developers/keys). - Open **Customize > Connectors** (on Team and Enterprise plans an Owner adds it under **Organization settings > Connectors**). - Click **Add custom connector**, name it TGMCharts and enter `https://tgmcharts.com/api/v1/mcp`. - For authentication choose **Sign in when needed** (keep the default OAuth client), then **Add**. Every plan can add one, the Free plan one custom connector. ## Ask your first question Each of these is answered by one tool from stored, daily-refreshed data. A value that is missing or not meaningful for the company comes back empty (null or n/a), never as a made-up zero. | Ask | Tool | |---|---| | Use TGMCharts to summarize Coca-Cola's fundamentals. | get_stock_summary | | How has Microsoft's P/E moved over the last 10 years? | get_metric_series | | Show Apple's annual income statement from its SEC filings. | get_financial_statement | | Compare JPMorgan and Bank of America. | compare_stocks | | Find US stocks yielding over 3% with 25+ years of dividend increases. | screen_stocks | | Chart Coca-Cola's dividend yield over 20 years. | get_chart | ## After the free trial: sign in or add a key No key needed: the free trial runs at once, and when it ends Claude asks you to sign in to TGMCharts once with a free account. When the trial is used up the server asks the app to sign in (MCP OAuth). You sign in to TGMCharts once with a free account; the connection then shows on [your keys page](https://tgmcharts.com/developers/keys), where you can end it at any time. ## If something does not work - **No tools listed:** check the URL is exactly `https://tgmcharts.com/api/v1/mcp` and reconnect. Listing the tools never needs a key. - **A sign-in window or a 401 after some calls:** the free trial on this connection is used up. Sign in, or add a free key. - **A 429:** the key's quota for the period is used. The `Retry-After` header says when it resets ([limits](https://tgmcharts.com/developers/docs/authentication-and-limits)). - **A company is missing:** coverage is the US-listed companies on tgmcharts.com; a ticker we do not cover is reported as not covered, not guessed. ## Frequently asked questions ### Is TGMCharts free to use in Claude? Yes to try: about 40 tool calls per connection with no account. After that a free account (no card) keeps it working, within the free tier's limits. ### Where does the data come from? Financial statements come from SEC EDGAR filings as filed. Valuation ratios, growth rates and other metrics are computed by TGMCharts and refreshed daily. Summaries, metric histories and statements carry their as-of date. # Connect TGMCharts to ChatGPT > Connect ChatGPT to TGMCharts with a custom MCP connector: company summaries, SEC filings and valuation history in chat, signed in with a free account. Page: https://tgmcharts.com/developers/docs/connect-chatgpt · Documentation updated 2026-10-10 · All docs as one file: https://tgmcharts.com/llms-full.txt ## Set up in ChatGPT The server: `https://tgmcharts.com/api/v1/mcp` (streamable HTTP). No key is needed to try: about 40 tool calls per connection. Then a free key, no card: your agent can ask for one and you approve it with one click ([how](https://tgmcharts.com/developers/docs/authentication-and-limits#agent-keys)), or create one at [/developers/keys](https://tgmcharts.com/developers/keys). - Turn on **Developer mode** in ChatGPT's settings, under Apps & Connectors (the menu names and the plans that have it vary). - Create a connector with the URL `https://tgmcharts.com/api/v1/mcp` and **OAuth** authentication, then sign in to TGMCharts when asked (a free account). - In a chat, pick TGMCharts from the tools menu. ## Ask your first question Each of these is answered by one tool from stored, daily-refreshed data. A value that is missing or not meaningful for the company comes back empty (null or n/a), never as a made-up zero. | Ask | Tool | |---|---| | Use TGMCharts to summarize Coca-Cola's fundamentals. | get_stock_summary | | How has Microsoft's P/E moved over the last 10 years? | get_metric_series | | Show Apple's annual income statement from its SEC filings. | get_financial_statement | | Compare JPMorgan and Bank of America. | compare_stocks | | Find US stocks yielding over 3% with 25+ years of dividend increases. | screen_stocks | | Chart Coca-Cola's dividend yield over 20 years. | get_chart | ## Signing in No key needed: the connector signs in to your TGMCharts account. ChatGPT signs in when you create the connector (MCP OAuth): one free TGMCharts account. The connection then shows on [your keys page](https://tgmcharts.com/developers/keys), where you can end it at any time. ## If something does not work - **No tools listed:** check the URL is exactly `https://tgmcharts.com/api/v1/mcp` and reconnect. Listing the tools never needs a key. - **A sign-in window or a 401 after some calls:** the free trial on this connection is used up. Sign in, or add a free key. - **A 429:** the key's quota for the period is used. The `Retry-After` header says when it resets ([limits](https://tgmcharts.com/developers/docs/authentication-and-limits)). - **A company is missing:** coverage is the US-listed companies on tgmcharts.com; a ticker we do not cover is reported as not covered, not guessed. ## Frequently asked questions ### Is TGMCharts free to use in ChatGPT? Yes to try: about 40 tool calls per connection with no account. After that a free account (no card) keeps it working, within the free tier's limits. ### Where does the data come from? Financial statements come from SEC EDGAR filings as filed. Valuation ratios, growth rates and other metrics are computed by TGMCharts and refreshed daily. Summaries, metric histories and statements carry their as-of date. # Connect TGMCharts to Cursor > Install the TGMCharts MCP server in Cursor with one click: fundamentals, SEC statements and chart URLs for the code and analyses you build. Page: https://tgmcharts.com/developers/docs/connect-cursor · Documentation updated 2026-10-10 · All docs as one file: https://tgmcharts.com/llms-full.txt ## Set up in Cursor [Install in Cursor](cursor://anysphere.cursor-deeplink/mcp/install?name=tgmcharts&config=eyJ1cmwiOiJodHRwczovL3RnbWNoYXJ0cy5jb20vYXBpL3YxL21jcCJ9) — one click, then confirm in Cursor. The server: `https://tgmcharts.com/api/v1/mcp` (streamable HTTP). No key is needed to try: about 40 tool calls per connection. Then a free key, no card: your agent can ask for one and you approve it with one click ([how](https://tgmcharts.com/developers/docs/authentication-and-limits#agent-keys)), or create one at [/developers/keys](https://tgmcharts.com/developers/keys). - Click **Install in Cursor** and confirm, or add the entry below to `~/.cursor/mcp.json`. **~/.cursor/mcp.json** ``` { "mcpServers": { "tgmcharts": { "url": "https://tgmcharts.com/api/v1/mcp" } } } ``` ## Ask your first question Each of these is answered by one tool from stored, daily-refreshed data. A value that is missing or not meaningful for the company comes back empty (null or n/a), never as a made-up zero. | Ask | Tool | |---|---| | Use TGMCharts to summarize Coca-Cola's fundamentals. | get_stock_summary | | How has Microsoft's P/E moved over the last 10 years? | get_metric_series | | Show Apple's annual income statement from its SEC filings. | get_financial_statement | | Compare JPMorgan and Bank of America. | compare_stocks | | Find US stocks yielding over 3% with 25+ years of dividend increases. | screen_stocks | | Chart Coca-Cola's dividend yield over 20 years. | get_chart | ## After the free trial: sign in or add a key With a key: add `"headers": { "Authorization": "Bearer tgm_live_YOUR_KEY" }` to the entry. When the trial is used up the server asks the app to sign in (MCP OAuth). You sign in to TGMCharts once with a free account; the connection then shows on [your keys page](https://tgmcharts.com/developers/keys), where you can end it at any time. ## If something does not work - **No tools listed:** check the URL is exactly `https://tgmcharts.com/api/v1/mcp` and reconnect. Listing the tools never needs a key. - **A sign-in window or a 401 after some calls:** the free trial on this connection is used up. Sign in, or add a free key. - **A 429:** the key's quota for the period is used. The `Retry-After` header says when it resets ([limits](https://tgmcharts.com/developers/docs/authentication-and-limits)). - **A company is missing:** coverage is the US-listed companies on tgmcharts.com; a ticker we do not cover is reported as not covered, not guessed. ## Frequently asked questions ### Is TGMCharts free to use in Cursor? Yes to try: about 40 tool calls per connection with no account. After that a free account (no card) keeps it working, within the free tier's limits. ### Where does the data come from? Financial statements come from SEC EDGAR filings as filed. Valuation ratios, growth rates and other metrics are computed by TGMCharts and refreshed daily. Summaries, metric histories and statements carry their as-of date. # Connect TGMCharts to VS Code > Install the TGMCharts MCP server in VS Code with one click, or a .vscode/mcp.json that asks for the key once: fundamentals for Copilot agent mode. Page: https://tgmcharts.com/developers/docs/connect-vscode · Documentation updated 2026-10-10 · All docs as one file: https://tgmcharts.com/llms-full.txt ## Set up in VS Code [Install in VS Code](vscode:mcp/install?%7B%22name%22%3A%22tgmcharts%22%2C%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Ftgmcharts.com%2Fapi%2Fv1%2Fmcp%22%7D) — one click, then confirm in VS Code. The server: `https://tgmcharts.com/api/v1/mcp` (streamable HTTP). No key is needed to try: about 40 tool calls per connection. Then a free key, no card: your agent can ask for one and you approve it with one click ([how](https://tgmcharts.com/developers/docs/authentication-and-limits#agent-keys)), or create one at [/developers/keys](https://tgmcharts.com/developers/keys). - Click **Install in VS Code** and confirm, or save the config file as `.vscode/mcp.json`: VS Code asks for the key once and stores it. **.vscode/mcp.json** ``` { "inputs": [ { "type": "promptString", "id": "tgmcharts-key", "description": "TGMCharts API key", "password": true } ], "servers": { "tgmcharts": { "type": "http", "url": "https://tgmcharts.com/api/v1/mcp", "headers": { "Authorization": "Bearer ${input:tgmcharts-key}" } } } } ``` ## Ask your first question Each of these is answered by one tool from stored, daily-refreshed data. A value that is missing or not meaningful for the company comes back empty (null or n/a), never as a made-up zero. | Ask | Tool | |---|---| | Use TGMCharts to summarize Coca-Cola's fundamentals. | get_stock_summary | | How has Microsoft's P/E moved over the last 10 years? | get_metric_series | | Show Apple's annual income statement from its SEC filings. | get_financial_statement | | Compare JPMorgan and Bank of America. | compare_stocks | | Find US stocks yielding over 3% with 25+ years of dividend increases. | screen_stocks | | Chart Coca-Cola's dividend yield over 20 years. | get_chart | ## After the free trial: sign in or add a key The install link sets up the trial; the config file asks for the key once. When the trial is used up the server asks the app to sign in (MCP OAuth). You sign in to TGMCharts once with a free account; the connection then shows on [your keys page](https://tgmcharts.com/developers/keys), where you can end it at any time. ## If something does not work - **No tools listed:** check the URL is exactly `https://tgmcharts.com/api/v1/mcp` and reconnect. Listing the tools never needs a key. - **A sign-in window or a 401 after some calls:** the free trial on this connection is used up. Sign in, or add a free key. - **A 429:** the key's quota for the period is used. The `Retry-After` header says when it resets ([limits](https://tgmcharts.com/developers/docs/authentication-and-limits)). - **A company is missing:** coverage is the US-listed companies on tgmcharts.com; a ticker we do not cover is reported as not covered, not guessed. ## Frequently asked questions ### Is TGMCharts free to use in VS Code? Yes to try: about 40 tool calls per connection with no account. After that a free account (no card) keeps it working, within the free tier's limits. ### Where does the data come from? Financial statements come from SEC EDGAR filings as filed. Valuation ratios, growth rates and other metrics are computed by TGMCharts and refreshed daily. Summaries, metric histories and statements carry their as-of date. # Connect TGMCharts to Claude Code > Add TGMCharts to Claude Code with one command: stock fundamentals, SEC statements and chart URLs for research agents and the code you write. Page: https://tgmcharts.com/developers/docs/connect-claude-code · Documentation updated 2026-10-10 · All docs as one file: https://tgmcharts.com/llms-full.txt ## Set up in Claude Code The server: `https://tgmcharts.com/api/v1/mcp` (streamable HTTP). No key is needed to try: about 40 tool calls per connection. Then a free key, no card: your agent can ask for one and you approve it with one click ([how](https://tgmcharts.com/developers/docs/authentication-and-limits#agent-keys)), or create one at [/developers/keys](https://tgmcharts.com/developers/keys). - Run the command below in a terminal. **Terminal** ``` claude mcp add --transport http tgmcharts https://tgmcharts.com/api/v1/mcp ``` ## Ask your first question Each of these is answered by one tool from stored, daily-refreshed data. A value that is missing or not meaningful for the company comes back empty (null or n/a), never as a made-up zero. | Ask | Tool | |---|---| | Use TGMCharts to summarize Coca-Cola's fundamentals. | get_stock_summary | | How has Microsoft's P/E moved over the last 10 years? | get_metric_series | | Show Apple's annual income statement from its SEC filings. | get_financial_statement | | Compare JPMorgan and Bank of America. | compare_stocks | | Find US stocks yielding over 3% with 25+ years of dividend increases. | screen_stocks | | Chart Coca-Cola's dividend yield over 20 years. | get_chart | ## After the free trial: sign in or add a key With a key: `claude mcp remove tgmcharts`, then add it again with `--header "Authorization: Bearer tgm_live_YOUR_KEY"`. When the trial is used up the server asks the app to sign in (MCP OAuth). You sign in to TGMCharts once with a free account; the connection then shows on [your keys page](https://tgmcharts.com/developers/keys), where you can end it at any time. ## If something does not work - **No tools listed:** check the URL is exactly `https://tgmcharts.com/api/v1/mcp` and reconnect. Listing the tools never needs a key. - **A sign-in window or a 401 after some calls:** the free trial on this connection is used up. Sign in, or add a free key. - **A 429:** the key's quota for the period is used. The `Retry-After` header says when it resets ([limits](https://tgmcharts.com/developers/docs/authentication-and-limits)). - **A company is missing:** coverage is the US-listed companies on tgmcharts.com; a ticker we do not cover is reported as not covered, not guessed. ## Frequently asked questions ### Is TGMCharts free to use in Claude Code? Yes to try: about 40 tool calls per connection with no account. After that a free account (no card) keeps it working, within the free tier's limits. ### Where does the data come from? Financial statements come from SEC EDGAR filings as filed. Valuation ratios, growth rates and other metrics are computed by TGMCharts and refreshed daily. Summaries, metric histories and statements carry their as-of date.