Build with
Confidence

Financial data API for US equities.
Spend less time cleaning, more time researching.
14-day money-back guarantee on all plans.

REST API Python client MCP server

Get API key
Trusted by researchers at
National University of Singapore UCL Seoul National University Purdue University King's College London INSEAD University of York University of St.Gallen

Key Features.

Coverage & quality
81M+
Daily prices
47K+
Total entities
17K+
Delisted entities
50+ yrs
Of history
150+
Fundamental fields
110+
Pre-computed metrics
Survivorship-bias free
Full price history for every company that ever traded — including the ones that failed.
Entity resolution
Recycled tickers mapped to the right entity, so history never blends two companies.
Stable prices
Split-adjusted to the academic standard. The same date returns the same number, every pull.
Pre-computed metrics
Deep, audited financial ratios for professional use.
Insider & index data
Form 4 insider transactions, point-in-time index membership, and dated addition and removal events.
Institutional holdings
Quarterly 13F ownership for every US stock — who holds it, and every manager's full portfolio, back to 1978.
GICS classification
Every entity tagged to its GICS sector and industry, standardized.
Industry-aware fields
Banks get bank fields, REITs get REIT fields. If a field doesn't apply, it's null.
Revenue segments
Geographic and product revenue breakdowns for every company.
Standardized columns
Same field names, same units, every company — straight into pandas.
Plot-ready DataFrames
Tidy format, proper dtypes, parsed dates. No reshaping between API and chart.
AI-native over MCP
Connect any LLM agent over MCP — your AI gets the same clean data you do.
Point-in-time
Fundamentals available as originally reported and as restated.
Built-in scores
Altman Z, Piotroski F, Beneish M, plus 100+ valuation and profitability ratios.
Returns, both bases
Total return with dividends; split-adjusted prices for price-only return.

Endpoints.

Python · REST · MCP
EndpointGrainDescriptionCoverage
/pricesTicker-dateOHLCV, returns, splits, and dividends across history.30+ yrs
/fundamentalsEntity-periodStandardized filing statements and segments by period.50+ yrs
/metricsEntity-periodRatios, margins, growth, and valuation by period.30+ yrs
/insidersTransactionInsider transactions with roles, values, and ownership.30+ yrs
/holdingsManager-quarterQuarterly 13F institutional ownership for every US stock.45+ yrs
/managersFirmInstitutional manager lookup and full reported portfolios.45+ yrs
/resolveTicker spellTicker history, entities, classifications, index membership, and succession links.50+ yrs
/indexIndex-dateHistorical index membership, plus dated additions and removals.100+ yrs
/searchEntityCompany lookup by name, ticker, sector, or code.Current

Examples.

From the blog
Annualised return of one identical revenue-growth screen run on a point-in-time versus survivorship-contaminated S&P 500 universe
July 17, 2026/Index Research
How Much of a Growth Screen's Backtested Edge Is Survivorship Bias? Point-in-Time Index Testing in Python
Point-in-time versus contaminated S&P 500 universes running one identical revenue-growth screen from 2021 to 2026, measuring the survivorship premium in basis points per year.
Forward return comparison of months with multiple S&P 500 insider buyers versus a single buyer, 2015-2025
July 26, 2026/Insider Flows
Do Insider Buying Clusters Predict Returns? Signal Testing in Python
Testing whether multiple S&P 500 insiders buying in the same month beats a single buyer: 2,699 company-months, 2015-2025, and the cluster does slightly worse.
Average forward twelve-month total return by profitability quintile for S&P 500 members, comparing gross profit over assets against net income over assets, with one standard error whiskers
July 26, 2026/Profitability Analysis
Does Gross Profitability Predict Stock Returns? Quintile Factor Test in Python
Eleven annual quintile sorts on gross profit over assets in a point-in-time S&P 500 universe find no forward return premium: Q5 minus Q1 is -5.3pp, p 0.30.
Top-ten portfolio weight of index trackers and stock pickers from Form 13F filings since 2011
July 28, 2026/Portfolio Construction
How Concentrated Are Institutional Equity Portfolios? Form 13F Concentration Analysis in Python
Form 13F concentration analysis in Python: index trackers' top-ten weight doubled from 16.5% to 29.7% since 2011, and stock pickers concentrated harder.
Top-ten share of S&P 500 profit and revenue from fiscal 2010 to 2025 on point-in-time membership
August 2, 2026/Index Universe
How Concentrated Are S&P 500 Earnings? Point-in-Time Index Analysis in Python
The 10 largest S&P 500 earners took 23.4% of index profit in fiscal 2010 and 35.9% in 2025, while their share of revenue moved only from 21.8% to 25.4%.
Blog
Warmed up?

