Authentication
Send your API key with each request, and know which endpoints answer without one.
Requests to data endpoints need your API key. This page shows the three places the API reads it from, what happens without a key, and the responses you get when a key is missing or not accepted.
Get a key
Create a free account at https://xfinlink.com/signup. No card is needed for Free. The dashboard at https://xfinlink.com/dashboard creates your first key and shows it with a copy button.
A key is xfl_ followed by 32 lowercase hexadecimal characters (0 to 9 and a to f), 36 characters in all. Treat it like a password. Anyone who holds it can spend your plan's quota.
Use an invitation code
If you received an invitation for one free month (30 days), create your Free account first. In the dashboard's Plan & billing section, open Have an invitation code?, choose Pro or Max and monthly or yearly billing, and enter the code before continuing to checkout. The invitation field is in the xfinlink dashboard, not Stripe's promotion-code field. Each invitation can be redeemed once; its redeem-by date is stated in the invitation.
Nothing is charged during the free period. After it ends, monthly billing charges the monthly price, or yearly billing charges the full annual price for the next twelve months. Checkout shows the amount and first payment date. You can change between monthly and yearly billing through Manage billing during the invitation trial without shortening the free period, or cancel before it ends and pay nothing.
Invitation trials apply only to Pro and Max. Ordinary Stripe promotion codes remain monthly-only. Earlier three-month research discounts keep their original terms, including disabled plan changes while the discount is active.
Send the key
The API reads the key from one of three places.
- The
X-API-Keyrequest header. Use this wherever you can. - The
Authorizationrequest header, asBearer YOUR_API_KEY. - The
api_keyquery parameter. Use this only where you cannot set headers, for example in an MCP server URL.
All three return the same response, under the same account and plan limits.
curl -H "X-API-Key: YOUR_API_KEY" \
"https://api.xfinlink.com/v1/prices/MSFT?start=2026-09-25&end=2026-09-25&fields=close"
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://api.xfinlink.com/v1/prices/MSFT?start=2026-09-25&end=2026-09-25&fields=close"
curl "https://api.xfinlink.com/v1/prices/MSFT?start=2026-09-25&end=2026-09-25&fields=close&api_key=YOUR_API_KEY"{
"data": [
{
"entity_id": 10000086,
"ticker": "MSFT",
"entity_name": "MICROSOFT CORP",
"gics_sector": "Information Technology",
"date": "2026-09-25",
"close": 516.17,
"price_basis": "trade"
}
],
"meta": {
"tickers_requested": ["MSFT"],
"tickers_resolved": {"MSFT": 10000086},
...
"count": 1,
...
}
}A query string can end up in server logs, browser history and shared links, so prefer a header.
Rules that apply to all three:
- When a request carries a key in more than one place, the API reads
X-API-Keyfirst, thenapi_key, thenAuthorization, and ignores the others. A wrong key in the place read first returns401even when a later place holds a valid one. An empty header or parameter is treated as absent. - In
Authorization, a key is read only in the formBearer YOUR_API_KEY. The wordBeareris not case-sensitive. Any other value inAuthorizationis not read as a key, and an endpoint that needs a key returns401with amessagethat names theAuthorizationheader. - The key is sent exactly as the dashboard shows it, with no quotes or spaces. In
X-API-Keyandapi_keyit has no prefix.
Python client
The client sends your key in the X-API-Key header. It looks for a key in this order:
- The value passed to
xfl.set_api_key(). - The
XFINLINK_API_KEYenvironment variable. - The
XFL_API_KEYenvironment variable.
import xfinlink as xfl
xfl.set_api_key("YOUR_API_KEY")export XFINLINK_API_KEY=YOUR_API_KEYWith no key set, a call that needs a key raises XfinlinkError without sending a request. A key with characters outside ASCII, such as the masked key text on the dashboard, does the same. If the API returns 401 or 403, the client raises XfinlinkError with the API's message for the cause.
xfinlink.client.XfinlinkError: xfinlink: No API key set. Fix: call xfl.set_api_key('your_key') at the top of your script. Get a free key at https://xfinlink.com/signupMCP server
The MCP server at https://api.xfinlink.com/mcp accepts the key in the same three places: the api_key query parameter, the X-API-Key header or the Authorization header as Bearer YOUR_API_KEY. Most AI clients only let you enter a URL, so put the key in the URL.
https://api.xfinlink.com/mcp?api_key=YOUR_API_KEYThe MCP server needs a key. Without one, it answers with HTTP 200 and a JSON-RPC error with code -32000. id repeats the request's id and is left out when the request has none. This is the answer to an initialize request with "id": 1:
{"jsonrpc":"2.0","id":1,"error":{"code":-32000,"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"}}Any other refused key gets the same error code, with the message the REST API gives for that cause.
Endpoints that need no key
Three endpoints answer without a key. Every other endpoint returns 401 without one.
GET /v1/statusnever needs a key. The response is the same with or without one. See Status and freshness.GET /v1/searchreturns the same response with or without a valid key.GET /v1/resolve/{ticker}without a key returns a restricted body.
A restricted resolve body carries "restricted": true and leaves out ticker_valid_from, ticker_valid_to, classifications and index_membership. Its meta.freshness lists only the datasets it used. Succession links (succession) are returned with or without a key.
curl "https://api.xfinlink.com/v1/resolve/MSFT"{
"data": {
"MSFT": {
"entities": [
{
"entity_id": 10000086,
"name": "MICROSOFT CORP",
"entity_type": "corporation",
"country": "US",
"figi": "BBG000BPH459",
"cik": "0000789019",
"entity_grain": "security",
"issuer_entity_id": 8611,
"share_class": null,
"instrument_type": "common",
"exchange": "NASDAQ"
}
]
}
},
"meta": {
"tickers_requested": ["MSFT"],
"tickers_resolved": ["MSFT"],
"tickers_unresolved": [],
"resolved_as_of": "2026-09-27",
...
},
"restricted": true
}With any valid key, including a Free key, the same request returns the full entity.
curl -H "X-API-Key: YOUR_API_KEY" "https://api.xfinlink.com/v1/resolve/MSFT"{
"data": {
"MSFT": {
"entities": [
{
"entity_id": 10000086,
"name": "MICROSOFT CORP",
...
"exchange": "NASDAQ",
"ticker_valid_from": "1986-03-13",
"ticker_valid_to": null,
"classifications": {
"sic_code": "7372",
"naics_code": "513210",
"gics_sector": "Information Technology",
"gics_group": "Software & Services",
...
"classification_as_of": "2026-09-18"
},
"index_membership": [
{"index": "DJIA", "index_name": "Dow Jones Industrial Average", "added": "1999-11-01", "removed": null},
...,
{"index": "SP500", "index_name": "S&P 500", "added": "1994-06-07", "removed": null}
]
}
]
}
},
"meta": {...}
}On resolve and search, a key that is sent is still checked: a value in X-API-Key or api_key that is incomplete, revoked or unrecognised returns 401, as does a revoked or unrecognised key sent as Authorization: Bearer. A request with no key, with a key under another header or parameter name, or with any other Authorization value, is answered as a keyless request.
Requests without a key are limited per IP address to 40 requests per clock hour and 100 per UTC day. Their responses carry X-RateLimit-Limit-Day: 100 and X-RateLimit-Limit-Hour: 40. See Rate limits.
Errors
| status | error code | when it happens | how to fix |
|---|---|---|---|
401 | unauthorized | An endpoint that needs a key got no key. | Send your key in X-API-Key. |
401 | unauthorized | The key was sent under another name: the api-key, apikey, x-api-token or token header, or the apikey, key, token or access_token query parameter. | Send it in X-API-Key or as Authorization: Bearer, or in api_key where headers cannot be set. |
401 | unauthorized | The value sent in X-API-Key or api_key is not xfl_ followed by 32 lowercase hexadecimal characters, for example a partial copy, a quoted key or a Bearer prefix. | Copy the key again with the copy button on the dashboard. |
401 | unauthorized | Authorization holds something other than Bearer followed by a complete key, for example a key without Bearer, a partial copy or a quoted key. | Send Authorization: Bearer YOUR_API_KEY, or send the key in X-API-Key. |
401 | unauthorized | The key has been revoked. | Use a current key from the dashboard. |
401 | unauthorized | The key is well-formed but the API does not recognise it. | Copy your current key from the dashboard. |
403 | account_disabled | The account is disabled. Body: {"error":"Account temporarily disabled. Contact hello@xfinlink.com","code":"account_disabled","status":403,"detail":"Account temporarily disabled. Contact hello@xfinlink.com","message":"Account temporarily disabled. Contact hello@xfinlink.com"}. | Contact hello@xfinlink.com. |
Every 401 body has error and code set to unauthorized, status 401, and a detail that names the cause and the fix; message repeats detail. Without a key:
{
"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"
}Errors shows the message for each cause.
Keys per account
An account can hold 1 active key on Free, 1 on Pro, 5 on Max and 10 on Redistribution. All keys on an account share one set of quotas: requests, rows and index snapshots are counted per account, not per key.
Keys are managed on the dashboard. On Free and Pro, Regenerate revokes the current key and issues a new one. On Max and Redistribution, Create key adds a key up to the plan's limit, and Revoke removes one. A revoked key stops working and returns 401 with a message that gives the date it was revoked.
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.