Response metadata
Read response metadata to see how tickers resolved, what an entity ID names, how rows page and how current the data is.
Every JSON response carries metadata next to its rows. It tells you which entity each ticker was matched to, whether entity_id names a share class or a company, how many rows came back and whether more exist, and how current each dataset behind the response is. This page explains every metadata field once. Reference pages list the fields their endpoint returns and link here for the meaning. Examples that send several tickers or ids in one request, or read dates more than 12 months back, show paid-plan responses.
Where metadata lives
The API uses two envelope shapes.
Prices, fundamentals, metrics, resolve, search, index constituents and index events return data and meta. When the API has something to tell you about your parameters, it adds a top-level warnings array. A resolve request without a key also carries a top-level restricted: true.
{
"data": [ ... ],
"meta": {
"tickers_requested": ["TWTR"],
"tickers_resolved": {"TWTR": 10003373},
...
"count": 4,
"has_more": false,
"next_cursor": null,
"knowledge_time": "2026-09-26T12:48:18Z",
"as_of": "2022-11-30",
"freshness": [ ... ],
"change_cursor": "MTc5MTAwNTAxNTcyNnww"
},
"warnings": ["Unknown field ignored: 'foo'"]
}Insider transactions, institutional holdings, manager holdings and manager search put request and paging fields at the top level, next to data, and keep grain, era and freshness fields in a nested meta. These four endpoints need Pro or higher.
- Insiders and holdings:
tickers,entity_idsandentity_ids_unresolved(entity ID requests),tickers_unresolved,historical_resolution,historical_resolution_note,data,data_through,count,next_cursor,warnings,meta. - Manager holdings:
manager,data,data_through,count,next_cursor,warnings,meta. - Manager search:
data,count,next_cursor,warnings,meta.
entity_ids, entity_ids_unresolved, tickers_unresolved, historical_resolution, historical_resolution_note and warnings appear only when they have something to report.
{
"tickers": ["BRK"],
"data": [ ... ],
"data_through": "2020-12-31",
"count": 1,
"next_cursor": "djJ8ZXlKeUlqb2lhRzlzWkdsdVozTWlMQ0p4SWpvaWFHdEpPVEp5ZUd4RlQwdFlia0ZPYWxOWlkzUlBVU0lzSW5BaU9qSXNJbXNpT2lKTmFrRjVUVU13ZUUxcE1IcE5XSGQ0VFhwVmVFNUVaek5QUkVZNFQxUkJkMDFFYTNkT1JGVXpaa2hOZUUxRVFYbE9WRWw1VFZoNE9FOXFhekJOYW04d1RWUkJNVTFxV1hwTlJHTjNXbGRXYUUweVRUQk9ha1Y2V1hwb2JFNXFaelZPUjBwcVdrUlJOVTFCUFQwaWZRfDc2dWU1Z05IclpqRTdOd3BRMFZNSlE=",
"warnings": ["BRK named more than one share class on that date; served at the company level"],
"meta": {
"entity_id_is": "security",
"entity_id_grain": "issuer",
"archive_edge": "2025-12-31",
"amendment_view": "current",
"era_fallback": false,
"knowledge_time": "2026-07-25T19:46:39Z",
"as_of": "2020-12-31",
"freshness": [
{"dataset": "institutional_holdings_historical", "through": "2025-12-31", "promoted_at": "2026-09-24T19:51:07Z"}
],
"change_cursor": "MTc5MTAwNDY3OTA5NXww",
"has_more": true,
"next_cursor": "djJ8ZXlKeUlqb2lhRzlzWkdsdVozTWlMQ0p4SWpvaWFHdEpPVEp5ZUd4RlQwdFlia0ZPYWxOWlkzUlBVU0lzSW5BaU9qSXNJbXNpT2lKTmFrRjVUVU13ZUUxcE1IcE5XSGQ0VFhwVmVFNUVaek5QUkVZNFQxUkJkMDFFYTNkT1JGVXpaa2hOZUUxRVFYbE9WRWw1VFZoNE9FOXFhekJOYW04d1RWUkJNVTFxV1hwTlJHTjNXbGRXYUUweVRUQk9ha1Y2V1hwb2JFNXFaelZPUjBwcVdrUlJOVTFCUFQwaWZRfDc2dWU1Z05IclpqRTdOd3BRMFZNSlE="
}
}That response came from GET /v1/holdings/BRK?quarter=2020-12-31&limit=1.
In the Python client
Functions that return a DataFrame (prices, fundamentals, metrics, search, index, index_events, insiders, holdings, manager_holdings, managers) return rows only. xfl.resolve() and xfl.status() return the JSON body as a dict, meta included. To read meta on other endpoints, call the REST API or the MCP server.
import xfinlink as xfl
xfl.set_api_key("YOUR_API_KEY")
df = xfl.prices("MSFT", start="2026-09-25", end="2026-09-25")
print(type(df).__name__, df.attrs)
r = xfl.resolve("MSFT")
print(sorted(r.keys()))
print(r["meta"]["resolved_as_of"], r["meta"]["tickers_resolved_via"])DataFrame {}
['data', 'meta']
2026-09-27 {'MSFT': 'security_alias'}Freshness fields
Every data response carries knowledge_time and freshness, and carries as_of when the request fixes a date. /v1/status returns freshness for every dataset at once. Every data response also ends its meta with change_cursor, a position in the change feed that /v1/changes takes as since.
| field | type | unit | nullable | description |
|---|---|---|---|---|
knowledge_time | str | UTC timestamp, YYYY-MM-DDTHH:MM:SSZ | yes | The newest knowledge time among the datasets the response was built from: the latest moment at which any of them recorded new information. |
as_of | str | date, YYYY-MM-DD | no | The date the response is pinned to. Present only when the request fixes one; the source differs by endpoint (list below). |
freshness | list[object] | none | no | One entry per dataset behind the response. |
freshness[].dataset | str | none | no | Public dataset name, for example prices. Status and freshness lists all nineteen. |
freshness[].through | str | date, YYYY-MM-DD | no | The last date the dataset covers. |
freshness[].promoted_at | str | UTC timestamp, YYYY-MM-DDTHH:MM:SSZ | no | When the dataset's current build was published. Daily additions can move through forward without changing promoted_at. |
change_cursor | str | none | no | The change feed's position when the response was built. Sent as since to /v1/changes, it returns the changes published after this response. A response served from the cache carries the cursor of the moment it was cached, together with the data of that moment. |
"knowledge_time": "2026-09-26T12:48:18Z",
"as_of": "2026-09-25",
"freshness": [
{"dataset": "prices", "through": "2026-09-25", "promoted_at": "2026-09-21T14:19:25Z"},
{"dataset": "price_adjustments", "through": "2026-09-25", "promoted_at": "2026-09-18T19:07:02Z"},
{"dataset": "shares_outstanding", "through": "2026-09-23", "promoted_at": "2026-09-24T08:30:33Z"}
],
"change_cursor": "MTc5MTAwNDQ5MTMzNXww"Reading knowledge_time
knowledge_time describes the datasets, not your query. A prices request for October 2022 and one for September 2026 both carry 2026-09-26T12:48:18Z. It is also independent of the as_of you ask for: GET /v1/fundamentals/AAPL?period=annual&start=2023-01-01&as_of=2025-06-30 returns "as_of": "2025-06-30" with "knowledge_time": "2026-09-24T05:01:31Z".
It moves with the set of datasets used. GET /v1/resolve/MSFT without a key draws on four datasets and returns 2026-09-18T01:59:25Z. With a key it adds index_membership and classifications and returns 2026-09-26T18:09:11Z.
Point-in-time and as-of explains how to ask for figures as they were known on a past date.
Where as_of comes from
- Prices: your
enddate. - Fundamentals and metrics: your
as_ofparameter. - Resolve: your
dateparameter. - Index constituents: the roster date. Always present; today's date when you send no
as_of. - Index events: your
enddate. - Insiders: your
enddate, else yourstartdate. - Holdings: your
enddate, elsequarter, elsestart. - Manager holdings: your
enddate, elsequarter. - Search and manager search: never present.
Resolution fields
These fields report how each ticker or entity_id you sent was matched. Tickers and entities explains the resolution rules.
| field | type | unit | nullable | description |
|---|---|---|---|---|
tickers_requested | list[str] | none | no | The tickers you sent, upper-cased, in order. Empty on entity_id requests. Prices, fundamentals, metrics, resolve. |
tickers | list[str] | none | no | Top-level equivalent of tickers_requested on insiders and holdings. |
tickers_resolved | object or list[str] | none | no | On prices, fundamentals and metrics: an object mapping each resolved ticker to the entity_id served. On resolve: a list of the tickers that found at least one entity. |
tickers_unresolved | list[str] | none | no | Tickers that were not served. On insiders and holdings this is top-level and present only when non-empty. |
resolved_via | object | none | no | Prices only. How each resolved ticker was matched (values below). |
tickers_resolved_via | object | none | no | Fundamentals, metrics and resolve. Same meaning and values as resolved_via. |
tickers_ambiguous | object | none | no | Tickers that name more than one security on the resolution date, each mapped to its candidates. Prices, metrics and resolve; on fundamentals, tickers that name more than one company. Present only when some other ticker in the request was served. |
ambiguous_hint | str | none | no | Resolve only, with tickers_ambiguous: "pass entity_id=". |
tickers_no_listed_security | object | none | no | Resolve: tickers that name a company with no security listed on the resolution date, each mapped to {issuer_entity_id, name}. |
tickers_past_holders_only | list[str] | none | no | Resolve without date: tickers that no security holds today. Their past holders are still listed in data. |
resolved_as_of | str | date, YYYY-MM-DD | no | Resolve: the date tickers were resolved on. Your date, else today. |
historical_resolution | object | none | no | Tickers served by an entity that does not hold the ticker today, each mapped to {entity_id, current_entity_id, as_of}. current_entity_id is null when nothing holds the ticker today. as_of is the date the match was made on. Insiders and holdings add via, the date rule that chose the entity, and put this field at the top level. |
historical_resolution_note | str | none | no | A fixed sentence that accompanies historical_resolution. |
entity_ids_requested | list[int] | none | no | Prices, fundamentals and metrics, on entity_id requests: the IDs you sent, de-duplicated. |
entity_ids | list[int] | none | no | Top-level equivalent on insiders and holdings. |
entity_ids_unresolved | list[int] | none | no | IDs that matched nothing. |
entity_ids_received_as | object | none | no | Prices only: whether each ID you sent was read as a security_id or an issuer_id. |
resolved_via and tickers_resolved_via take these values:
security_alias: the ticker matched a share class that carried it on the date, for exampleAAPL.issuer_alias: the ticker matched a company, and the API served its only trading share class, or its only trading common share class, for exampleBKandACGL.security_alias_censored: the company lists several share classes, and the answer is the class that itself last carried the ticker, for exampleVOOandLBTYA.last_holder: nothing carried the ticker on any date the API tried, so it served the last security that did, for exampleTWTRon a window after its delisting.
A candidate in tickers_ambiguous has entity_id, name, exchange, share_class, last_bar_date, valid_from and valid_to. This came from GET /v1/prices/BRK,AAPL?start=2026-09-25&end=2026-09-25&fields=close:
"tickers_requested": ["BRK", "AAPL"],
"tickers_resolved": {"AAPL": 10003635},
"tickers_unresolved": [],
"tickers_ambiguous": {
"BRK": [
{"entity_id": 10006133, "name": "BERKSHIRE HATHAWAY INC DEL", "exchange": "NYSE", "share_class": "A", "last_bar_date": "2026-09-25", "valid_from": null, "valid_to": null},
{"entity_id": 10025221, "name": "BERKSHIRE HATHAWAY INC DEL", "exchange": "NYSE", "share_class": "B", "last_bar_date": "2026-09-25", "valid_from": null, "valid_to": null}
]
},
"resolved_via": {"AAPL": "security_alias"}Where an ambiguous ticker is listed differs by endpoint:
- Prices lists it in
tickers_ambiguousonly. - Fundamentals lists a ticker that names more than one company in both
tickers_unresolvedandtickers_ambiguous. A ticker that names several share classes of one company, such asBRK, is served at the company level. - Metrics lists it in both
tickers_unresolvedandtickers_ambiguous. - Resolve lists it in
tickers_ambiguousand addsambiguous_hint.
Prices, fundamentals and metrics also name it in warnings. When every ticker in the request is ambiguous, prices, resolve and metrics return 409 ambiguous_ticker with the same candidates, and so does fundamentals for a ticker that names more than one company. See Errors.
An entity_id request reports IDs instead of tickers. This came from GET /v1/prices?entity_id=10003635,8611,999999999&start=2026-09-24&end=2026-09-25&fields=close&limit=2:
"tickers_requested": [],
"tickers_resolved": {},
"tickers_unresolved": [],
"entity_ids_requested": [10003635, 8611, 999999999],
"entity_ids_unresolved": [999999999],
"entity_ids_received_as": {"8611": "issuer_id", "10003635": "security_id"}A ticker served by an entity that no longer holds it carries historical_resolution. This came from GET /v1/prices/TWTR?start=2022-10-24&end=2022-11-30&fields=close:
"historical_resolution": {
"TWTR": {"entity_id": 10003373, "current_entity_id": null, "as_of": "2022-10-24"}
},
"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.",
"resolved_via": {"TWTR": "security_alias"}Resolve reports tickers whose company has nothing listed. This came from GET /v1/resolve/HES,AAPL?include=events:
"tickers_requested": ["HES", "AAPL"],
"tickers_resolved": ["HES", "AAPL"],
"tickers_unresolved": [],
"resolved_as_of": "2026-09-27",
"tickers_resolved_via": {"AAPL": "security_alias"},
"tickers_no_listed_security": {
"HES": {"issuer_entity_id": 315, "name": "HESS CORP"}
},
"tickers_past_holders_only": ["HES"],
"include": ["events"]Grain fields
entity_id names a share class (a security) on some endpoints and a company (an issuer) on others. Each response states which. Tickers and entities explains the difference.
| field | type | unit | nullable | description |
|---|---|---|---|---|
entity_id_grain | str | none | no | Prices, index constituents and index events: "security". Holdings: "security", "issuer" when a ticker was widened to every share class of a company, or "mixed". Resolve and search: a sentence, because the grain can differ row by row. |
entity_id_basis | str | none | no | Fundamentals and metrics: "issuer". |
entity_id_is | str | none | no | Insiders: "issuer". Holdings and manager holdings: "security", the grain of each row's entity_id. |
market_cap_basis | str | none | no | Metrics: "issuer_all_share_classes". Market capitalisation covers every common share class of the company. |
per_share_basis | str | none | no | Metrics: "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 Metrics. |
adj_close_basis | str | none | no | Prices: "split". adj_close is adjusted for splits, stock dividends and spin-offs, not for cash dividends. |
units | str | none | no | Fundamentals: "millions_usd" when every row on the page says currency USD and none carries field_currency, and "millions_reporting_currency" otherwise, where each money value is in millions of its row's currency or of the currency field_currency names for it. Metrics: "millions_usd", and money values in rows are in millions of USD. See Units and scales. |
On resolve and search, entity_id_grain reads:
"entity_id_grain": "per row: entity_grain='security' means entity_id is the share-class id; 'issuer' means no share class carries the ticker and entity_id is the issuer id""entity_id_grain": "security id where a share class matched; issuer id where only the issuer exists"Paging and counts
| field | type | unit | nullable | description |
|---|---|---|---|---|
count | int | rows | no | Rows in this response. Top-level on insiders, holdings, manager holdings and manager search. |
limit | int | rows | no | The page size applied. Prices, fundamentals, metrics and search. |
offset | int | rows | no | Search: the offset applied. |
total | int | rows | no | Search, index constituents and index events: rows matching the query across all pages. |
has_more | bool | none | no | Every paged endpoint: true when another page exists. On search, true while offset plus count is less than total. |
next_cursor | str | none | yes | Every cursor endpoint, in meta. Insiders, holdings, manager holdings and manager search also carry the same value at the top level. Pass it back as cursor to get the next page. null when there is no next page. |
data_through | str | date, YYYY-MM-DD | yes | Prices: the latest row date on this page. Fundamentals: the latest period_end on this page. Insiders: the latest filing_date on this page. Holdings and manager holdings: the latest report_date on this page. Index constituents: the newest entry or exit date on record for the index. |
latest_filing | str | date, YYYY-MM-DD | yes | Fundamentals: the latest filing_date on this page. |
interval | str | none | no | Prices: the bar interval applied, for example "1d". |
segments | list[object] | none | no | Prices: one {entity_id, entity_name, first_date, last_date} per security on this page. |
Pagination covers cursors and offsets.
Dataset and plan fields
| field | type | unit | nullable | description |
|---|---|---|---|---|
delisting | object | none | no | Prices: for a series whose last bar is on or before a recorded delisting, maps the entity_id to {event_date, event_type, delisting_return}. delisting_return is a decimal ratio, not a percentage. |
fields_not_available | list[str] | none | no | Fundamentals: field names you requested that the API accepts but does not return. Rows omit them. |
metrics_not_available | object | none | no | Metrics: requested metrics that are not returned, each mapped to the input fields it would need. |
view | str | none | no | Fundamentals: the effective view, "latest", "original" or "as_reported". |
include | list[str] | none | no | Resolve: the sections included. all expands to ["events", "index", "classifications"]. |
index | str | none | no | Index constituents and events: the index code, for example "SP500". |
coverage_end | str | date, YYYY-MM-DD | no | Index constituents and events: the last date the index's record covers. |
event_coverage_start | str | date, YYYY-MM-DD | no | Index events: the date the index's record opens. |
data_floor | str | date, YYYY-MM-DD | yes | Index events: the earliest date your plan can see. null on paid plans. |
archive_edge | str | date, YYYY-MM-DD | no | Holdings and manager holdings: the last report quarter answered by the historical era. |
era_fallback | bool | none | no | Holdings: true when a quarter the historical era covers was answered from Form 13F filings for a security the historical era does not hold. |
amendment_view | str | none | no | Insiders and holdings: "current" (the default), "all" (include_amendments=true) or "originals" (include_amendments=false). |
derivative_lines | str | none | no | Insiders: "excluded" (the default) or "included" (include_derivatives=true). |
uncoded_rows_excluded | int | rows | no | Insiders: archive-era rows in your window left out because they carry no SEC transaction code. include_uncoded=true returns them. |
unmapped_codes | int | rows | no | Insiders: archive-era rows on this page whose transaction_code is null. |
unlinked_filings_included | int | filings | no | Insiders: filings on this page matched to the company by the ticker stated on the filing. |
archive_era | object | none | yes | Insiders: {through, seam}. Rows dated through through come from the archive era; seam is the first day of the filing era. |
id_regimes | list[str] | none | no | Manager search: the manager ID spaces in the response, for example ["filing"]. |
restricted | bool | none | no | Resolve, top level: true when the request had no key. See Authentication. |
Free keys see one year of history on prices, fundamentals, metrics and index events. All four report the earliest date in the X-Data-Floor response header, and index events also report it in meta.data_floor. A Free request whose start or end falls before the floor also carries a warnings entry that says so. See Plans and limits.
"index": "SP500",
"event_coverage_start": "1925-12-31",
"entity_id_grain": "security",
"coverage_end": "2026-09-26",
"data_floor": "2025-09-27",
"count": 2,
"total": 46,
"has_more": trueThat is GET /v1/index/sp500/events?start=2020-01-01&limit=2 with a Free key. The same request with a Pro key returns "data_floor": null.
Insiders report era and filter state. This came from GET /v1/insiders/AAPL?start=2000-01-01&end=2000-12-31&limit=2:
"meta": {
"entity_id_is": "issuer",
"amendment_view": "current",
"derivative_lines": "excluded",
"uncoded_rows_excluded": 4,
"archive_era": {"through": "2005-11-30", "seam": "2005-12-01"},
"unmapped_codes": 0,
"unlinked_filings_included": 0,
...
}Prices report a delisting. This came from GET /v1/prices/TWTR?start=2022-10-24&end=2022-11-30&fields=close:
"delisting": {
"10003373": {"event_date": "2022-10-27", "event_type": "merger", "delisting_return": 0.009311}
}Response warnings
warnings is a list of plain-English strings. It appears when a parameter was ignored or reinterpreted, when a Free request reaches before the plan's one-year floor, and on manager search it states the search's coverage. A request with warnings still returns 200.
GET /v1/prices/TWTR?...&fields=close,fooreturns"warnings": ["Unknown field ignored: 'foo'"].GET /v1/prices/AAPL?start_date=2026-09-24returns"warnings": ["Unknown parameter ignored: 'start_date' (did you mean 'start'?)"].GET /v1/holdings/BRK?quarter=2020-12-31returns"warnings": ["BRK named more than one share class on that date; served at the company level"].- Every manager search returns
"warnings": ["Search covers managers that have filed Form 13F from 2013 onward. Managers that appear only in earlier quarters are not searchable by name; their holdings are served by id at /v1/managers/{manager_id}/holdings."].
Keys by endpoint
Keys marked "when present" appear only when they have something to report.
- Prices, in
meta:tickers_requested,tickers_resolved,tickers_unresolved,entity_id_grain,adj_close_basis,segments,interval,data_through,count,limit,has_more,next_cursor,knowledge_time,freshness,change_cursor; when presentresolved_via,as_of,tickers_ambiguous,historical_resolution,historical_resolution_note,entity_ids_requested,entity_ids_unresolved,entity_ids_received_as,delisting. - Fundamentals, in
meta:tickers_requested,tickers_resolved,tickers_unresolved,data_through,latest_filing,count,limit,has_more,next_cursor,units,entity_id_basis,view,knowledge_time,freshness,change_cursor; when presenttickers_resolved_via,tickers_ambiguous,historical_resolution,historical_resolution_note,entity_ids_requested,entity_ids_unresolved,fields_not_available,as_of. - Metrics, in
meta:tickers_requested,tickers_resolved,tickers_unresolved,count,limit,has_more,next_cursor,units,entity_id_basis,market_cap_basis,per_share_basis,knowledge_time,freshness,change_cursor; when presenttickers_resolved_via,historical_resolution,historical_resolution_note,entity_ids_requested,entity_ids_unresolved,metrics_not_available,as_of. - Resolve, in
meta:tickers_requested,tickers_resolved,tickers_unresolved,resolved_as_of,include,entity_id_grain,knowledge_time,freshness,change_cursor; when presenttickers_resolved_via,tickers_ambiguous,ambiguous_hint,tickers_no_listed_security,tickers_past_holders_only,as_of. - Search, in
meta:count,limit,offset,total,has_more,entity_id_grain,knowledge_time,freshness,change_cursor. - Index constituents, in
meta:index,as_of,data_through,entity_id_grain,coverage_end,count,total,has_more,knowledge_time,freshness,change_cursor. - Index events, in
meta:index,event_coverage_start,entity_id_grain,coverage_end,data_floor,count,total,has_more,knowledge_time,freshness,change_cursor; when presentas_of. - Insiders, in
meta:entity_id_is,amendment_view,derivative_lines,uncoded_rows_excluded,archive_era,unmapped_codes,unlinked_filings_included,knowledge_time,freshness,has_more,next_cursor,change_cursor; when presentas_of. - Holdings, in
meta:entity_id_is,entity_id_grain,archive_edge,amendment_view,era_fallback,knowledge_time,freshness,has_more,next_cursor,change_cursor; when presentas_of. - Manager holdings, in
meta:entity_id_is,archive_edge,amendment_view,knowledge_time,freshness,has_more,next_cursor,change_cursor; when presentas_of. - Manager search, in
meta:id_regimes,knowledge_time,freshness,has_more,next_cursor,change_cursor.
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.