Factor backtests, survivorship-bias studies, insider-signal research, and runnable notebooks live on the blog.

Read in-depth examples
LIVE · RESOLVE

Try it.

> to resolve
GET /v1/resolve/
200 OK
DOCS

xfinlink documentation.

Install, query, done. Everything you need to integrate xfinlink into a research pipeline, trading system, or weekend project.

Quick start

Install the package, set your API key, and make your first query in under a minute.

terminal
pip install -U xfinlink

Create a free account to get your API key, then:

quickstart.py
import xfinlink as xfl

# Set your API key — get a free key at https://xfinlink.com/signup
xfl.set_api_key("YOUR_API_KEY")

# Historical prices
prices = xfl.prices("AAPL", start="2024-01-01")

# Financial statements
fundamentals = xfl.fundamentals("AAPL", period_type="annual")

# Pre-computed metrics (P/E, ROE, margins, ...)
metrics = xfl.metrics("AAPL", fields=["pe_ratio", "roe"])

# Index constituents
sp500 = xfl.index("sp500")

# Search for entities
results = xfl.search(q="apple")

# Entity resolution (handles ticker recycling)
entity = xfl.resolve("GM")

Use an API key via the X-API-Key header for full access (the Python client handles this automatically).

Authentication

Most API requests require an API key. Create a free account to get yours. Search and resolve allow restricted unauthenticated calls; use a key for normal limits and full detail.

Pass the key via the X-API-Key header:

curl
curl -H "X-API-Key: your-api-key" \
  https://api.xfinlink.com/v1/prices/AAPL?start=2024-01-01

The Python client handles auth automatically:

auth.py
import xfinlink as xfl

# Set your API key — get a free key at https://xfinlink.com/signup
xfl.set_api_key("YOUR_API_KEY")

Your API key is shown on the dashboard after sign-up. You can regenerate it at any time.

/v1/prices/{ticker}

Daily OHLCV prices with split adjustment, total returns, and dividend/split event data.

paramtypedefaultdescription
tickerstr | list[str]requiredTicker(s) to fetch.
startstr (ISO date)optionalEarliest date, inclusive.
endstr (ISO date)optionalLatest date, inclusive. Defaults to today.
fieldslist[str]optionalSubset of columns. Defaults to 11 fields; market_cap is opt-in.
adjuststr"split"Adjustment mode: split (default) or none.

Request:

request.py
df = xfl.prices("AAPL", start="2024-01-01", fields=["close", "volume"])

Response:

stdout
  date        ticker   close      volume
  2024-01-02  AAPL     185.64  45,123,456
  2024-01-03  AAPL     184.25  42,889,012
  2024-01-04  AAPL     181.91  49,301,234
  ...

/v1/fundamentals/{ticker}

Reported financials — income statement, balance sheet, cash flow — for most listed US companies.

paramtypedefaultdescription
tickerstr | list[str]requiredTicker(s) to fetch.
period_typestr"all""annual" | "quarterly" | "all"
fieldslist[str]optionalSubset of available fields.
includestroptional"segments" — adds revenue breakdowns by geography, product, and business segment.
segment_membersstr"primary""primary" or "all". Primary returns segments summing to revenue; all includes subtotals.
startstr (ISO date)optionalEarliest period_end.
endstr (ISO date)optionalLatest period_end.
fiscal_yearintoptionalExact-match filter on fiscal_year.
period_endstr (ISO date)optionalExact-match filter on period_end.
request.py
df = xfl.fundamentals("AAPL", period_type="annual",
                  fields=["revenue", "net_income"])

/v1/resolve/{ticker}

Full entity history for a ticker. Every company that ever used this ticker, with validity dates, classifications, and index membership.

