Get startedDashboard

Authentication

Send your API key with each request, and know which endpoints answer without one.

View llms.txt

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-Key request header. Use this wherever you can.
  • The Authorization request header, as Bearer YOUR_API_KEY.
  • The api_key query 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.

Terminal
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"
response.json
{
  "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-Key first, then api_key, then Authorization, and ignores the others. A wrong key in the place read first returns 401 even 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 form Bearer YOUR_API_KEY. The word Bearer is not case-sensitive. Any other value in Authorization is not read as a key, and an endpoint that needs a key returns 401 with a message that names the Authorization header.
  • The key is sent exactly as the dashboard shows it, with no quotes or spaces. In X-API-Key and api_key it has no prefix.

Python client

The client sends your key in the X-API-Key header. It looks for a key in this order:

  1. The value passed to xfl.set_api_key().
  2. The XFINLINK_API_KEY environment variable.
  3. The XFL_API_KEY environment variable.
request.py
import xfinlink as xfl

xfl.set_api_key("YOUR_API_KEY")
Terminal
export XFINLINK_API_KEY=YOUR_API_KEY

With 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.

stdout
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/signup

MCP 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.

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

The 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:

response.json
{"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/status never needs a key. The response is the same with or without one. See Status and freshness.
  • GET /v1/search returns 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.

Terminal
curl "https://api.xfinlink.com/v1/resolve/MSFT"
response.json
{
  "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.

Terminal
curl -H "X-API-Key: YOUR_API_KEY" "https://api.xfinlink.com/v1/resolve/MSFT"
response.json
{
  "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

statuserror codewhen it happenshow to fix
401unauthorizedAn endpoint that needs a key got no key.Send your key in X-API-Key.
401unauthorizedThe 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.
401unauthorizedThe 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.
401unauthorizedAuthorization 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.
401unauthorizedThe key has been revoked.Use a current key from the dashboard.
401unauthorizedThe key is well-formed but the API does not recognise it.Copy your current key from the dashboard.
403account_disabledThe 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:

response.json
{
  "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?