Metrics
Get 100 computed ratios, scores, growth rates and volatilities per company, by fiscal year, quarter, trailing twelve months or trading day.
GET /v1/metrics/{ticker} returns financial metrics computed from each company's statements, its closing prices and its share counts: valuation multiples, margins and returns, leverage and liquidity ratios, efficiency ratios, per-share values, dividend ratios, accounting scores, growth rates and realised volatility. The API serves 100 metrics. The Metrics catalogue gives the formula, unit and input fields of each one.
Pass one or more tickers in the path, or issuer ids as GET /v1/metrics?entity_id=1. Each row describes one company for one period.
Rows are at issuer grain. entity_id is the issuer, the company that files the statements, so GOOGL and GOOG both return Alphabet's rows and meta.entity_id_basis reads issuer. See Tickers and entities for how issuer and share-class ids differ across endpoints.
Units:
- Multiples such as
pe_ratio,debt_to_equityandcurrent_ratioare plain ratios (times). - Margins, returns, yields, payout ratios and growth rates are decimal fractions:
0.25means 25%. They are not percentages. market_cap,enterprise_valueandaccrualsare in millions of USD, andmeta.unitsreadsmillions_usd. Amarket_capof4977636.9726is USD 4.98 trillion.- Per-share metrics are in USD per share.
days_inventory,days_payable,days_sales_outstandingandcash_conversion_cycleare in days.- The three volatility metrics are annualised decimal fractions:
0.2165means 21.65% a year. - Scores are unitless.
piotroski_f_scoreis an integer from 0 to 9.
Values are not rounded.
Null, never zero
A metric whose input is unavailable is null, and the row's missing_inputs names the input or the reason. No input is ever replaced by zero.
What each period returns
period selects one of four row types. Every row states its own period_type and basis.
annual(the default): one row per fiscal year. Flow items such asrevenueandnet_incomecover the fiscal year. Balance items such astotal_assetsare taken atperiod_end.basisisannual.quarterly: one row per fiscal quarter. Fourteen metrics, mostly valuation and leverage ratios, read trailing-twelve-month (TTM) flows, and every other metric reads the quarter's own flows. The Metrics catalogue marks the fourteen.basisisquarterly.ttm: one row per company, taken on today's date or onas_of. Flows are summed over the four quarters ending with the latest quarterly statement published on or before that date whose period had ended before that date, and the row is valued at the most recent close on or before it.period_endis the end of the last quarter in the window andpriced_onis the date of the close. When the company has not traded in the days up to that date, for example after a delisting,datais empty.daily: one row per trading day of the requested share class. Each day uses the latest quarterly statement published on or before that day whose period had ended before that day, with flows summed over the trailing twelve months, and that day's close.statement_period_endgives that statement's period end.period_endis the trading date andbasisisttm.
A TTM flow needs four consecutive quarterly statements with the item present in each. Otherwise the metric is null. A trailing EPS is the four quarters' EPS summed; where one of them is null, it is the EPS filed on an annual report, as ttm_eps_basis describes, or null.
Prices and share counts
close is the requested share class's own close, as traded, on the last trading day on or before the row's date. On annual and quarterly rows that date is period_end, on ttm rows it is priced_on, and on daily rows it is the trading date. A close more than 30 days old is not used.
market_cap is the whole company: close times share count for every common share class that traded within 30 days of the date, summed. Where no common class trades, the company's depositary receipts are used instead. meta.market_cap_basis reads issuer_all_share_classes. market_cap is null unless every class in that set has both a close and a share count. A share count recorded as a count of depositary shares rather than the company's own shares is not used: market_cap is then null, named market_cap:<entity_id>:depositary_count.
Per-share metrics divide by the same summed share count, taken on the row's date and consistent with that day's close across splits. shares_as_of and shares_source report the share-count observation used for the requested class. A share count more than 400 days older than the row's date is not used (an observation dated 2024-04-30 prices rows up to 2025-06-04 and is refused from 2025-06-05): the row carries shares_stale: true, and market_cap, every metric built on it and every per-share metric are null.
Point in time
Without as_of, annual and quarterly rows use the current version of each statement, including later restatements. With as_of, each statement is the version filed on or before that date, and periods first filed after it are left out. A daily row appears only from the day the statement behind it was published. See Point-in-time and as-of.
Parameters
tickerstr (path)Required unless entity_id is givenOne ticker, or a comma-separated list: /v1/metrics/AAPL,MSFT. Up to 1 ticker on Free, 100 on Pro, 500 on Max and 5,000 on Redistribution. A share-class ticker such as BRK-B resolves to its issuer. A ticker that names more than one security on the date, such as BRK, returns 409; in a list with other tickers, it is listed in meta.tickers_ambiguous and the others are served.
entity_idint or comma-separated int listOptionalIssuer id or ids in place of a ticker: GET /v1/metrics?entity_id=1. Same per-plan cap as ticker. Cannot be combined with a ticker in the path. A share-class (security) id is not resolved: on its own it returns 404, and in a list it is reported in meta.entity_ids_unresolved. Get issuer ids from Resolve or Search.
periodstrDefault: "annual"annual, quarterly, ttm or daily, lower case. See "What each period returns".
period_typestrDefault: "annual"Alias of period, with the same values. When both are given, period is used. The Python client and the MCP server use this name.
startstr (YYYY-MM-DD)Default: none. Free: one year before todayannual and quarterly: earliest period_end. daily: earliest trading date; when absent, the window is the 90 days ending on end, or on today. Does not move a ttm row. On Free, an absent start or one earlier than one year before today (UTC) is replaced by that date, and the date is returned in the X-Data-Floor header. When the request's start or end is earlier than that date, warnings also says so.
endstr (YYYY-MM-DD)Default: noneannual and quarterly: latest period_end. daily: latest trading date. Does not move a ttm row. Not limited on any plan. start and end also date the ticker's resolution (see "Recycled tickers").
as_ofstr (YYYY-MM-DD)Default: noneKnowledge date. Statements are the versions filed on or before this date, and periods first filed after it are left out. On ttm, the snapshot is valued at the most recent close on or before this date. Returned as meta.as_of.
growth_basisstrDefault: "yoy"Comparison period for growth metrics and peg_ratio on quarterly rows: yoy (the quarter ending a year earlier), qoq (the quarter ending a quarter earlier) or ttm_yoy (TTM flows against the TTM flows ending a year earlier). No effect on annual, ttm or daily rows. See "Parameters by period" for how the comparison period is found.
fieldsstr (comma-separated)Default: all 100 served metricsMetric names, category names (valuation, profitability, leverage, liquidity, efficiency, per_share, dividends, scores, growth, volatility), or all. Metric keys appear in each row in the order you list them. Unknown names are ignored with a warnings entry; if no name is valid the request fails with 400. Row fields such as ticker and period_end are always returned and are ignored in fields.
limitintDefault: 20Rows per page, 1 to 100 on every plan. A larger whole number, up to nine digits, is treated as 100; 0, a negative or a non-numeric value returns 400.
viewstrDefault: "latest"Only latest; any other non-empty value returns 400. Use as_of for the figures known on a date.
versionstrDefault: "restated"Only restated; any other non-empty value returns 400.
cursorstrDefault: nonemeta.next_cursor from the previous page, passed back unchanged with the same other parameters.
Parameters by period
annual:startandendfilterperiod_end.growth_basishas no effect: growth compares with the fiscal year ending a year earlier.quarterly:startandendfilterperiod_end.growth_basisselects the comparison quarter.ttm:start,endandgrowth_basisdo not change the row. Growth compares the TTM total with the TTM total ending a year earlier. Useas_ofto take the snapshot on an earlier date.daily:startandendbound the trading dates.growth_basishas no effect: growth compares the TTM total with the TTM total ending a year earlier.as_of,fields,limitandcursorapply to all four.
A year earlier is the period ending closest to 365 days before the end of the period the row reads (period_end, or statement_period_end on daily rows), within 45 days either way. A quarter earlier is the latest period ending 60 to 125 days before it. Derived fourth quarters count as periods. Where no period ends in that window, the row has no comparison and the metric is null, named prior:<field>.
Snapshots on past dates
On ttm requests, start and end do not move the snapshot, which is always taken on today's date unless you pass as_of. Pass as_of for any historical ttm value.
In the Python client, pass the period as period_type. The client's own period argument is a lookback shorthand such as "5y", not this parameter. For annual and quarterly, the client sends start one year before today unless you pass start or period. See Python client.
Response
A 200 response is a JSON object with these top-level fields.
| field | type | unit | nullable | description |
|---|---|---|---|---|
data | list[object] | no | Metric rows for this page, ordered by issuer entity_id, then period_end, then the statement behind the row. Empty when nothing matches. | |
meta | object | no | Resolution, paging, units and freshness for the request. | |
warnings | list[str] | no | Present only when there is something to report: unknown names in fields, for example "Unknown field ignored: 'foo'", a parameter the endpoint does not read, a Free request that reaches before the one-year floor, or a ticker in a list that named more than one security. |
Row fields
| field | type | unit | nullable | description |
|---|---|---|---|---|
entity_id | int | no | Issuer id. | |
ticker | str | yes | The requested ticker that resolved to this issuer. On entity_id requests, the ticker of the issuer's primary listed class (see "Share classes"). When two requested tickers resolve to the same issuer, the issuer's rows appear once, under one of them. | |
entity_name | str | yes | Company name. | |
period_end | str (date) | no | annual and quarterly: the statement's period end. ttm: the end of the last quarter in the TTM window. daily: the trading date. | |
period_type | str | no | annual, quarterly, ttm or daily. | |
fiscal_year | int | yes | Fiscal year of the statement behind the row. | |
fiscal_period | str | yes | FY, Q1, Q2, Q3 or Q4: the fiscal period of the statement behind the row. | |
source | str | no | filing or archive: which leg of the fundamentals data the statement comes from, as on Fundamentals. | |
basis | str | no | The flow basis of the row: annual, quarterly or ttm. daily rows read ttm. | |
priced_on | str (date) | no | ttm rows only: the date of the close the snapshot is valued at. | |
statement_period_end | str (date) | no | daily rows only: the period_end of the statement behind the row, the latest statement published on or before the row's date whose period had ended before that date. Statements whose period ends fall within 20 days of each other count as one period, and among them the later-published one is the statement behind the row. | |
shares_as_of | str (date) | yes | Date of the share-count observation for the requested class on the row's date. | |
shares_source | str | yes | Source label of that observation, for example filing, filing_class or archive. | |
shares_stale | bool | no | Present only when true: a share count needed for market_cap is more than 400 days older than the row's date, so market_cap, the metrics built on it and the per-share metrics are null. | |
| one key per metric | float or int | per metric | yes | One key for each requested metric that the API serves, in the order requested. Units and formulas are in the Metrics catalogue. |
missing_inputs | object | no | Present only when at least one requested metric is null because an input was unavailable. Maps each such metric to a list of reasons, described below. | |
ttm_eps_basis | object | no | Quarterly, ttm and daily rows, present only where a trailing EPS was not the four quarters' EPS summed. Maps each EPS-based metric (pe_ratio, peg_ratio, grahams_number, eps_diluted_growth, eps_basic_growth) to a list of strings, one per trailing window its value read: the row's window first, then, for a growth figure over trailing windows, the comparison window. quarterly_sum: the four quarters' EPS summed. annual_as_filed:<period_end>: the diluted or basic EPS filed on the annual report for the fiscal year ending on that date. Example: {"pe_ratio": ["annual_as_filed:2026-07-25"]}. See "Derived fourth quarters". | |
ttm_includes_derived_q4 | bool | no | On every row. true where the four quarters behind the row's trailing-twelve-month figures include a derived fourth quarter (on ttm and daily rows, the four ending at the statement behind the row); false otherwise, and on annual rows. |
Reasons in missing_inputs:
- A statement field name, such as
eps_dilutedorcash_and_equivalents: the field isnullfor this period. prior:<field>, such asprior:revenue: the field isnullfor the preceding or comparison period (see Metrics catalogue).close: no close within 30 days of the row's date.shares_outstandingorprior:shares_outstanding: no usable share count on the row's date, or on the preceding or comparison date.shares_outstanding:depositary_count: on a per-share metric, the share count is recorded as a count of depositary shares rather than the company's own shares, and is not used.market_cap:no_equity_class_trading: no common class or depositary receipt of the issuer traded within 30 days of the date.market_cap:<entity_id>:stale_shares: the share class with that securityentity_idhas a share count more than 400 days old. The same pattern carriesno_pricefor a class whose latest bar has no close,no_sharesfor a class with no share-count observation on or before the date, ordepositary_countfor a class whose share count is recorded as a count of depositary shares rather than the company's own shares.prior:market_cap: no market capitalisation on the comparison date.insufficient_price_history: a volatility window lacks its full count of closes within its calendar span.close:not_common_equity: onpe_ratioandpeg_ratio, the priced security is not common stock, a depositary receipt or a fund share, such as a preferred, a unit, a structured product or a note.market_capand the metrics built on it do not read that close.eps_diluted:zero: onpe_ratio,peg_ratioandgrahams_number, the diluted EPS the metric reads is zero.eps_diluted:negative: ongrahams_number, diluted EPS is negative and book value per share is positive.eps_diluted:scale_suspectoreps_basic:scale_suspect: the EPS the metric reads carries theeps_scale_suspectlabel on Fundamentals and is not used.prior:eps_diluted:scale_suspectandprior:eps_basic:scale_suspectname the same for the comparison period.<input>:currency, such aseps_diluted:currency: the metric would set statement figures in two currencies against each other (within a row, across its trailing window or against its comparison row), or a figure in a currency other than USD against a USD close or market cap, or is a per-share figure or money amount computed from such a figure. Each figure counts in its own currency: its row'scurrencyon Fundamentals, or the onefield_currencynames for it. A figure whose currency isnulldoes not count.prior:<input>:currencynames an input of the comparison row. Ratios of figures in one currency are not affected: Canadian National's fiscal 2023pe_ratioisnullwitheps_diluted:currency, and itsnet_marginis served.shares_outstanding:zero: ongrahams_number, a share count of zero leaves book value per share undefined. Where book value per share is unknown for another reason,grahams_numbernamestotal_equityorshares_outstanding.prior:<field>:zero, such asprior:revenue:zero: on a growth metric orpeg_ratio, the field is zero for the comparison period.eps_diluted_growth:zero: onpeg_ratio, diluted EPS equals the comparison period's.
A metric that is null with no missing_inputs entry had every input but no defined value: a zero denominator that no reason above names, or, on grahams_number, a positive diluted EPS against a negative book value per share. A derived fourth quarter is a Fundamentals quarterly row whose labels carry derived_q4: true; see "Derived fourth quarters".
Apple's annual rows before its December 1980 listing have no market inputs. Paid plans return these rows; Free returns rows from the one-year window only (see Plan differences).
curl -s -H "X-API-Key: YOUR_API_KEY" "https://api.xfinlink.com/v1/metrics/AAPL?fields=market_cap,pe_ratio"{
"data": [
{
"entity_id": 1,
"ticker": "AAPL",
"entity_name": "APPLE INC",
"period_end": "1978-09-30",
"period_type": "annual",
"fiscal_year": 1978,
"fiscal_period": "FY",
"source": "archive",
"basis": "annual",
"shares_as_of": null,
"shares_source": null,
"market_cap": null,
"pe_ratio": null,
"missing_inputs": {
"market_cap": ["market_cap:no_equity_class_trading"],
"pe_ratio": ["eps_diluted", "close"]
},
"ttm_includes_derived_q4": false
},
...
],
"meta": {
...
"count": 20,
"limit": 20,
"has_more": true,
"next_cursor": "djJ8ZXlKeUlqb2liV1YwY21samN5SXNJbkVpT2lKUVdsWXhOMTloVlV0c00zZ3hXbXhXZFU5S2RXTkJJaXdpY0NJNk1pd2lheUk2SWsxWWQzaFBWR3N6VEZSQk5VeFVUWGRtUjBVMlRXcEJlRTE1TUhkT2VUQjNUbFJ2ZUU5VWF6TlBha0U5SW4wfEx1a2hDTmQ4a0RhZ2JBdHVWMFQ0Qmc=",
...
}
}Meta fields
See Response metadata for the meaning of knowledge_time, as_of and freshness.
| field | type | unit | nullable | description |
|---|---|---|---|---|
tickers_requested | list[str] | no | Tickers from the path. Empty on entity_id requests. | |
tickers_resolved | object | no | Ticker to issuer entity_id. Two tickers can map to the same issuer. | |
tickers_unresolved | list[str] | no | Tickers that did not resolve to an issuer, including ones that name more than one security on the date. | |
tickers_ambiguous | object | no | Present when a ticker named more than one security on the date and another ticker was served. Ticker to its candidates, each with entity_id, name, exchange, share_class, last_bar_date, valid_from and valid_to. | |
tickers_no_listed_security | list[str] | no | Present when a ticker reached an issuer that had no listed security on the resolution date. These tickers are also in tickers_unresolved. | |
tickers_resolved_via | object | no | Ticker to how it was matched, for example security_alias or last_holder. See Tickers and entities. | |
historical_resolution | object | no | Present when a ticker resolved to a company other than its holder today. Ticker to {entity_id, current_entity_id, as_of}: the issuer served, the issuer holding the ticker today (null if none) and the date the resolution landed on. For a last-holder match, that is the last date the company held the ticker. | |
historical_resolution_note | str | no | Present with historical_resolution: a fixed sentence explaining it. | |
entity_ids_requested | list[int] | no | entity_id requests only: the ids requested. | |
entity_ids_unresolved | list[int] | no | entity_id requests only: ids that did not resolve to an issuer, such as share-class ids. | |
count | int | rows | no | Rows in data on this page. |
limit | int | rows | no | Page size applied. |
has_more | bool | no | true when another page follows. | |
next_cursor | str | yes | Pass as cursor for the next page. null on the last page. | |
units | str | no | millions_usd: money metrics are in millions of USD. | |
entity_id_basis | str | no | issuer. | |
market_cap_basis | str | no | issuer_all_share_classes. | |
per_share_basis | str | no | split_adjusted_to_price_date: EPS from the statements is put on the share basis of the row's price date where its basis is confirmed. See "Stock splits". | |
metrics_not_available | object | no | Present when the request asks for metrics that are accepted but not served, which includes every request without fields. Maps each such metric to the statement fields it needs that are not served. Those metrics get no key in the rows. | |
knowledge_time | str (UTC timestamp) | yes | Newest knowledge time across the datasets behind the response. | |
as_of | str (date) | no | Present when you pass as_of: the value you passed. | |
freshness | list[object] | no | One {dataset, through, promoted_at} entry each for fundamentals, fundamentals_point_in_time, fundamentals_historical, prices and shares_outstanding. |
Pagination
A page holds limit rows: 20 by default, at most 100 on every plan. Rows are ordered by issuer entity_id, then period_end, both ascending, then by the statement behind the row, whatever order you list tickers in. When meta.has_more is true, repeat the request with cursor set to meta.next_cursor and the same path and other parameters. Treat the cursor as opaque.
A query can run to 10 pages on Free, 50 on Pro, 100 on Max and 200 on Redistribution, as on Prices and Fundamentals. A cursor beyond that returns 400 with Pagination limit reached. See Pagination, and Python client for how the client pages.
curl -s -H "X-API-Key: YOUR_API_KEY" "https://api.xfinlink.com/v1/metrics/AAPL?period=daily&start=2026-09-01&end=2026-09-25&fields=market_cap,pe_ratio&limit=10"{
"data": [
{
"entity_id": 1,
"ticker": "AAPL",
"entity_name": "APPLE INC",
"period_end": "2026-09-01",
"period_type": "daily",
"fiscal_year": 2026,
"fiscal_period": "Q3",
"source": "filing",
"basis": "ttm",
"statement_period_end": "2026-06-27",
"shares_as_of": "2026-07-17",
"shares_source": "filing",
"market_cap": 4745005.7434,
"pe_ratio": 37.2855504587156,
"ttm_includes_derived_q4": false
},
...
{
"entity_id": 1,
"ticker": "AAPL",
"entity_name": "APPLE INC",
"period_end": "2026-09-15",
"period_type": "daily",
"fiscal_year": 2026,
"fiscal_period": "Q3",
"source": "filing",
"basis": "ttm",
"statement_period_end": "2026-06-27",
"shares_as_of": "2026-07-17",
"shares_source": "filing",
"market_cap": 4835635.6012,
"pe_ratio": 37.997706422018354,
"ttm_includes_derived_q4": false
}
],
"meta": {
...
"count": 10,
"limit": 10,
"has_more": true,
"next_cursor": "djJ8ZXlKeUlqb2liV1YwY21samN5SXNJbkVpT2lKaWRFbHhkVEZUUTJOeVdEWjViak5yZUVFMGFWVkJJaXdpY0NJNk1pd2lheUk2SWsxWWQzbE5SRWt5VEZSQk5VeFVSVEZtUVQwOUluMHxNbnd0SjQtajdnT2NtWGhXT0hCZWdB",
...
}
}curl -s -H "X-API-Key: YOUR_API_KEY" "https://api.xfinlink.com/v1/metrics/AAPL?period=daily&start=2026-09-01&end=2026-09-25&fields=market_cap,pe_ratio&limit=10&cursor=djJ8ZXlKeUlqb2liV1YwY21samN5SXNJbkVpT2lKaWRFbHhkVEZUUTJOeVdEWjViak5yZUVFMGFWVkJJaXdpY0NJNk1pd2lheUk2SWsxWWQzbE5SRWt5VEZSQk5VeFVSVEZtUVQwOUluMHxNbnd0SjQtajdnT2NtWGhXT0hCZWdB"{
"data": [
{
"entity_id": 1,
"ticker": "AAPL",
"entity_name": "APPLE INC",
"period_end": "2026-09-16",
...
"market_cap": 4851251.3738,
"pe_ratio": 38.12041284403671,
"ttm_includes_derived_q4": false
},
...
{
"entity_id": 1,
"ticker": "AAPL",
"entity_name": "APPLE INC",
"period_end": "2026-09-25",
...
"market_cap": 4977636.9726,
"pe_ratio": 39.11353211009175,
"ttm_includes_derived_q4": false
}
],
"meta": {
...
"count": 8,
"limit": 10,
"has_more": false,
"next_cursor": null,
...
}
}Errors
| status | error code | when it happens | how to fix |
|---|---|---|---|
400 | bad_request | period or period_type is not annual, quarterly, ttm or daily. Values are case-sensitive. | Use one of the four values in lower case. |
400 | bad_request | growth_basis is not yoy, qoq or ttm_yoy. | Use one of the three values. |
400 | bad_request | start or end is not YYYY-MM-DD, or is not a real calendar date. | Send a real date such as 2024-02-29. |
400 | bad_request | as_of is not a real YYYY-MM-DD date. | Send a real date. |
400 | bad_request | start or end is outside 0005-01-01 to 9999-11-30, as_of is before 0005-01-01, or end is before start. | Send dates in range, with end on or after start. |
400 | bad_request | limit is not a whole number from 1 to 999,999,999, view is a non-empty value other than latest, or version a non-empty value other than restated. | Send a limit of 1 or more, and leave out view and version or send their one value. |
400 | bad_request | fields names no valid metric or category. | Use names from the Metrics catalogue or a category name. |
400 | bad_request | cursor was not issued for this request: it is not a next_cursor value, it has been altered, or it came from another path, a changed parameter or another endpoint. | Pass meta.next_cursor unchanged with the same path and parameters, or repeat the request without cursor. |
400 | bad_request | A ticker in the path and entity_id are both given. | Send one or the other. |
400 | bad_request | entity_id is empty or contains something other than positive integers. | Send ids such as entity_id=1 or entity_id=1,8611. |
400 | bad_request | More tickers or ids than your plan allows in one request. | Split the request, or see Plans and limits. |
401 | unauthorized | The X-API-Key header is missing or the key is not valid. | Send a valid key. See Authentication. |
404 | not_found | No requested ticker or id resolved to an issuer. A share-class id on its own returns this. | Check the ticker with Search, or use the issuer id from Resolve. |
404 | not_found | GET /v1/metrics with neither a ticker nor entity_id. | Add a ticker to the path or pass entity_id. |
405 | method_not_allowed | Any method other than GET and OPTIONS. | Use GET. |
409 | ambiguous_ticker | Every ticker in the request names more than one security on the date, such as BRK. candidates lists them, and hint reads pass entity_id=. | Request one class's ticker, such as BRK-B, or pass the issuer entity_id. |
429 | see Rate limits | A request or row allowance is used up. | Wait for the reset. A request-limit body gives the wait in retry_after_seconds; daily allowances reset at 00:00 UTC and hourly ones at the top of the UTC hour. |
Timeouts and server errors are listed on Errors. The bodies below are real responses from this endpoint.
{"error":"bad_request","code":"bad_request","status":400,"detail":"period must be annual, quarterly, ttm, or daily"}{"error":"bad_request","code":"bad_request","status":400,"detail":"growth_basis must be yoy, qoq, or ttm_yoy"}{"error":"bad_request","code":"bad_request","status":400,"detail":"Invalid start date format (YYYY-MM-DD)"}{"error":"bad_request","code":"bad_request","status":400,"detail":"Invalid start date: '2024-02-30' (expected a real YYYY-MM-DD date)"}{"error":"bad_request","code":"bad_request","status":400,"detail":"Invalid end date: '2024-13-01' (expected a real YYYY-MM-DD date)"}{"error":"bad_request","code":"bad_request","status":400,"detail":"Invalid as_of date format (YYYY-MM-DD)"}{"error":"bad_request","code":"bad_request","status":400,"detail":"No valid fields in request. Unknown field ignored: 'foo'. Available: market_cap, market_cap_diluted, enterprise_value, pe_ratio, ps_ratio, pb_ratio, ... realized_volatility_252d"}{"error":"bad_request","code":"bad_request","status":400,"detail":"Invalid cursor: not a cursor this API issued, or one from an earlier paging scheme. Repeat the request without cursor to start from the first page."}{"error":"bad_request","code":"bad_request","status":400,"detail":"Provide either a ticker in the path or an entity_id parameter, not both."}{"error":"bad_request","code":"bad_request","status":400,"detail":"Invalid entity_id: 'abc'. Must be a positive integer."}{"error":"bad_request","code":"bad_request","status":400,"detail":"entity_id must be a positive integer, or a comma-separated list of them"}{"error":"bad_request","code":"bad_request","status":400,"detail":"Maximum 100 tickers per request"}{"error":"unauthorized","code":"unauthorized","status":401,"detail":"No API key was sent. Pass your key in the X-API-Key header or the ?api_key= query parameter. Get one free at https://xfinlink.com/signup","message":"No API key was sent. Pass your key in the X-API-Key header or the ?api_key= query parameter. Get one free at https://xfinlink.com/signup"}{"error":"not_found","code":"not_found","status":404,"detail":"No matching entities for: ZZZZZZ"}{"error":"not_found","code":"not_found","status":404,"detail":"No matching entities for: 10003635"}{"error":"not_found","code":"not_found","status":404,"detail":"Unknown endpoint"}{"error":"method_not_allowed","code":"method_not_allowed","status":405,"detail":"This endpoint accepts GET only. Send a GET request."}Plan differences
Free and Pro serve the same metrics and the same row fields. They differ in how many tickers you can send, how far back rows go, and the default daily window.
- Tickers or ids per request: 1 on Free, 100 on Pro, 500 on Max and 5,000 on Redistribution.
- History: on Free,
startis replaced by the date one year before today (UTC) when it is absent or earlier, and theX-Data-Floorheader carries that date. Pro has no floor. dailywithoutstart: Free starts at the floor, so the window runs up to a year. Pro returns the last 90 days.limitis at most 100 on both. A query can run to 10 pages on Free and 50 on Pro.
The same request on both plans:
curl -s -D - -H "X-API-Key: YOUR_API_KEY" "https://api.xfinlink.com/v1/metrics/AAPL?fields=market_cap,pe_ratio"On Free, only fiscal years ending on or after the floor are returned:
HTTP/2 200
...
x-data-floor: 2025-09-27
x-ratelimit-limit-day: 100
x-ratelimit-limit-hour: 40
...{
"data": [
{
"entity_id": 1,
"ticker": "AAPL",
"entity_name": "APPLE INC",
"period_end": "2025-09-27",
"period_type": "annual",
"fiscal_year": 2025,
"fiscal_period": "FY",
"source": "filing",
"basis": "annual",
"shares_as_of": "2025-09-26",
"shares_source": "archive",
"market_cap": 3773976.9996,
"pe_ratio": 34.243967828418235,
"ttm_includes_derived_q4": false
}
],
"meta": {
...
"count": 1,
"limit": 20,
"has_more": false,
"next_cursor": null,
...
}
}On Pro, rows start at fiscal 1978 and run to 48 annual rows over three pages:
HTTP/2 200
...
x-ratelimit-limit-day: 10000
...{
"data": [
{
"entity_id": 1,
"ticker": "AAPL",
"entity_name": "APPLE INC",
"period_end": "1978-09-30",
...
},
...
],
"meta": {
...
"count": 20,
"limit": 20,
"has_more": true,
"next_cursor": "djJ8ZXlKeUlqb2liV1YwY21samN5SXNJbkVpT2lKUVdsWXhOMTloVlV0c00zZ3hXbXhXZFU5S2RXTkJJaXdpY0NJNk1pd2lheUk2SWsxWWQzaFBWR3N6VEZSQk5VeFVUWGRtUjBVMlRXcEJlRTE1TUhkT2VUQjNUbFJ2ZUU5VWF6TlBha0U5SW4wfEx1a2hDTmQ4a0RhZ2JBdHVWMFQ0Qmc=",
...
}
}A second ticker on Free is refused before any data is read:
curl -s -H "X-API-Key: YOUR_API_KEY" "https://api.xfinlink.com/v1/metrics/AAPL,MSFT"{"error":"bad_request","code":"bad_request","status":400,"detail":"Free tier allows 1 ticker per request. Upgrade to Pro for up to 100. https://xfinlink.com/pricing"}With entity_id the Free message reads Free tier allows 1 entity_id per request. Upgrade to Pro for up to 100. https://xfinlink.com/pricing. Above the cap on a paid plan the message names the plan's limit: Maximum 100 tickers per request on Pro and Maximum 5000 tickers per request on Redistribution.
daily without start, requested on 2026-09-27 with limit=100: on Free the first row is 2025-09-29, the first trading day on or after the floor, and more pages follow. On Pro the first row is 2026-06-29 and the 63 rows fit on one page.
curl -s -H "X-API-Key: YOUR_API_KEY" "https://api.xfinlink.com/v1/metrics/AAPL?period=daily&fields=market_cap,pe_ratio&limit=100"{
"data": [
{
"entity_id": 1,
"ticker": "AAPL",
"entity_name": "APPLE INC",
"period_end": "2025-09-29",
"period_type": "daily",
"fiscal_year": 2025,
"fiscal_period": "Q3",
"source": "filing",
"basis": "ttm",
"statement_period_end": "2025-06-28",
"shares_as_of": "2025-09-26",
"shares_source": "archive",
"market_cap": 3758760.5418,
"pe_ratio": 38.60849772382398,
"ttm_includes_derived_q4": false
},
...
],
"meta": {
...
"count": 100,
"limit": 100,
"has_more": true,
...
}
}Edge cases
Most examples in this section read periods and dates more than 12 months back. Paid plans return these rows; on Free, the same requests return only the rows inside the one-year window described under Plan differences.
Negative earnings
When diluted EPS is negative, pe_ratio is negative, not null. earnings_yield is negative too. grahams_number is null, with eps_diluted:negative in missing_inputs, because the value under its square root is negative. Intel's fiscal 2024:
curl -s -H "X-API-Key: YOUR_API_KEY" "https://api.xfinlink.com/v1/metrics/INTC?start=2023-01-01&fields=pe_ratio,earnings_yield,grahams_number,peg_ratio,eps_diluted_growth,net_margin"{
"data": [
...
{
"entity_id": 3862,
"ticker": "INTC",
"entity_name": "INTEL CORP",
"period_end": "2024-12-28",
"period_type": "annual",
"fiscal_year": 2024,
"fiscal_period": "FY",
"source": "filing",
"basis": "annual",
"shares_as_of": "2024-12-27",
"shares_source": "archive",
"pe_ratio": -4.634703196347032,
"earnings_yield": -0.2133812671361449,
"grahams_number": null,
"peg_ratio": 0.003878412716608395,
"eps_diluted_growth": -11.95,
"net_margin": -0.35321368712453627,
"missing_inputs": {
"grahams_number": ["eps_diluted:negative"]
},
"ttm_includes_derived_q4": false
},
...
],
...
}A negative diluted EPS never makes pe_ratio null; a zero one does, named eps_diluted:zero. Filter on sign before ranking companies by P/E.
Stock splits
Per-share metrics divide by the share count on the row's date, consistent with that day's close, so they step down by the split ratio on the split date. Where the basis of the EPS a row reads is confirmed, as for NVIDIA here, pe_ratio moves with the price only. NVIDIA split 10-for-1 on 2024-06-10:
curl -s -H "X-API-Key: YOUR_API_KEY" "https://api.xfinlink.com/v1/metrics/NVDA?period=daily&start=2024-06-07&end=2024-06-10&fields=market_cap,revenue_per_share,book_value_per_share,pe_ratio"{
"data": [
{
"entity_id": 29109,
"ticker": "NVDA",
"entity_name": "NVIDIA CORP",
"period_end": "2024-06-07",
"period_type": "daily",
...
"market_cap": 2970077.9299200005,
"revenue_per_share": 32.46958342355602,
"book_value_per_share": 20.001758324772354,
"pe_ratio": 70.69473684210526,
"ttm_includes_derived_q4": false
},
{
"entity_id": 29109,
"ticker": "NVDA",
"entity_name": "NVIDIA CORP",
"period_end": "2024-06-10",
"period_type": "daily",
...
"market_cap": 2992239.0236,
"revenue_per_share": 3.2469583423556014,
"book_value_per_share": 2.000175832477235,
"pe_ratio": 71.22222222222221,
"ttm_includes_derived_q4": false
}
],
...
}market_cap is unaffected by the split. EPS and realised volatility enter as follows:
- Every EPS a metric reads, in
pe_ratio,peg_ratio,grahams_number,eps_diluted_growthandeps_basic_growth, including each EPS behind a trailing EPS, is put on the share basis of the row's price date:period_endonannualandquarterlyrows, the trading date ondailyrows andpriced_ononttmrows. A figure is moved only where its own share count confirms the basis it was filed on.meta.per_share_basisreadssplit_adjusted_to_price_date. - Where an EPS a row reads would need moving and its basis is not confirmed, every EPS on that row enters as filed, as on Fundamentals, so
pe_ratio,peg_ratioandgrahams_numberon that row can jump across a split. - Realised volatility is computed from day-to-day log changes in the as-traded
closeof the requested class, not fromadj_closeorreturn_daily. Dividends are not added back, and a window that includes a split date includes that day's price change.
Delisted companies
A delisted company's ticker resolves on the dates you request, and meta.historical_resolution reports it. Twitter was taken private in October 2022, so its last annual row is fiscal 2021 and nobody holds TWTR today:
curl -s -H "X-API-Key: YOUR_API_KEY" "https://api.xfinlink.com/v1/metrics/TWTR?start=2020-01-01&fields=market_cap,pe_ratio,revenue_growth"{
"data": [
{
"entity_id": 12271,
"ticker": "TWTR",
"entity_name": "TWITTER INC",
"period_end": "2020-12-31",
...
"market_cap": 43068.2025,
"pe_ratio": -37.604166666666664,
"revenue_growth": 0.074297645583869,
"ttm_includes_derived_q4": false
},
{
"entity_id": 12271,
"ticker": "TWTR",
"entity_name": "TWITTER INC",
"period_end": "2021-12-31",
...
"market_cap": 34559.1442,
"pe_ratio": -154.35714285714283,
"revenue_growth": 0.36625542972417274,
"ttm_includes_derived_q4": false
}
],
"meta": {
"tickers_requested": ["TWTR"],
"tickers_resolved": {"TWTR": 12271},
"tickers_unresolved": [],
"tickers_resolved_via": {"TWTR": "security_alias"},
"historical_resolution": {
"TWTR": {"entity_id": 12271, "current_entity_id": null, "as_of": "2020-01-01"}
},
"historical_resolution_note": "Resolved to a previous holder of the ticker: the requested date window ends before the ticker's current holder acquired it. Pass entity_id to pin an entity explicitly.",
...
}
}A ttm request without as_of values the company at today's close, so a delisted company returns 200 with an empty data array and count: 0. Pass as_of for a date when it traded:
curl -s -H "X-API-Key: YOUR_API_KEY" "https://api.xfinlink.com/v1/metrics/TWTR?period=ttm&as_of=2022-06-30&fields=market_cap,pe_ratio,ps_ratio"{
"data": [
{
"entity_id": 12271,
"ticker": "TWTR",
"entity_name": "TWITTER INC",
"period_end": "2022-03-31",
"period_type": "ttm",
"fiscal_year": 2022,
"fiscal_period": "Q1",
"source": "filing",
"basis": "ttm",
"priced_on": "2022-06-30",
"shares_as_of": "2022-06-30",
"shares_source": "archive",
"market_cap": 28577.06483,
"pe_ratio": 162.56521739130443,
"ps_ratio": 5.451091709445663,
"ttm_includes_derived_q4": false
}
],
"meta": {
...
"as_of": "2022-06-30",
...
}
}Recycled tickers
A ticker is resolved on as_of, then end, then start, then today, and finally to its last holder, so a window in the past reaches the company that held the ticker then. EDS for 2006 to 2008 returns Electronic Data Systems:
curl -s -H "X-API-Key: YOUR_API_KEY" "https://api.xfinlink.com/v1/metrics/EDS?start=2006-01-01&end=2008-12-31&fields=market_cap,pe_ratio"{
"data": [
{
"entity_id": 3165,
"ticker": "EDS",
"entity_name": "ELECTRONIC DATA SYS CORP NEW",
"period_end": "2006-12-31",
"period_type": "annual",
"fiscal_year": 2006,
"fiscal_period": "FY",
"source": "archive",
"basis": "annual",
"shares_as_of": "2006-12-29",
"shares_source": "archive",
"market_cap": 14249.5212,
"pe_ratio": 29.308510638297875,
"ttm_includes_derived_q4": false
},
{
"entity_id": 3165,
...
"period_end": "2007-12-31",
...
"market_cap": 10615.66716,
"pe_ratio": 15.131386861313867,
"ttm_includes_derived_q4": false
}
],
"meta": {
...
"historical_resolution": {
"EDS": {"entity_id": 3165, "current_entity_id": null, "as_of": "2006-01-01"}
},
...
}
}On ttm requests, start and end still date the resolution but do not move the snapshot. GM?period=ttm&end=2005-12-31 resolves to the General Motors that held the ticker in 2005 (entity_id 4, with current_entity_id 5), while the snapshot is still taken at today's date, so data is empty. Use as_of to take the snapshot on an earlier date, as in the Twitter example above. To pin a company regardless of dates, pass its issuer entity_id.
Share classes
A share-class ticker resolves to its issuer. market_cap, per-share metrics and statement ratios are the same whichever class you request. Price ratios such as pe_ratio use the requested class's own close:
curl -s -H "X-API-Key: YOUR_API_KEY" "https://api.xfinlink.com/v1/metrics/GOOGL?period=ttm&fields=market_cap,pe_ratio,book_value_per_share"
curl -s -H "X-API-Key: YOUR_API_KEY" "https://api.xfinlink.com/v1/metrics/GOOG?period=ttm&fields=market_cap,pe_ratio,book_value_per_share"{
"data": [
{
"entity_id": 31223,
"ticker": "GOOGL",
"entity_name": "ALPHABET INC",
"period_end": "2026-06-30",
"period_type": "ttm",
"fiscal_year": 2026,
"fiscal_period": "Q2",
"source": "filing",
"basis": "ttm",
"priced_on": "2026-09-25",
"shares_as_of": "2026-07-15",
"shares_source": "filing_class",
"market_cap": 3903271.72,
"pe_ratio": 17.27373179306881,
"book_value_per_share": 56.2071083808688,
"ttm_includes_derived_q4": false
}
],
...
}{
"data": [
{
"entity_id": 31223,
"ticker": "GOOG",
"entity_name": "ALPHABET INC",
"period_end": "2026-06-30",
"period_type": "ttm",
"fiscal_year": 2026,
"fiscal_period": "Q2",
"source": "filing",
"basis": "ttm",
"priced_on": "2026-09-25",
"shares_as_of": "2026-07-15",
"shares_source": "filing_class",
"market_cap": 3903271.72,
"pe_ratio": 17.131089904570565,
"book_value_per_share": 56.2071083808688,
"ttm_includes_derived_q4": false
}
],
...
}When one request names two classes of the same issuer, such as /v1/metrics/GOOGL,GOOG, both tickers map to 31223 in meta.tickers_resolved and the issuer's rows appear once, under one of the two tickers. Request one class per issuer when you need class-specific price ratios.
A request by issuer entity_id is priced on, and labelled with, the issuer's primary listed class, chosen on as_of, or on today without it. It is the issuer's one share class that traded in the 30 days up to that date; when several traded, one of the common classes among them; when none traded, one of its common classes, or its only class. Among several, the class with no class letter comes first, then the lowest letter, then the lowest entity_id. ?entity_id=31223 reads GOOGL and returns the same rows as /v1/metrics/GOOGL. ?entity_id=942 reads BRK-A, ?entity_id=1944 (Molson Coors) reads TAP-A and ?entity_id=1141 (Brown-Forman) reads BF-A. To price on another class, request its ticker, such as BRK-B.
BRK, which names both Berkshire Hathaway classes, returns 409 with both classes as candidates; see Errors.
Before and after a filing
as_of returns what was knowable on a date. Apple filed its fiscal 2025 annual report on 2025-10-31. The day before, the fiscal 2025 row does not exist:
curl -s -H "X-API-Key: YOUR_API_KEY" "https://api.xfinlink.com/v1/metrics/AAPL?start=2024-01-01&as_of=2025-10-30&fields=pe_ratio,market_cap,net_margin,revenue_growth"{
"data": [
{
"entity_id": 1,
"ticker": "AAPL",
"entity_name": "APPLE INC",
"period_end": "2024-09-28",
"period_type": "annual",
"fiscal_year": 2024,
"fiscal_period": "FY",
"source": "filing",
"basis": "annual",
"shares_as_of": "2024-09-27",
"shares_source": "archive",
"pe_ratio": 37.46545888157895,
"market_cap": 3443452.5317721395,
"net_margin": 0.23971255769943867,
"revenue_growth": 0.020219940775141214,
"ttm_includes_derived_q4": false
}
],
"meta": {
...
"count": 1,
...
"as_of": "2025-10-30"
}
}With as_of=2025-10-31 the same request returns a second row:
{
"data": [
{
"entity_id": 1,
...
"period_end": "2024-09-28",
...
},
{
"entity_id": 1,
"ticker": "AAPL",
"entity_name": "APPLE INC",
"period_end": "2025-09-27",
"period_type": "annual",
"fiscal_year": 2025,
"fiscal_period": "FY",
"source": "filing",
"basis": "annual",
"shares_as_of": "2025-09-26",
"shares_source": "archive",
"pe_ratio": 34.243967828418235,
"market_cap": 3773976.9996,
"net_margin": 0.2691506412181824,
"revenue_growth": 0.0642551178283274,
"ttm_includes_derived_q4": false
}
],
"meta": {
...
"count": 2,
...
"as_of": "2025-10-31"
}
}daily rows follow the same rule day by day. Apple filed its June 2026 quarter on 2026-07-31. Daily rows up to 2026-07-30 carry fiscal_period Q2. From 2026-07-31 they carry Q3 and include the new quarter in their TTM flows.
Dates before coverage
Rows begin at the company's first statement. Annual rows for periods before the company's shares traded carry statement metrics and null market metrics, with market_cap:no_equity_class_trading in missing_inputs (see the Apple 1978 row under "Row fields").
A window that ends before the first statement returns 200 with an empty data array:
curl -s -H "X-API-Key: YOUR_API_KEY" "https://api.xfinlink.com/v1/metrics/AAPL?end=1975-12-31&fields=market_cap"{
"data": [],
"meta": {
"tickers_requested": ["AAPL"],
"tickers_resolved": {"AAPL": 1},
"tickers_unresolved": [],
"tickers_resolved_via": {"AAPL": "security_alias"},
"count": 0,
"limit": 20,
"has_more": false,
"next_cursor": null,
...
}
}A daily row needs a statement published on or before its day. Without as_of, each period's statement is its current version, dated by when that version was published, so a daily window far in the past can be empty. With as_of, each statement is the version current on that date, and Apple's December 2005 window returns 21 rows:
curl -s -H "X-API-Key: YOUR_API_KEY" "https://api.xfinlink.com/v1/metrics/AAPL?period=daily&start=2005-12-01&end=2005-12-31&as_of=2005-12-31&fields=market_cap,pe_ratio&limit=100"{
"data": [
...
{
"entity_id": 1,
"ticker": "AAPL",
"entity_name": "APPLE INC",
"period_end": "2005-12-30",
"period_type": "daily",
"fiscal_year": 2005,
"fiscal_period": "Q4",
"source": "archive",
"basis": "ttm",
"statement_period_end": "2005-09-30",
"shares_as_of": "2005-12-30",
"shares_source": "archive",
"market_cap": 60791.40613,
"pe_ratio": 37.63874345549738,
"ttm_includes_derived_q4": false
}
],
"meta": {
...
"count": 21,
"limit": 100,
"has_more": false,
...
"as_of": "2005-12-31"
}
}Daily default window
Without start, a daily request covers the 90 calendar days ending on end, or on today. On Pro on 2026-09-27 that is 2026-06-29 to 2026-09-25, 63 trading days. With end=2024-06-28 and no start it is 2024-04-01 to 2024-06-28. On Free the window starts at the floor instead (see "Plan differences").
curl -s -H "X-API-Key: YOUR_API_KEY" "https://api.xfinlink.com/v1/metrics/AAPL?period=daily&fields=pe_ratio,market_cap,realized_volatility_21d&limit=100"{
"data": [
{
"entity_id": 1,
"ticker": "AAPL",
"entity_name": "APPLE INC",
"period_end": "2026-06-29",
"period_type": "daily",
"fiscal_year": 2026,
"fiscal_period": "Q2",
"source": "filing",
"basis": "ttm",
"statement_period_end": "2026-03-28",
"shares_as_of": "2026-04-17",
"shares_source": "filing",
"pe_ratio": 34.0677146311971,
"market_cap": 4138015.67944,
"realized_volatility_21d": 0.3356200116817197,
"ttm_includes_derived_q4": false
},
...
{
"entity_id": 1,
"ticker": "AAPL",
"entity_name": "APPLE INC",
"period_end": "2026-09-25",
"period_type": "daily",
"fiscal_year": 2026,
"fiscal_period": "Q3",
"source": "filing",
"basis": "ttm",
"statement_period_end": "2026-06-27",
"shares_as_of": "2026-07-17",
"shares_source": "filing",
"pe_ratio": 39.11353211009175,
"market_cap": 4977636.9726,
"realized_volatility_21d": 0.21645096599842498,
"ttm_includes_derived_q4": false
}
],
"meta": {
...
"count": 63,
"limit": 100,
"has_more": false,
"next_cursor": null,
...
}
}Derived fourth quarters
A quarterly row on Fundamentals whose labels carry derived_q4: true is a derived fourth quarter: the fiscal year as reported on the 10-K less the first nine months as reported on the third-quarter 10-Q. Its eps_basic, eps_diluted and share counts are null. Metrics read it as follows:
- A derived fourth quarter is a period like any other for comparisons. Its own row compares with the periods ending a quarter and a year before it, and later rows compare with it. With
growth_basisyoyorqoq, its EPS growth metrics arenull, namedeps_dilutedoreps_basic, because its EPS isnull. Withttm_yoythey compare trailing EPS, andttm_eps_basisnames the EPS each window read. - A trailing EPS over a window that holds the derived quarter is not a four-quarter sum. Where the four quarters span exactly one fiscal year, it is the EPS filed on that year's annual report. Where the window spans two fiscal years and its only missing EPS is the derived quarter's, it is the EPS filed for the fiscal year that quarter closes.
ttm_eps_basisnames either caseannual_as_filed:<period_end>. ttm_includes_derived_q4istrueon every quarterly,ttmanddailyrow whose four trailing quarters include a derived fourth quarter.
Cisco's fiscal 2026 fourth quarter, ending 2026-07-25, is derived:
curl -s -H "X-API-Key: YOUR_API_KEY" "https://api.xfinlink.com/v1/metrics/CSCO?period=quarterly&start=2026-04-01&fields=pe_ratio,net_margin,revenue_growth,eps_diluted_growth"{
"data": [
{
"entity_id": 12912,
"ticker": "CSCO",
"entity_name": "CISCO SYSTEMS INC",
"period_end": "2026-04-25",
"period_type": "quarterly",
"fiscal_year": 2026,
"fiscal_period": "Q3",
"source": "filing",
"basis": "quarterly",
"shares_as_of": "2026-02-12",
"shares_source": "filing",
"pe_ratio": 29.57142857142857,
"net_margin": 0.2129284767375797,
"revenue_growth": 0.11958442292741536,
"eps_diluted_growth": 0.3709677419354838,
"ttm_includes_derived_q4": false
},
{
"entity_id": 12912,
"ticker": "CSCO",
"entity_name": "CISCO SYSTEMS INC",
"period_end": "2026-07-25",
"period_type": "quarterly",
"fiscal_year": 2026,
"fiscal_period": "Q4",
"source": "filing",
"basis": "quarterly",
"shares_as_of": "2026-05-14",
"shares_source": "filing",
"pe_ratio": 34.28528528528528,
"net_margin": 0.2236842105263158,
"revenue_growth": 0.17576501056362026,
"eps_diluted_growth": null,
"missing_inputs": {
"eps_diluted_growth": ["eps_diluted"]
},
"ttm_eps_basis": {
"pe_ratio": ["annual_as_filed:2026-07-25"]
},
"ttm_includes_derived_q4": true
}
],
...
}The fourth quarter's pe_ratio divides the close on 2026-07-25 by the diluted EPS filed on Cisco's fiscal 2026 annual report, because the window's four quarters are that fiscal year. Its net_margin reads the quarter's own derived figures, and its revenue_growth compares the derived quarter's revenue with fiscal 2025's fourth quarter, whose period_end on Fundamentals is 2025-07-31, 359 days earlier. ttm and daily rows built on that quarter carry the same ttm_eps_basis entry and ttm_includes_derived_q4: true.
Request examples
A trailing-twelve-month snapshot of four valuation metrics for Apple. market_cap is in millions of USD, pe_ratio and ev_revenue are multiples, and earnings_yield is a decimal fraction.
import xfinlink as xfl
xfl.set_api_key("YOUR_API_KEY")
df = xfl.metrics("AAPL", period_type="ttm", fields=["pe_ratio", "ev_revenue", "market_cap", "earnings_yield"])
print(df[["ticker", "period_end", "priced_on", "pe_ratio", "ev_revenue", "market_cap", "earnings_yield"]].to_string(index=False))curl -s -H "X-API-Key: YOUR_API_KEY" "https://api.xfinlink.com/v1/metrics/AAPL?period_type=ttm&fields=pe_ratio,ev_revenue,market_cap,earnings_yield"Using xfinlink, what are Apple's trailing twelve-month P/E ratio, EV to revenue, market cap and earnings yield?ticker period_end priced_on pe_ratio ev_revenue market_cap earnings_yield
AAPL 2026-06-27 2026-09-25 39.113532 10.735182 4977636.9726 0.025902{
"data": [
{
"entity_id": 1,
"ticker": "AAPL",
"entity_name": "APPLE INC",
"period_end": "2026-06-27",
"period_type": "ttm",
"fiscal_year": 2026,
"fiscal_period": "Q3",
"source": "filing",
"basis": "ttm",
"priced_on": "2026-09-25",
"shares_as_of": "2026-07-17",
"shares_source": "filing",
"pe_ratio": 39.11353211009175,
"ev_revenue": 10.735182226668352,
"market_cap": 4977636.9726,
"earnings_yield": 0.025901848750664352,
"ttm_includes_derived_q4": false
}
],
"meta": {
"tickers_requested": [
"AAPL"
],
"tickers_resolved": {
"AAPL": 1
},
"tickers_unresolved": [],
"tickers_resolved_via": {
"AAPL": "security_alias"
},
"count": 1,
"limit": 20,
"has_more": false,
"next_cursor": null,
"units": "millions_usd",
"entity_id_basis": "issuer",
"market_cap_basis": "issuer_all_share_classes",
"per_share_basis": "split_adjusted_to_price_date",
"knowledge_time": "2026-09-26T12:48:18Z",
"freshness": [
{
"dataset": "fundamentals",
"through": "2026-08-31",
"promoted_at": "2026-09-24T08:26:05Z"
},
{
"dataset": "fundamentals_point_in_time",
"through": "2026-07-31",
"promoted_at": "2026-09-18T03:34:17Z"
},
{
"dataset": "fundamentals_historical",
"through": "2026-07-31",
"promoted_at": "2026-10-01T06:51:42Z"
},
{
"dataset": "prices",
"through": "2026-09-25",
"promoted_at": "2026-09-21T14:19:25Z"
},
{
"dataset": "shares_outstanding",
"through": "2026-09-23",
"promoted_at": "2026-09-24T08:30:33Z"
}
]
}
}{"tool": "get_metrics", "arguments": {"ticker": "AAPL", "period_type": "ttm", "fields": "pe_ratio,ev_revenue,market_cap,earnings_yield"}}
{
"data": [
{
"entity_id": 1,
"ticker": "AAPL",
"entity_name": "APPLE INC",
"period_end": "2026-06-27",
"period_type": "ttm",
"fiscal_year": 2026,
"fiscal_period": "Q3",
"source": "filing",
"basis": "ttm",
"priced_on": "2026-09-25",
"shares_as_of": "2026-07-17",
"shares_source": "filing",
"pe_ratio": 39.11353211009175,
"ev_revenue": 10.735182226668352,
"market_cap": 4977636.9726,
"earnings_yield": 0.025901848750664352,
"ttm_includes_derived_q4": false
}
],
"meta": {
"tickers_requested": ["AAPL"],
"tickers_resolved": {"AAPL": 1},
"tickers_unresolved": [],
"tickers_resolved_via": {"AAPL": "security_alias"},
"count": 1,
"limit": 20,
"has_more": false,
"next_cursor": null,
"units": "millions_usd",
"entity_id_basis": "issuer",
"market_cap_basis": "issuer_all_share_classes",
"per_share_basis": "split_adjusted_to_price_date",
"knowledge_time": "2026-09-26T12:48:18Z",
"freshness": [
{"dataset": "fundamentals", "through": "2026-08-31", "promoted_at": "2026-09-24T08:26:05Z"},
{"dataset": "fundamentals_point_in_time", "through": "2026-07-31", "promoted_at": "2026-09-18T03:34:17Z"},
{"dataset": "fundamentals_historical", "through": "2026-07-31", "promoted_at": "2026-10-01T06:51:42Z"},
{"dataset": "prices", "through": "2026-09-25", "promoted_at": "2026-09-21T14:19:25Z"},
{"dataset": "shares_outstanding", "through": "2026-09-23", "promoted_at": "2026-09-24T08:30:33Z"}
]
}
}Was this page helpful?
Thank you for helping improve xfinlink documentation.
- Need help? Get in touch.
- Building with an LLM? Read llms.txt.
- Using Claude or ChatGPT? Connect the MCP server.