paramtypedefaultdescription
tickerstrrequiredTicker symbol or comma-separated tickers (up to 10).
includestroptionalindex, classifications
request.py
info = xfl.resolve("GM")
for entity in info["data"]["GM"]["entities"]:
    print(entity["name"], entity["ticker_valid_from"], entity["ticker_valid_to"])

/v1/index/{index_name}

Current and historical index constituents. Available indices: sp500, ndx100, djia, russell2000.

paramtypedefaultdescription
index_namestrsp500Index name (path parameter).
as_ofstr (ISO date)todayPoint-in-time membership date.
limitint500Results per page (max 1000).
offsetint0Pagination offset.
request.py
df = xfl.index("sp500")
df = xfl.index("sp500", as_of="2020-01-01")

/v1/insiders/{ticker} Paid

Insider transactions from SEC Form 3, 4, and 5 filings. One row per transaction. Shares and prices are split-adjusted. Coverage 1996 to present. Available on all paid plans (Pro and above); free-tier keys receive 402.

paramtypedefaultdescription
tickerstrrequiredTicker or comma-separated tickers (up to 100).
startstr (ISO date)1y agoEarliest transaction_date.
endstr (ISO date)optionalLatest transaction_date.
transaction_typestroptionalDecoded type, e.g. open_market_buy, open_market_sell, grant_or_award, option_exercise, tax_withholding, gift. Comma-separated for multiple.
acquisition_or_dispositionstroptional"A" or "D".
ownership_typestroptional"direct" or "indirect".
form_typestroptional"3", "4", "5" (or amended e.g. "4/A").
insider_rolestroptionalSubstring match on role (CEO, CFO, Director, etc.).
insider_namestroptionalSubstring match on name.
min_valuenumoptionalMinimum transaction_value in dollars.
include_amendmentsboolfalseInclude amendment rows.
limitint1000Rows per page, max 5000.

Fields returned: entity_id, ticker, entity_name, transaction_date, filing_date, form_type, insider_name, insider_role, insider_role_other, transaction_code, transaction_type, acquisition_or_disposition, shares, shares_held_after, transaction_price, transaction_value, ownership_type, is_amendment, document_id, sequence_in_filing, data_quality.

request.py
df = xfl.insiders("TSLA", transaction_type="open_market_sell", insider_role="CEO")

/v1/metrics/{ticker}

Pre-computed financial metrics across multiple categories — valuation, profitability, leverage, liquidity, efficiency, per-share, dividends, financial scores, and growth. All ratios as decimals (0.46 = 46%). Market cap and enterprise value in millions USD. Per-share values in dollars.

paramtypedefaultdescription
tickerstrrequiredTicker or comma-separated tickers.
period_typestrannualannual or quarterly.
fieldsstrallComma-separated metric names.
startstr (ISO date)optionalStart date for period_end.
endstr (ISO date)optionalEnd date for period_end.
limitint20Rows per page.

Valuation: market_cap, market_cap_diluted, enterprise_value, pe_ratio, ps_ratio, pb_ratio, price_to_cash_flow, ev_ebitda, earnings_yield, dividend_yield

Profitability: gross_margin, operating_margin, net_margin, ebitda_margin, roe, roa, roic

Leverage: debt_to_equity, debt_to_assets, long_term_debt_to_equity, long_term_debt_to_assets, current_ratio, quick_ratio, interest_coverage

Efficiency: asset_turnover, inventory_turnover

Per-share ($/share): revenue_per_share, book_value_per_share, tangible_book_value_per_share, cash_per_share, debt_per_share, ocf_per_share, fcf_per_share, ebit_per_share, ebitda_per_share, capex_per_share, working_capital_per_share

request.py
df = xfl.metrics("AAPL", fields=["pe_ratio", "roe", "market_cap"])

Field reference

Data fields across every endpoint. See the Explorer on the home page for live values.

• /v1/fundamentals

INCOME STATEMENT (38)

revenuecost_of_revenuecost_of_goods_soldgross_profitresearch_and_developmentselling_general_adminselling_and_marketinggeneral_and_adminstock_based_compensationdepreciation_amortizationdepreciationamortization_intangiblesdepletionrestructuring_chargesimpairment_chargesprovision_for_credit_lossesgain_loss_on_sale_of_assetsother_operating_expensesoperating_expenses_totaloperating_incomeinterest_expenseinterest_incomeincome_from_equity_method_investmentsother_non_operating_incomepretax_incomeincome_tax_expenseincome_from_discontinued_operationsnet_incomeminority_interest_incomenet_income_attributable_to_parentpreferred_dividendsnet_income_available_to_commoncomprehensive_incomeebitebitdaeps_basiceps_diluteddividends_per_share

