DOCS

Read the docs.

Seven endpoints. 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 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}

OHLCV prices with split adjustment, total returns, and dividend/split event data. Coverage back to 1996 for every US-listed stock and ETF. Supports daily through yearly aggregation intervals.

paramtypedefaultdescription
tickerstr | list[str]requiredTicker(s) to fetch.
startstr (ISO date)optionalEarliest date, inclusive.
endstr (ISO date)optionalLatest date, inclusive. Defaults to today.
intervalstr"1d"Aggregation interval: 1d, 3d, 1w, 1mo, 3mo, 6mo, 1y.
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 — back to 1950 for most listed US companies.

paramtypedefaultdescription
tickerstr | list[str]requiredTicker(s) to fetch.
period_typestr"all""annual" | "quarterly" | "all"
fieldslist[str]optionalSubset of 147 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 (e.g. 2023). Invalid values emit a warning and are ignored.
period_endstr (ISO date)optionalExact-match filter on period_end (e.g. 2023-09-30). Invalid values emit a warning and are ignored.
request.py
df = xfl.fundamentals("AAPL", period_type="annual",
                fields=["revenue", "net_income"])
# With revenue segments
df = xfl.fundamentals("AAPL", include_segments=True)

/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} Pro

Insider transactions from SEC Form 3, 4, and 5 filings. One row per transaction. Shares and prices are split-adjusted. Coverage 1986 to present. Pro tier only; 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}

37 pre-computed financial metrics derived from prices and fundamentals. 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.
periodstroptionalAlias of period_type. annual 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

230+ data fields across seven endpoints. See the Explorer on the home page for live values.

• /v1/fundamentals — 147 fields

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 (23)

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

Convention: as-filed. Share count fields are returned as the company reported them on the filing date — not retroactively split-adjusted. To derive split-adjusted shares for a period, multiply by the cumulative product of split_ratio from /v1/prices for all splits after period_end.

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 — 12 fields
openhighlowcloseadj_closevolumereturn_dailyshares_outstandingexchange_codesplit_ratiodividendmarket_cap
• /v1/metrics — 37 fields
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 — 15 fields
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 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_insiders

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 limits: Free: 100/day, Pro: 10,000/day.

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