BALANCE SHEET — ASSETS (22)

cash_and_equivalentsrestricted_cashmarketable_securitiesshort_term_investmentscash_and_short_term_investmentsaccounts_receivablecontract_assetsinventoryprepaid_expensesother_current_assetscurrent_assets_totalproperty_plant_equipment_grossaccumulated_depreciationproperty_plant_equipment_netoperating_lease_assetsfinance_lease_assetslong_term_investmentsequity_method_investmentsgoodwillintangible_assetsdeferred_tax_assetsother_noncurrent_assetstotal_assets

BALANCE SHEET — LIABILITIES (19)

accounts_payableshort_term_debtcurrent_portion_long_term_debtoperating_lease_liabilities_currentfinance_lease_liabilities_currentdeferred_revenue_currentaccrued_liabilitiesother_current_liabilitiescurrent_liabilities_totallong_term_debtoperating_lease_liabilities_noncurrentfinance_lease_liabilities_noncurrentdeferred_revenue_noncurrentdeferred_tax_liabilitiespension_liabilitiesinsurance_loss_reservesother_noncurrent_liabilitiestotal_liabilitiestotal_debt

BALANCE SHEET — EQUITY (10)

common_stock_valuepreferred_equityadditional_paid_in_capitalretained_earningstreasury_stockaccumulated_other_comprehensive_incometemporary_equitytotal_equityminority_interesttotal_equity_including_minority

CASH FLOW (33)

net_income_cfdepreciation_amortization_cfstock_based_compensation_cfdeferred_income_taxeschange_in_accounts_receivablechange_in_inventorychange_in_accounts_payablechange_in_working_capitalother_operating_activitiesoperating_cash_flowcapital_expendituresacquisitions_netproceeds_from_divestiturespurchases_of_investmentssales_of_investmentsother_investing_activitiesinvesting_cash_flowlong_term_debt_issuancelong_term_debt_repaymentshort_term_debt_proceedsshort_term_debt_repaymentsfinance_lease_principal_paymentsshare_issuanceshare_repurchasesdividends_paiddividends_paid_commonother_financing_activitiesfinancing_cash_flowcash_taxes_paidcash_interest_paideffect_of_exchange_rate_on_cashnet_change_in_cashfree_cash_flow

SHARES & CLASSIFICATION (7)

shares_outstandingcommon_shares_issuedweighted_avg_shares_basicweighted_avg_shares_dilutedtreasury_sharessicnaics

INDUSTRY — BANKING (9) • INSURANCE (5) • REIT (3)

bank_interest_incomebank_interest_expensebank_net_interest_incomebank_noninterest_incomebank_noninterest_expensebank_loans_netbank_depositsbank_allowance_for_credit_lossesbank_net_charge_offsins_premiums_earnedins_losses_incurredins_underwriting_expenseins_net_investment_incomeins_policy_benefitsreit_rental_revenuereit_fforeit_affo
• /v1/prices
openhighlowcloseadj_closevolumereturn_dailyshares_outstandingexchange_codesplit_ratiodividendmarket_cap
• /v1/metrics
market_capmarket_cap_dilutedenterprise_valuepe_ratiops_ratiopb_ratioprice_to_cash_flowev_ebitdaearnings_yielddividend_yieldgross_marginoperating_marginnet_marginebitda_marginroeroaroicdebt_to_equitydebt_to_assetslong_term_debt_to_equitylong_term_debt_to_assetscurrent_ratioquick_ratiointerest_coverageasset_turnoverinventory_turnoverrevenue_per_sharebook_value_per_sharetangible_book_value_per_sharecash_per_sharedebt_per_shareocf_per_sharefcf_per_shareebit_per_shareebitda_per_sharecapex_per_shareworking_capital_per_share
• /v1/resolve
entity_idnameentity_typecountryfigicikticker_valid_fromticker_valid_tosic_codenaics_codegics_sectorgics_groupgics_industrygics_subindustryindex_membership
• /v1/insiders — 21 fields (Pro)
entity_identity_nametickertransaction_datefiling_dateform_typeinsider_nameinsider_roleinsider_role_othertransaction_codetransaction_typeacquisition_or_dispositionsharesshares_held_aftertransaction_pricetransaction_valueownership_typeis_amendmentdocument_idsequence_in_filingdata_quality

Understanding price fields

xfinlink follows the academic convention for price data. This matters for backtesting and returns analysis.

fielddescription
closeRaw unadjusted closing price — what actually traded on the exchange that day.
adj_closeSplit-only adjusted close. Adjusted for stock splits but NOT for dividends. Comparable across split events.
return_dailyTotal daily return including dividends. Use this for performance analysis and backtesting.
dividendCash dividend amount on ex-date. Zero on non-dividend days.
split_ratioSplit ratio on split date (e.g., 4.0 for a 4:1 split). 1.0 on non-split days.

Adjustment direction: adj_close is split-only backward-adjusted to the current post-split share basis. To derive a forward-adjusted series from an anchor date, request raw close plus split_ratio, then compound split ratios forward.

forward_adjusted.py
import xfinlink as xfl

df = xfl.prices("AAPL", start="2020-08-27", end="2020-09-02", fields=["close", "split_ratio"], adjust="none")
df = df.sort_values("date")

factor = df["split_ratio"].fillna(1.0).cumprod()
df["forward_adj_close"] = df["close"] * factor
stdout
date        ticker  close      split_ratio  forward_adj_close
2020-08-27  AAPL    500.04001  NaN          500.04001
2020-08-28  AAPL    499.23001  NaN          499.23001
2020-08-31  AAPL    129.03999  4.0          516.15996
2020-09-01  AAPL    134.17999  NaN          536.71996
2020-09-02  AAPL    131.39999  NaN          525.59996

Why no dividend-adjusted prices? Dividend-adjusted prices retroactively change every time a company pays a dividend, making historical values unstable. xfinlink stores stable values (split-only adjusted) plus total returns, which is the academic standard for quantitative research.

How to compute dividend-adjusted prices client-side:

div_adjusted.py
import xfinlink as xfl

df = xfl.prices("AAPL", start="2020-01-01", fields=["adj_close", "return_daily"])

# Build cumulative total return index
df["total_return_index"] = (1 + df["return_daily"]).cumprod()

# Derive dividend-adjusted price series
df["div_adj_close"] = df["adj_close"].iloc[-1] * df["total_return_index"] / df["total_return_index"].iloc[-1]

Data caveats

Price fields and fundamentals fields are on different split-adjustment bases.

adj_close is split-only adjusted (no dividend adjustment). All fundamentals per-share fields (eps_diluted, dividends_per_share) are as-reported with no split adjustment. Do not combine them for ratios (P/E, P/B, etc.) unless no split occurred between the reporting date and today.

Recipes

— Revenue comparison across big tech

compare.py
import xfinlink as xfl

df = xfl.fundamentals(
    ["AAPL", "MSFT", "GOOGL"],
    period_type="annual",
    fields=["revenue", "net_income", "operating_cash_flow"],
    start="2024-01-01",
)
print(df[["ticker", "period_end", "revenue", "net_income"]])

— AAPL cumulative return

backtest.py
import xfinlink as xfl

df = xfl.prices("AAPL", start="2024-01-01", end="2024-12-31")
df["cumulative_return"] = (1 + df["return_daily"]).cumprod() - 1
print(f"AAPL 2024 total return: {df['cumulative_return'].iloc[-1]:.1%}")

— Entity resolution: GM bankruptcy split

resolve.py
import xfinlink as xfl

info = xfl.resolve("GM")
for entity in info["data"]["GM"]["entities"]:
    print(f"{entity['name']}: {entity['ticker_valid_from']} → {entity['ticker_valid_to']}")
# General Motors Corporation (pre-2009 bankruptcy): 1962-07-02 → 2009-06-01
# General Motors Company: None → None (current)

Vibe coding

Path 1 — Code Generation

For developers with Python + IDE

  1. Get your API key (free)
  2. Install: pip install -U xfinlink
  3. Copy the context block below and paste it into Claude, ChatGPT, or Cursor as system context
  4. Describe what you want — the LLM writes working xfinlink code
context.md
Loading llms.txt…

Path 2 — Direct Access via MCP

Zero code — ask questions, get answers

  1. Get your API key (free)
  2. Pick your AI platform and connect using the server URL below
  3. Ask anything — “What’s AAPL’s P/E ratio?” or “Compare top 5 banks by ROE”

Server URL

MCP server URL
https://api.xfinlink.com/mcp?api_key=YOUR_API_KEY

Replace YOUR_API_KEY with your key from the dashboard.

Available tools: get_prices, get_fundamentals, get_metrics, resolve_ticker, search, get_index, get_index_events, get_insiders, get_holdings, get_manager_holdings, search_managers

Claude (Anthropic)

Option A — Web (claude.ai)

  1. Go to claude.ai and sign in
  2. Click your profile icon → SettingsConnectors
  3. Click + then Add custom connector
  4. Name: xfinlink, URL: https://api.xfinlink.com/mcp?api_key=YOUR_API_KEY
  5. Click Create
  6. Start a new chat and ask: “What’s NVDA’s P/E ratio?”

Available on Free (1 connector), Pro, Max, Team, and Enterprise plans.

Option B — Claude Desktop

  1. Open Claude Desktop → SettingsDeveloperEdit Config
  2. Add to claude_desktop_config.json:
claude_desktop_config.json
{
  "mcpServers": {
    "xfinlink": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://api.xfinlink.com/mcp?api_key=YOUR_API_KEY"]
    }
  }
}
  1. Restart Claude Desktop

ChatGPT (OpenAI)

Requires Plus, Pro, Team, Enterprise, or Edu plan.

  1. Open chatgpt.comSettingsApps & Connectors
  2. Scroll to Advanced Settings → toggle Developer Mode on
  3. Go back to Connectors → click Create
  4. Name: xfinlink, MCP server URL: https://api.xfinlink.com/mcp?api_key=YOUR_API_KEY, Authentication: None
  5. Click Create
  6. Start a new chat → click +MoreDeveloper ModeAdd sources → enable xfinlink
  7. Ask: “Compare AAPL and MSFT revenue growth over the past 3 years”

Grok (xAI)

Option A — Web (grok.com)

Requires a paid Grok account.

  1. Go to grok.comMenuConnectors
  2. Click Add custom connector
  3. Name: xfinlink, URL: https://api.xfinlink.com/mcp?api_key=YOUR_API_KEY
  4. Enable the connector per conversation
  5. Ask: “Screen the S&P 500 for stocks with P/E below 20”

Option B — xAI API (Developer)

python
from openai import OpenAI

client = OpenAI(
    api_key="your-xai-api-key",
    base_url="https://api.x.ai/v1",
)

response = client.responses.create(
    model="grok-4.20-reasoning",
    input=[{"role": "user", "content": "What's AAPL's quarterly revenue trend?"}],
    tools=[{
        "type": "mcp",
        "server_url": "https://api.xfinlink.com/mcp?api_key=YOUR_API_KEY",
        "server_label": "xfinlink",
    }],
)

Perplexity

Requires Pro, Max, or Enterprise plan.

  1. Go to perplexity.aiAccount SettingsConnectors
  2. Click + Custom connector → select Remote
  3. Name: xfinlink, MCP Server URL: https://api.xfinlink.com/mcp?api_key=YOUR_API_KEY, Authentication: None, Transport: Streamable HTTP
  4. Check acknowledgement box → click Add
  5. Click the xfinlink card to enable it
  6. In a new search, toggle xfinlink under Sources
  7. Ask: “What’s NVDA’s gross margin trend over the past 2 years?”

Cursor

Add to .cursor/mcp.json:

.cursor/mcp.json
{
  "mcpServers": {
    "xfinlink": {
      "url": "https://api.xfinlink.com/mcp?api_key=YOUR_API_KEY"
    }
  }
}

Rate limits & usage policy

RATE LIMITS

API key request limits: Free: 100/day, Pro: 10,000/day, Max: 50,000/day, Redistribution: 500,000/day.

Sign up to get your API key. View pricing for higher limits.