# llms.txt Source: https://docs.financialdatapi.com/ai-agents/llms-txt The keyless, self-describing text indexes an agent reads to discover the Financial Data API. Financial Data API publishes two plain-text artifacts that describe the entire API in a form an LLM agent can read directly: a compact index at `GET /llms.txt` and the full reference at `GET /llms-full.txt`. Both are generated from the same OpenAPI 3.1 document the API serves, so they never drift from the live surface. Neither needs an API key. An agent can fetch one cold, learn the endpoints and conventions, then start making authenticated calls. `GET /llms.txt`, `GET /llms-full.txt`, and `GET /openapi.json` are all keyless, alongside `GET /health` and `GET /ready`. ## The two files A compact, sectioned index. A short preamble (base URL, auth, envelope, error codes, pagination, time model) followed by one line per endpoint grouped into sections such as "Public data (redistribution-safe)", "Observations & provenance", and "Calendar & official events". Start here to learn the surface quickly. The full endpoint reference. Same preamble, then every endpoint with its summary, description, and parameters (types, enums, formats, and whether each is a path or query parameter). Use this when an agent needs to construct a call precisely. ## What the preamble tells an agent Both files open with the same machine-readable conventions, so an agent gets the contract before it sees a single endpoint: * **Base URL** and **version** (`v1`). * **Auth.** Send `x-api-key: ` or `Authorization: Bearer `. Scopes are `data:read`, `ops:read`, `admin`. The keyless endpoints are listed explicitly. * **Envelope.** `{ data, meta: { request_id, api_version, pagination }, requestId }`, with the error shape and the stable codes (`bad_request`, `not_found`, `unauthorized`, `forbidden`, `rate_limited`, `internal_error`). It states plainly that unknown query params are rejected with `bad_request`. * **Pagination.** Cursor-based: `limit` (1 to 500, default 100) and `cursor`, with `meta.pagination.next_cursor` and `has_more`. * **Time model.** How `period` / `period_start` / `period_end`, `start_date` / `end_date`, and `as_of` differ. * **Read-only.** Every endpoint is `GET`. ## Fetch them ```bash cURL theme={"theme":"css-variables"} # Compact index (no key required) curl "https://api.financialdatapi.com/llms.txt" # Full reference with parameters (no key required) curl "https://api.financialdatapi.com/llms-full.txt" ``` ```python Python theme={"theme":"css-variables"} import requests BASE = "https://api.financialdatapi.com" index = requests.get(f"{BASE}/llms.txt").text full = requests.get(f"{BASE}/llms-full.txt").text print(index[:500]) ``` ```typescript TypeScript theme={"theme":"css-variables"} const BASE = "https://api.financialdatapi.com"; const index = await (await fetch(`${BASE}/llms.txt`)).text(); const full = await (await fetch(`${BASE}/llms-full.txt`)).text(); ``` ## How an agent uses them Fetch `/llms.txt` to read the conventions and scan the endpoint index. This is enough to choose the right endpoint for a question (for example, `/observations/latest` for the latest reading, or `/screener` to filter countries). Fetch `/llms-full.txt` (or `/openapi.json` for the structured spec) to read the exact parameters, types, and enums for the chosen endpoint, then build a valid request. Because unknown params are rejected, getting names right up front avoids a `bad_request`. Make the authenticated request with your key. The response is the standard envelope. For list endpoints, follow `meta.pagination.next_cursor` while `has_more` is `true`. For programmatic consumers (Postman, Insomnia, code generators, or your own tooling), the structured OpenAPI 3.1 document at `GET /openapi.json` is the canonical source the text files are projected from. Use the text files for agents that read prose, and the OpenAPI document for machine import. ## Related Skip the manual HTTP and give your agent native tools instead. A typed client over the same envelope and errors. # MCP server Source: https://docs.financialdatapi.com/ai-agents/mcp-server Financial Data API's native Model Context Protocol server: read-only macro tools for Claude Code, Claude Desktop, and Cursor. Financial Data API ships a native [Model Context Protocol](https://modelcontextprotocol.io) server that exposes the public API as agent tools. Add it to Claude Code, Claude Desktop, or Cursor and your agent can query official-source macro indicators, rates, FX reference rates, the economic calendar, and derived analytics conversationally, with no glue code. The server is read-only by design: every tool maps to a `GET` endpoint on the Financial Data API HTTP API and returns the raw JSON envelope as text, so the agent sees `data`, `meta`, and `requestId` and can follow `next_cursor` for pagination itself. Transport is stdio. The server's `stdout` is reserved for the MCP protocol; it logs only to `stderr`. You do not need to interact with this directly, but it is why the server is launched as a long-running subprocess by your agent host. ## Read-only tools | Tool | What it does | | ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | | `screen_macro` | Screen countries by macro indicator values using the `filter` DSL (`field:operator:value`, AND-ed). | | `screen_equities` | Screen the scored US equity universe by valuation multiples, financial ratios, and price analytics using the same `filter` DSL. | | `insider_trades` | SEC Forms 3/4/5 insider transactions for a company, by ticker, CIK, or entity id. Also available over REST as `GET /companies/{idOrLookup}/insider-trades`. | | `institutional_holdings` | Quarterly SEC 13F holdings for 25 headline institutional filers, ticker- or filer-centric. | | `get_latest_observations` | Get the latest public observation per canonical indicator, optionally scoped to one country. | | `cross_country` | Cross-country macro differentials for a scope or country versus its peer basket. | | `rates_analytics` | Rates analytics (real rate, curve spread, policy-cycle position) for a scope or country. | | `observation_provenance` | The provenance (source, raw payload metadata, ingestion evidence) for a single observation by id. | The server also exposes supporting tools: `list_indicators`, `list_countries`, `country_indicators`, `get_observations`, `screener_fields` (discover macro screener fields and operators), `equity_screener_fields` (discover equity screener fields and operators), `economic_calendar`, `official_events`, `source_health`, and `resolve_entity` (resolve a country, company, or instrument by alias such as a ticker or ISO code). Tell your agent to call `screener_fields` before `screen_macro`, and `equity_screener_fields` before `screen_equities`. Each returns the screenable field slugs, the operators (`gt`, `lt`, `gte`, `lte`, `eq`, `in`), and the DSL syntax, so the agent builds a valid filter instead of guessing field names. ## Build the server Build once to emit the runnable entry point at `mcp/dist/index.js`. ```bash npm theme={"theme":"css-variables"} cd mcp npm install npm run build # emits dist/index.js ``` ## Add it to your agent Register the server with the `claude mcp add` command, passing your key via `--env` and the built entry point after the `--` separator. Use an absolute path. ```bash theme={"theme":"css-variables"} claude mcp add financialdatapi \ --env FINANCIALDATA_API_KEY=your_key_here \ -- node /absolute/path/to/financialdatapi/mcp/dist/index.js ``` Everything after `--` is the launch command for the server. The `FINANCIALDATA_API_KEY` value is sent as `x-api-key` on every request. Add a `financialdatapi` entry to the `mcpServers` block in `claude_desktop_config.json`, then restart Claude Desktop. ```json theme={"theme":"css-variables"} { "mcpServers": { "financialdatapi": { "command": "node", "args": ["/absolute/path/to/financialdatapi/mcp/dist/index.js"], "env": { "FINANCIALDATA_API_BASE_URL": "https://api.financialdatapi.com", "FINANCIALDATA_API_KEY": "your_key_here" } } } } ``` Add the same `mcpServers` block to `~/.cursor/mcp.json`. ```json theme={"theme":"css-variables"} { "mcpServers": { "financialdatapi": { "command": "node", "args": ["/absolute/path/to/financialdatapi/mcp/dist/index.js"], "env": { "FINANCIALDATA_API_KEY": "your_key_here" } } } } ``` Ask your agent something macro and let it pick the tool, for example: "Which countries have CPI inflation above 3% and unemployment below 5%?" The agent will call `screener_fields`, then `screen_macro` with `filter=cpi_inflation_yoy:gt:3,unemployment_rate:lt:5`, and read the result envelope directly. ## Configuration | Env var | Default | Notes | | ---------------------------- | --------------------------------- | ------------------------------------------------------------ | | `FINANCIALDATA_API_BASE_URL` | `https://api.financialdatapi.com` | Financial Data API base URL. | | `FINANCIALDATA_API_KEY` | *(unset)* | Sent as `x-api-key` when present. Production requires a key. | During development you can run the server without building it with `npm run dev` from the `mcp/` directory. It uses `tsx` and runs the TypeScript source directly. For agent hosts, prefer the built `dist/index.js`. ## How errors surface Because each tool returns the raw HTTP result, an agent sees Financial Data API's stable error codes verbatim. A request that fails validation returns a `bad_request` body (for example, an unknown query parameter, which Financial Data API rejects rather than ignores), and a missing or insufficient key returns `unauthorized` or `forbidden`. The agent can read `error.code` and adjust, rather than retrying blindly. # Financial Data API for AI agents Source: https://docs.financialdatapi.com/ai-agents/overview Why Financial Data API is agent-native, and the three ways an agent consumes it. Financial Data API is macro and global-markets data infrastructure built to be read and called by LLM agents, not only by humans. It serves official and public-domain macro indicators, rates and yields, FX reference rates, the economic calendar, SEC fundamentals, and derived analytics as predictable JSON, with per-observation provenance and rights metadata. Every endpoint is read-only and `GET`. Every response shares one envelope. Every error carries a stable, machine-readable code. That consistency is what makes an agent reliable against the API: it never has to guess the shape of a response or parse free-form error prose. ## Why Financial Data API is agent-native Every response is `{ data, meta, requestId }`. Lists carry `meta.pagination`. An agent learns the shape once and reuses it across every endpoint. Errors return a machine-readable `code` (`bad_request`, `unauthorized`, `forbidden`, `not_found`, `rate_limited`, `internal_error`) plus a `requestId`. Unknown query params fail closed with `bad_request` rather than being silently ignored, so a typo surfaces instead of returning wrong data. `GET /llms.txt` and `GET /llms-full.txt` describe the entire API as plain text an agent can read with no key. `GET /openapi.json` is the OpenAPI 3.1 source of truth. Observations carry source attribution, source URL, freshness, a raw payload reference, and rights metadata. `GET /v1/provenance/observations/{observationId}` returns the full chain from official release to API response, so an agent can cite where a number came from. ## The three ways an agent consumes Financial Data API The Financial Data API Model Context Protocol server exposes the API as read-only tools (`screen_macro`, `get_latest_observations`, `cross_country`, `rates_analytics`, `observation_provenance`, and more). Add it to Claude Code, Claude Desktop, or Cursor and your agent can query macro data conversationally with no glue code. This is the lowest-friction path for a chat-driven agent. Point an agent at `/llms.txt` for a compact, sectioned index of every endpoint, or `/llms-full.txt` for the full reference with parameters. Both need no API key and stay in lock-step with the OpenAPI spec. An agent can fetch one, learn the surface, then call endpoints directly with HTTP. The `@financialdatapi/client` TypeScript SDK wraps the same envelope and errors. It constructs with your `apiKey`, throws a typed `FinancialDataApiError` on non-2xx, auto-paginates cursor pages via an async iterator, and ships a `buildScreenerFilter` helper for the screener DSL. Use it when your agent runs inside a TypeScript or JavaScript runtime. ## Base URL and auth All paths are relative to `https://api.financialdatapi.com`. Send your key as `x-api-key: ` or `Authorization: Bearer `. The following endpoints need no key: `GET /health`, `GET /ready`, `GET /openapi.json`, `GET /llms.txt`, `GET /llms-full.txt`. Everything under `/v1` requires a key. Create an API key at [app.financialdatapi.com](https://app.financialdatapi.com): sign up, verify your email, and it is active immediately, with no card required. Keys are SHA-256 hashed server-side and never returned. ## Conventions an agent should know * **Envelope.** Lists return `{ "data": [...], "meta": { "request_id", "requestId", "api_version", "pagination" }, "requestId" }`. Items return `{ "data": { ... }, "meta": { ... }, "requestId" }`. * **Pagination.** Cursor-based: `limit` (1 to 500, default 100) and an opaque `cursor`. Follow `meta.pagination.next_cursor` while `has_more` is `true`. * **Time model.** `period` / `period_start` / `period_end` filter the period a value describes (for example May 2026 CPI). `start_date` / `end_date` filter knowledge-time (`observed_at`, when the value became known). `as_of` returns the latest vintage known on or before a timestamp; revisions are retained, never overwritten. * **Rights-aware.** `/v1/public/*` returns only redistribution-safe official and public-domain data. Licensed vendor data is internal-only and never appears on the public surface. * **Read-only.** Every endpoint is `GET`. `as_of` currently approximates the ingestion timestamp, not a full provider-vintage reconstruction. Full vintage reconstruction is future work. Treat `as_of` as "known to Financial Data API on or before this time" rather than "published by the provider on or before this time". ## Latest readings in one call ```bash cURL theme={"theme":"css-variables"} curl "https://api.financialdatapi.com/v1/public/observations/latest?country=USA" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` ```python Python theme={"theme":"css-variables"} import requests BASE = "https://api.financialdatapi.com" res = requests.get( f"{BASE}/v1/public/observations/latest", params={"country": "USA"}, headers={"x-api-key": "your_key_here"}, ) res.raise_for_status() print(res.json()["data"]) ``` ```typescript TypeScript theme={"theme":"css-variables"} import { FinancialDataApiClient } from "@financialdatapi/client"; const financialdatapi = new FinancialDataApiClient({ apiKey: process.env.FINANCIALDATA_API_KEY }); const { data } = await financialdatapi.getLatestObservations({ country: "USA" }); console.log(data); ``` To see the live breadth of what is covered (catalog totals, public indicator categories, covered countries), call `GET /v1/public/coverage` rather than relying on a number hard-coded in docs. ## Next steps Add Financial Data API's read-only tools to Claude Code, Claude Desktop, or Cursor. The keyless, self-describing indexes an agent reads to discover the API. # Get Company Source: https://docs.financialdatapi.com/api-reference/get-company GET /v1/companies/{idOrLookup} # Get Company Financials Source: https://docs.financialdatapi.com/api-reference/get-company-financials GET /v1/companies/{idOrLookup}/financials # Get Company Profile Source: https://docs.financialdatapi.com/api-reference/get-company-profile GET /v1/companies/{idOrLookup}/profile # Get Country Source: https://docs.financialdatapi.com/api-reference/get-country GET /v1/countries/{idOrIso} # Get Coverage Summary Source: https://docs.financialdatapi.com/api-reference/get-coverage-summary GET /v1/public/coverage # Get Derived Indicator Source: https://docs.financialdatapi.com/api-reference/get-derived-indicator GET /v1/derived-indicators/{idOrSlug} # Get Economic Calendar Event Source: https://docs.financialdatapi.com/api-reference/get-economic-calendar-event GET /v1/economic-calendar/{eventId} # Get Entity Source: https://docs.financialdatapi.com/api-reference/get-entity GET /v1/entities/{idOrSlug} # Get Indicator Source: https://docs.financialdatapi.com/api-reference/get-indicator GET /v1/indicators/{idOrSlug} # Get Instrument Source: https://docs.financialdatapi.com/api-reference/get-instrument GET /v1/instruments/{idOrLookup} # Get Observation Provenance Source: https://docs.financialdatapi.com/api-reference/get-observation-provenance GET /v1/provenance/observations/{observationId} # Get Official Event Source: https://docs.financialdatapi.com/api-reference/get-official-event GET /v1/events/{eventId} # Get Provider Source: https://docs.financialdatapi.com/api-reference/get-provider GET /v1/providers/{providerId} # Get Source Source: https://docs.financialdatapi.com/api-reference/get-source GET /v1/sources/{sourceId} # Get Sync Manifest Source: https://docs.financialdatapi.com/api-reference/get-sync-manifest GET /v1/manifest # Get Sync Snapshot Source: https://docs.financialdatapi.com/api-reference/get-sync-snapshot GET /v1/snapshot # Health Check Source: https://docs.financialdatapi.com/api-reference/health-check GET /health # API Reference Source: https://docs.financialdatapi.com/api-reference/introduction Auto-generated endpoint reference for the Financial Data API, built from the live OpenAPI spec. Every page in this section is generated from Financial Data API's OpenAPI spec. Each endpoint page shows its path, method, parameters, request scopes, and response schema directly from the source of truth, so the reference never drifts from the running service. The reference is built from [`openapi.json`](/api-reference/openapi.json). If an endpoint, parameter, or field appears in the spec, it is live. If it does not appear there, it is not part of the public contract. ## Base URL All paths are relative to a single host. ``` https://api.financialdatapi.com ``` Endpoints use clean, versionless paths (for example `/observations/latest`), and every response reports `meta.api_version = "v1"`. The legacy `/v1/...` paths remain available as aliases. Financial Data API is read-only and GET-only. ## Authentication Send your API key on every data request. Two header forms are accepted. ```bash x-api-key header theme={"theme":"css-variables"} curl https://api.financialdatapi.com/observations/latest \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` ```bash Authorization header theme={"theme":"css-variables"} curl https://api.financialdatapi.com/observations/latest \ -H "Authorization: Bearer $FINANCIALDATA_API_KEY" ``` A small set of routes need no key: `GET /health`, `GET /ready`, `GET /openapi.json`, `GET /llms.txt`, and `GET /llms-full.txt`. Keys carry scopes. Most product and data routes require `data:read`. Operational routes require `ops:read`. Sensitive admin routes require `admin`, which also satisfies the lower scopes. A key without the required scope returns `403 forbidden`. Keys are issued on request today. There is no self-serve signup form yet. See [Support](/support) to request access. Keys are hashed server-side and are never returned, so store yours securely when issued. ## The response envelope Every response shares one shape, so you can write parsing once and reuse it everywhere. List responses wrap an array in `data` and carry pagination in `meta.pagination`. Item responses wrap a single object in `data`. Errors carry a stable machine-readable `code`. The `request_id` (also mirrored as top-level `requestId`) identifies the exact request and is what you quote when you contact support. ```json List response theme={"theme":"css-variables"} { "data": [ /* ... */ ], "meta": { "request_id": "8f1c0e2a-6b3d-4f0a-9c11-1d2e3f4a5b6c", "requestId": "8f1c0e2a-6b3d-4f0a-9c11-1d2e3f4a5b6c", "api_version": "v1", "pagination": { "limit": 100, "cursor": null, "next_cursor": null, "has_more": false } }, "requestId": "8f1c0e2a-6b3d-4f0a-9c11-1d2e3f4a5b6c" } ``` ```json Item response theme={"theme":"css-variables"} { "data": { /* ... */ }, "meta": { "request_id": "8f1c0e2a-6b3d-4f0a-9c11-1d2e3f4a5b6c", "requestId": "8f1c0e2a-6b3d-4f0a-9c11-1d2e3f4a5b6c", "api_version": "v1" }, "requestId": "8f1c0e2a-6b3d-4f0a-9c11-1d2e3f4a5b6c" } ``` ```json Error response theme={"theme":"css-variables"} { "error": { "code": "bad_request", "message": "Unknown query parameter: foo", "request_id": "8f1c0e2a-6b3d-4f0a-9c11-1d2e3f4a5b6c", "requestId": "8f1c0e2a-6b3d-4f0a-9c11-1d2e3f4a5b6c", "details": {} }, "requestId": "8f1c0e2a-6b3d-4f0a-9c11-1d2e3f4a5b6c" } ``` ### Error codes Errors use a stable `error.code`. Branch on the code, not the message. | Code | HTTP | Meaning | | ---------------- | ---- | ----------------------------------------------- | | `bad_request` | 400 | Malformed input, or an unknown query parameter. | | `unauthorized` | 401 | Missing or invalid API key. | | `forbidden` | 403 | Key is valid but lacks the required scope. | | `not_found` | 404 | The resource does not exist. | | `rate_limited` | 429 | Rate limit exceeded for this client and scope. | | `internal_error` | 500 | Unexpected server error. | Unknown query parameters fail closed. A parameter Financial Data API does not recognize is rejected with `bad_request`, never silently ignored. This catches typos before they return misleading data. ## Pagination List endpoints page with an opaque cursor. Set `limit` (1 to 500, default 100). When `meta.pagination.has_more` is `true`, pass `meta.pagination.next_cursor` back as `cursor` to fetch the next page. `sort` and `order` (`asc` or `desc`, default `asc`) control ordering on endpoints that support them. ## Rate limits Limits are enforced per client, per required scope, in a fixed window. Every API response includes `x-ratelimit-policy`, `x-ratelimit-limit`, `x-ratelimit-remaining`, and `x-ratelimit-reset` (ISO timestamp). On exceed you get `429 rate_limited` with `details` carrying `required_scope`, `limit`, and `window_seconds`. | Scope | Default limit | Window | | ----------- | ------------- | ------ | | `data:read` | 1000 requests | 60s | | `ops:read` | 500 requests | 60s | | `admin` | 250 requests | 60s | ## Explore the spec The raw machine-readable contract. Import it into Postman, Insomnia, or your own code generator. A live breadth summary: catalog totals, public indicator categories, and covered countries. # List Canonical Indicators Source: https://docs.financialdatapi.com/api-reference/list-canonical-indicators GET /v1/canonical-indicators # List Changed Observations Source: https://docs.financialdatapi.com/api-reference/list-changed-observations GET /v1/observations/changes # List Companies Source: https://docs.financialdatapi.com/api-reference/list-companies GET /v1/companies # List Countries Source: https://docs.financialdatapi.com/api-reference/list-countries GET /v1/countries # List Country Indicators Source: https://docs.financialdatapi.com/api-reference/list-country-indicators GET /v1/countries/{idOrIso}/available-indicators # List Derived Indicator Observations Source: https://docs.financialdatapi.com/api-reference/list-derived-indicator-observations GET /v1/derived-indicators/{idOrSlug}/observations # List Derived Indicators Source: https://docs.financialdatapi.com/api-reference/list-derived-indicators GET /v1/derived-indicators # List Derived Observations Source: https://docs.financialdatapi.com/api-reference/list-derived-observations GET /v1/derived-observations # List Economic Calendar Events Source: https://docs.financialdatapi.com/api-reference/list-economic-calendar-events GET /v1/economic-calendar # List Entities Source: https://docs.financialdatapi.com/api-reference/list-entities GET /v1/entities # List Entity Aliases Source: https://docs.financialdatapi.com/api-reference/list-entity-aliases GET /v1/entities/{idOrSlug}/aliases # List Entity Derived Observations Source: https://docs.financialdatapi.com/api-reference/list-entity-derived-observations GET /v1/entities/{entityId}/derived-observations # List Entity Observations Source: https://docs.financialdatapi.com/api-reference/list-entity-observations GET /v1/entities/{entityId}/observations # List Indicator Aliases Source: https://docs.financialdatapi.com/api-reference/list-indicator-aliases GET /v1/indicators/{idOrSlug}/aliases # List Indicator Entities Source: https://docs.financialdatapi.com/api-reference/list-indicator-entities GET /v1/indicators/{idOrSlug}/entities # List Indicator Observations Source: https://docs.financialdatapi.com/api-reference/list-indicator-observations GET /v1/indicators/{indicatorId}/observations # List Indicator Series Source: https://docs.financialdatapi.com/api-reference/list-indicator-series GET /v1/indicators/{idOrSlug}/series # List Indicators Source: https://docs.financialdatapi.com/api-reference/list-indicators GET /v1/indicators # List Instruments Source: https://docs.financialdatapi.com/api-reference/list-instruments GET /v1/instruments # List Latest Observations Source: https://docs.financialdatapi.com/api-reference/list-latest-observations GET /v1/observations/latest # List Latest Public Observations Source: https://docs.financialdatapi.com/api-reference/list-latest-public-observations GET /v1/public/observations/latest # List Observations Source: https://docs.financialdatapi.com/api-reference/list-observations GET /v1/observations # List Official Events Source: https://docs.financialdatapi.com/api-reference/list-official-events GET /v1/events # List Providers Source: https://docs.financialdatapi.com/api-reference/list-providers GET /v1/providers # List Public Observations Source: https://docs.financialdatapi.com/api-reference/list-public-observations GET /v1/public/observations # List Scored Companies Source: https://docs.financialdatapi.com/api-reference/list-scored-companies GET /v1/public/companies # List Screener Filters Source: https://docs.financialdatapi.com/api-reference/list-screener-filters GET /v1/public/screener/filters # List Source Health Source: https://docs.financialdatapi.com/api-reference/list-source-health GET /v1/source-health # List Sources Source: https://docs.financialdatapi.com/api-reference/list-sources GET /v1/sources # Llm Documentation Index Source: https://docs.financialdatapi.com/api-reference/llm-documentation-index GET /llms.txt Compact, sectioned index of the API for LLM agents (text/plain). No API key required. # Llm Full Api Reference Source: https://docs.financialdatapi.com/api-reference/llm-full-api-reference GET /llms-full.txt Full machine-readable endpoint reference with parameters for LLM agents (text/plain). No API key required. # Openapi Document Source: https://docs.financialdatapi.com/api-reference/openapi-document GET /openapi.json # Resolve Entity Source: https://docs.financialdatapi.com/api-reference/resolve-entity GET /v1/entities/resolve # Screen Entities Source: https://docs.financialdatapi.com/api-reference/screen-entities GET /v1/public/screener # Central bank sentiment Source: https://docs.financialdatapi.com/apis/central-bank-sentiment Every monetary policy statement from five central banks, scored on one hawkish to dovish scale, with a confidence, a rationale, and a link to the official statement. Financial Data API scores central bank policy statements on a single hawkish to dovish scale and serves the scores as observations, in the same envelope and with the same provenance as everything else. Policy tone becomes a time series you can chart, screen and backtest, and because every bank is scored on the same scale with the same method, tone is comparable across banks rather than only against a bank's own past. Two feeds exist side by side. Read this page before choosing between them, because they answer different questions. ## The two feeds | Feed | `indicatorId` | Coverage | Method | | ---------------------- | ---------------------------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------- | | Model scored | `cb_statement_sentiment_llm` | 831 statements, five banks | A version-pinned model reads each statement and scores it, returning a confidence and a rationale | | Deterministic baseline | `cb_statement_sentiment` | 244 statements, FOMC only, 1994 to today | A fixed, versioned lexicon of hawkish and dovish language | The deterministic feed is kept published and unchanged as a reproducible baseline. Identical input always produces an identical score, which is what makes it safe as a research control. The model feed covers four more banks and captures nuance a phrase list cannot, at the cost of not being reproducible from first principles by a reader. Neither feed replaces the other, and they are not merged. Use the deterministic feed when reproducibility matters more than coverage, and the model feed when you need banks beyond the Fed. ## Coverage | Bank | Entity | Statements | From | | ------------------------- | ------------------ | ---------- | -------------- | | Federal Reserve | `country_usa` | 244 | February 1994 | | European Central Bank | `region_euro_area` | 285 | January 1999 | | Reserve Bank of Australia | `country_aus` | 164 | February 2011 | | Bank of England | `country_gbr` | 89 | September 2015 | | Bank of Canada | `country_can` | 49 | January 2010 | New statements are scored automatically after release. Coverage begins where each bank's statement archive begins in a machine readable form, which is why the start dates differ. Two Bank of England meetings from 2015 have no surviving statement URL and are absent. ## The scale Scores run from minus 1 to plus 1, judged relative to neutral rather than relative to the previous meeting. | Score | Reading | | ------ | ---------------------------------------------- | | `+1.0` | Emergency or aggressive tightening | | `+0.6` | Firm tightening bias | | `+0.3` | Mild tightening bias | | `0.0` | Balanced, risks two sided, no directional bias | | `-0.3` | Mild easing bias | | `-0.6` | Firm easing bias | | `-1.0` | Emergency or aggressive easing | `valueText` carries a coarse label alongside the number: `hawkish` above `+0.2`, `dovish` below `-0.2`, `neutral` in between. A hawkish reading is not good news and a dovish reading is not bad news. These scores describe what a statement said about its policy stance, nothing more. Turning tone into a market view is your job, not the data's. ## Querying it Pull one bank's full history: ```bash theme={"theme":"css-variables"} curl "https://api.financialdatapi.com/v1/observations?indicator=cb_statement_sentiment_llm&country=gbr" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` Pull the latest statement for every covered bank: ```bash theme={"theme":"css-variables"} curl "https://api.financialdatapi.com/v1/observations/latest?indicator=cb_statement_sentiment_llm" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` ## What a row carries ```json theme={"theme":"css-variables"} { "entityId": "country_gbr", "indicatorId": "indicator_cb_statement_sentiment_llm", "valueNumeric": 0.3, "valueText": "hawkish", "unit": "score", "frequency": "event", "periodEnd": "2022-06-16T00:00:00.000Z", "sourceUrl": "https://www.bankofengland.co.uk/monetary-policy-summary-and-minutes/2022/june-2022", "metadata": { "bank": "boe", "confidence": 0.8, "rationale": "The Bank of England increased Bank Rate by 0.25 percentage points, citing continuing signs of robust cost and price pressures...", "keyPhrases": [], "wordCount": 1036, "deltaVsPrior": 0, "methodVersion": "fdapi_llm_v1" } } ``` | Field | Meaning | | ------------------------ | ---------------------------------------------------- | | `valueNumeric` | The score, minus 1 to plus 1 | | `valueText` | `hawkish`, `dovish` or `neutral` | | `periodEnd` | The statement's own date, not the date it was scored | | `sourceUrl` | The official statement the score was read from | | `metadata.confidence` | The model's own confidence, 0 to 1 | | `metadata.rationale` | Short explanation quoting the statement's language | | `metadata.deltaVsPrior` | Change against the same bank's previous statement | | `metadata.methodVersion` | The pinned method that produced this score | ## Stability guarantees Published scores are never silently re-scored. Model inference is not bit deterministic, so a stored score is only ever recomputed on an explicit method version bump, and `methodVersion` records which method produced each row. Scores from different method versions are not comparable and should not be mixed in one series. This is what makes the series usable in a backtest. A score that quietly changes underneath you cannot be tested honestly. ## Statement text Statement text is not stored or redistributed. Only the derived score, its confidence, a short rationale and a link to the official statement are served. Central bank statement text outside the United States is not public domain, so the scores are Financial Data API's own derivation and are safe to use on every plan, while the underlying text stays with its publisher. The other computed families: surprise indices, positioning percentiles, valuation multiples and rates analytics. The decisions themselves: policy rates, real rates and policy cycle state. # Companies Source: https://docs.financialdatapi.com/apis/companies The scored SEC company universe (S&P 500 union Nasdaq-100) with sector and industry inline, plus entity resolution by ticker or CIK. Financial Data API serves a curated, scored universe of US issuers built from public SEC filings. The companies endpoint lists that universe with classification inline, so sector-aware logic resolves without a per-company fan-out. The entity resolver turns a ticker or CIK you already hold into a Financial Data API entity you can use everywhere else. `GET /companies` lists the curated fundamentals universe (S\&P 500 union Nasdaq-100) with sector and industry inline. `GET /entities/resolve` turns a ticker or CIK into the Financial Data API entity id used across the rest of the API. ## What data is available The universe is the constituents of the S\&P 500 and the Nasdaq-100, deduplicated into a single scored set of roughly 505 US companies. Membership is defined by carrying a SEC-derived sector, which excludes raw ticker-directory filers. Each row is intentionally lean: identity plus classification, so you get the ticker, CIK, exchange, domicile country, sector, and industry in one call. `entityId`, `name`, `ticker`, `cik`, and primary `exchange` for each company. SEC-derived `sector` and `industry` inline. Every universe member carries a sector. Use `entityId`, `ticker`, or `cik` as the lookup for [financial statements](/apis/financial-statements) and entity observations. The company universe is assembled from public SEC filings. Identity and classification are official-source and redistribution-safe. The `/companies` feed is part of the public surface. Coverage totals change as index membership and filings update. Read live breadth from `GET /coverage` rather than hard-coding the count. ## Authentication Send your key as `x-api-key` (or `Authorization: Bearer`) with the `data:read` scope. See [Authentication](/authentication). ## List the scored universe `GET /companies` returns the universe, one company per row, with sector and industry inline. It is a standard cursor-paginated list endpoint. Unknown query parameters are rejected with `bad_request`. ### Parameters ### Example ```bash cURL theme={"theme":"css-variables"} curl "https://api.financialdatapi.com/companies?limit=2" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` ```typescript TypeScript (@financialdatapi/client) theme={"theme":"css-variables"} import { FinancialDataApiClient } from "@financialdatapi/client"; const client = new FinancialDataApiClient({ apiKey: process.env.FINANCIALDATA_API_KEY! }); // Auto-paginate over every page of the universe. for await (const company of client.paginate("/companies")) { console.log(company.ticker, company.name, company.sector); } ``` ```json Response theme={"theme":"css-variables"} { "data": [ { "entityId": "ent_aapl", "name": "Apple Inc.", "ticker": "AAPL", "cik": "0000320193", "exchange": "NASDAQ", "country": "USA", "sector": "Information Technology", "industry": "Technology Hardware, Storage & Peripherals" } ], "meta": { "api_version": "v1", "pagination": { "limit": 2, "cursor": null, "next_cursor": "...", "has_more": true } }, "requestId": "..." } ``` Example values above are illustrative. Pull the live universe from the endpoint. ### Response fields ## Resolve by ticker or CIK `GET /entities/resolve` turns an identifier you already hold into the Financial Data API entity. Pass the value as `alias` and, optionally, narrow the lookup with `alias_type`. Narrowing avoids ambiguity when one string could match more than one identifier kind. ### Parameters ### Example ```bash cURL theme={"theme":"css-variables"} curl "https://api.financialdatapi.com/entities/resolve?alias=AAPL&alias_type=ticker" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` ```typescript TypeScript (@financialdatapi/client) theme={"theme":"css-variables"} import { FinancialDataApiClient } from "@financialdatapi/client"; const client = new FinancialDataApiClient({ apiKey: process.env.FINANCIALDATA_API_KEY! }); // resolveEntity(alias, aliasType?) const { data: entity } = await client.resolveEntity("AAPL", "ticker"); console.log(entity.id, entity.name); ``` ```json Response theme={"theme":"css-variables"} { "data": { "id": "ent_aapl", "type": "company", "name": "Apple Inc.", "slug": "aapl", "active": true, "metadata": {} }, "meta": { "api_version": "v1" }, "requestId": "..." } ``` An unresolved alias returns `404 not_found`. Catch it and fall back to listing the universe if you need to confirm membership. You can often skip resolution. The financials path lookup accepts a ticker or CIK directly, and the `entity` observation filter resolves a ticker for you. Resolve explicitly when you want to confirm identity before fetching. ## Worked example: find, then pull List `/companies` (or resolve a ticker) to get the identity and sector, and confirm membership and classification. Use `entityId`, `ticker`, or `cik` as the lookup for [financial statements](/apis/financial-statements) and for entity observations. Statement and fundamentals values originate from observations. Follow `GET /provenance/observations/{id}` to the named SEC source and ingestion run. ## Notes and caveats The universe is the S\&P 500 and Nasdaq-100 constituents, deduplicated. Membership is defined by carrying a SEC-derived sector, which excludes raw ticker-directory filers. The universe is US issuers only. Use `GET /coverage` for the current catalog totals and covered categories rather than assuming a fixed count. `sector` is SEC-derived and present on every member. `industry` is the finer classification within the sector and may be null. ## Related Pull income, balance-sheet, and cash-flow statements for any company in the universe. Company filings surface as `issuer_filing` events in the unified events feed. Trace any value back to its named SEC source and ingestion run. # Derived analytics Source: https://docs.financialdatapi.com/apis/derived-analytics Financial Data API's own computed signals — surprise indices, COT positioning percentiles, valuation multiples, rates analytics, and a risk-regime composite — served as observations alongside official data. Financial Data API computes a set of analytics on top of its official-source observations and SEC fundamentals, then stores the results and serves them **as observations**, in the same envelope, with the same provenance, as the official data underneath. You read precomputed values, not a live calculator, and each one traces back to the inputs it was built from. This page leads with the derived datasets you can get and the indicator slugs that identify them, then shows how to query them. ## What data is available Every derived dataset is a canonical indicator with its own `indicatorId`, queryable through the standard observation endpoints. Filter by the `category` to pull a whole family. | Family | `category` | Example indicator IDs | What it tells you | | --------------------------- | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Surprise indices | `surprise` | `inflation_surprise_index`, `growth_surprise_index` | How much recent data beat or missed expectations (standardized, in sigma). | | COT positioning percentiles | `positioning` | `cot_positioning_percentile`, `cot_tff_percentile` | A trader cohort's net positioning as a 3-year historical percentile (0–100) — how stretched it is versus its own history. Full weekly panels: legacy COT since 1992 (972 CFTC contracts), TFF leveraged funds since 2006 (117 financial futures). | | Valuation multiples | `valuation_multiples` | `trailing_pe_ratio`, `earnings_yield`, `dividend_yield`, `price_to_book_ratio`, `ev_to_ebitda_ratio`, `ev_to_sales_ratio`, `peg_ratio` | Equity valuation derived from SEC fundamentals and price inputs, per company. All 13 trailing multiples are daily series from 2007 to today for \~500 US companies, computed from raw as-traded prices and point-in-time TTM fundamentals. | | Central-bank sentiment | `central_bank` | `cb_statement_sentiment`, `cb_statement_sentiment_llm` | Hawk/dove scores for policy statements. The deterministic lexicon feed covers 244 FOMC statements from 1994; the model-scored feed covers 831 statements across the Fed, ECB, Bank of England, Bank of Canada and RBA. See [Central bank sentiment](/apis/central-bank-sentiment). | | Rates analytics | `rates` | `real_yield_10y`, `real_policy_rate`, `policy_cycle_state`, `yield_curve_spread_10y_2y`, `yield_10y_change` | Real rates, curve measures, and policy-cycle state derived from policy rates and yields. | | Risk-regime composite | `risk` | `risk_regime` | A composite signal summarizing the prevailing risk environment. | The catalog is live. Resolve the full set of derived slugs and their categories from `GET /canonical-indicators` (the same registry that lists macro indicators), and treat the examples above as a map rather than an exhaustive list. ### The forecast baseline Financial Data API also computes a **statistical macro forecast baseline** with prediction intervals — its own model output, **never** a vendor, sell-side, or street consensus. Where it is published, it populates the `forecast` field (and its interval bounds) on the relevant macro observation, gated by out-of-sample skill, so a series only carries a forecast where the baseline has earned it. The consensus and forecast numbers used to compute surprise indices are a separate, calendar-sourced input (see [Economic calendar and events](/apis/economic-calendar)), not the baseline. ## How derived analytics work Financial Data API ingests official observations (CPI prints, yields, CFTC positioning) and SEC fundamentals, then a derivation step computes higher-level values and persists them as observations. Because the result is stored: * Reads are fast and stable. You retrieve a value; you do not trigger a computation on request. * Each value is auditable. It carries the same `sourceUrl`, `provider`, and provenance chain as any observation, and you can trace it to the official releases underneath via `GET /provenance/observations/{observationId}`. * The product is read-only. You cannot pass your own formula or change the methodology; you read what Financial Data API has computed. Derived values are served through the **same** observation endpoints as official data — there is no separate calculator API. Query them by `indicatorId` or pull a whole family by `category`. ## Querying derived analytics Send your API key on every request (`x-api-key` header or `Authorization: Bearer`); derived routes require the `data:read` scope. All paths are relative to `https://api.financialdatapi.com`. ### Latest value of a derived series ```bash cURL theme={"theme":"css-variables"} curl "https://api.financialdatapi.com/observations/latest?indicator_id=inflation_surprise_index&country=USA" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` ```typescript TypeScript (@financialdatapi/client) theme={"theme":"css-variables"} import { FinancialDataApiClient } from "@financialdatapi/client"; const client = new FinancialDataApiClient({ apiKey: process.env.FINANCIALDATA_API_KEY }); const { data } = await client.getLatestObservations({ indicator_id: "inflation_surprise_index", country: "USA", }); console.log(data[0].actual, data[0].unit, data[0].periodEnd); ``` ### A derived time series ```bash cURL theme={"theme":"css-variables"} curl "https://api.financialdatapi.com/observations?indicator_id=cot_positioning_percentile&limit=20&order=desc" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` ```typescript TypeScript (@financialdatapi/client) theme={"theme":"css-variables"} import { FinancialDataApiClient } from "@financialdatapi/client"; const client = new FinancialDataApiClient({ apiKey: process.env.FINANCIALDATA_API_KEY }); for await (const obs of client.paginate("/observations", { indicator_id: "trailing_pe_ratio", order: "desc", })) { console.log(obs.periodEnd, obs.actual, obs.unit); } ``` ```json Response theme={"theme":"css-variables"} { "data": [ { "observationId": "obs_inflation_surprise_index_country_usa_2026-05-31", "indicatorId": "inflation_surprise_index", "indicatorName": "Inflation surprise index", "category": "surprise", "country": "USA", "actual": 0.628, "unit": "sigma", "periodEnd": "2026-05-31", "observedAt": "2026-06-12T06:00:00.000Z", "provider": "Financial Data API", "sourceUrl": "https://api.financialdatapi.com", "rawAvailable": true } ], "meta": { "request_id": "8f1c0e2a-6b3d-4f0a-9c11-1d2e3f4a5b6c", "requestId": "8f1c0e2a-6b3d-4f0a-9c11-1d2e3f4a5b6c", "api_version": "v1", "pagination": { "limit": 20, "cursor": null, "next_cursor": null, "has_more": false } }, "requestId": "8f1c0e2a-6b3d-4f0a-9c11-1d2e3f4a5b6c" } ``` Units vary by family: surprise indices are in `sigma`, COT percentiles in `percentile`, valuation multiples are a `ratio` (or `percent` for yields). Always branch on the `unit` field. ## Worked example: gold positioning at the extremes The COT percentile panel is deep enough to test against history. Gold in the week of its August 2011 all-time-high top: ```bash cURL theme={"theme":"css-variables"} curl "https://api.financialdatapi.com/observations?indicator_id=cot_positioning_percentile&entity=instrument_cftc_gold_commodity_exchange_inc&start_date=2011-08-01&end_date=2011-08-05" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` That week printed **93.3** (`crowded_long`). The same query over 2015-07-24 to 2015-07-31 returns **2.9** (`crowded_short`) for 2015-07-28 — the cycle bottom. Each row also carries `net`, `weeklyChange`, `percentile1y`, `percentile3y`, and `zScore3y` in metadata. ## FOMC statement sentiment `cb_statement_sentiment` scores every FOMC policy statement on a hawk/dove scale — 244 statements from February 1994 to today, keyed to `country_usa` with one event-frequency row per statement date. The score is deterministic, not model-generated: a versioned lexicon (`fdapi_hawk_dove_v1`) counts hawkish and dovish phrases in the statement text and nets them into a score in \[−1, +1]. `valueText` labels the row `hawkish` (score above 0.2), `dovish` (below −0.2), or `neutral`. Metadata carries a full audit trail: `lexiconVersion`, the matched hawkish and dovish phrases, phrase counts, word count, and `deltaVsPrior` — the change versus the previous statement, which is usually the tradable number. ```bash cURL theme={"theme":"css-variables"} curl "https://api.financialdatapi.com/observations?indicator_id=cb_statement_sentiment&entity=country_usa&start_date=2022-06-01&end_date=2022-06-30" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` The series tracks the eras you would expect it to: | Statement | Score | Reading | | ------------------------------------------- | ----- | ------------------------------ | | December 2008 (ZIRP, "all available tools") | −1.0 | Maximally dovish | | July 2019 (the "hawkish cut") | +0.14 | Eased policy, hawkish language | | June 2022 (75bp, inflation fight) | +1.0 | Maximally hawkish | Each row's `sourceUrl` links to the Federal Reserve statement it was scored from, so every value is verifiable against the public-domain original. ## Trace a derived value to its inputs Because every derived value is an observation, it carries full provenance. You can walk from a derived value back to the official releases it was built on — this is what makes derived analytics auditable. Pull the derived value from `GET /observations` (or `/observations/latest`) and capture its `observationId`. Call `GET /provenance/observations/{observationId}` to reach the named source, the source URL, the raw payload reference metadata, and the ingestion run behind it. Raw provider payload bodies are never exposed by the product API. Provenance returns reference metadata (source, URL, ingestion run, raw payload id), not the original payload contents. ## Notes Derived values are precomputed and persisted. The number you read was computed earlier; the request does not recompute it. You cannot pass your own formula or change the methodology through the API. The macro forecast baseline is Financial Data API's own statistical baseline, published with prediction intervals and gated by out-of-sample skill. It is never a vendor, sell-side, or street consensus. Where consensus is available for surprise computation, it comes from the economic calendar and is a separate input. Derived datasets follow the same rights model as the rest of the API, and trace to the same official provenance. Raw vendor and real-time market price-tick data is deliberately not part of the product and is never served on the public surface. ## Related The raw CFTC COT and TFF series behind the positioning percentile. Where the consensus and forecast inputs behind surprise indices come from. The official observations that feed derived values, and how to query them. The SEC fundamentals behind valuation multiples. # Economic calendar & official events Source: https://docs.financialdatapi.com/apis/economic-calendar Scheduled macro releases and official central bank events with source provenance, plus one unified feed across macro releases, central-bank actions, and issuer filings. Financial Data API dates the macro world. The economic calendar gives you scheduled and released macro events with the values consumers expect on a calendar (actual, forecast, consensus, previous, and revised). The unified events feed merges that calendar with every other official event Financial Data API tracks (central-bank actions and issuer filings) into one normalized shape with a single schema. `GET /economic-calendar` is the scheduled macro-release calendar: CPI prints, payrolls, central-bank meetings, each with actual, forecast, consensus, previous, and revised values. `GET /events` is one stream across macro releases, central-bank actions, and issuer filings, with a single normalized event shape. Use the calendar when you want classic macro-release rows with surprise inputs and release-time semantics. Use the unified events feed when you want a single stream across event classes (macro releases plus central-bank actions and issuer filings) under one schema. ## What data is available The calendar covers the same canonical macro indicators Financial Data API normalizes (CPI, core CPI, PCE, PPI, unemployment, nonfarm payrolls, jobless claims, real GDP growth, policy rates, money-market and government-bond yields, housing starts, building permits, trade balance, exports, imports, personal income, retail sales) across the covered countries, sourced from the institutions of record (FRED, BLS, ECB, OECD, BIS, Eurostat, Bank of England, Bank of Japan, and more). Read the live indicator list from `GET /canonical-indicators` and the country and category breadth from `GET /coverage`. The unified events feed spans three event families: Scheduled and released macro prints, the same rows the economic calendar carries, surfaced as `macro_release` events. Policy decisions and meetings from the central banks Financial Data API tracks, surfaced as `central_bank` events. SEC EDGAR filings from the company universe, surfaced as `issuer_filing` events. The structured statements behind them live in the [financial statements](/apis/financial-statements) endpoint. Coverage grows over time. Read live breadth from `GET /coverage` and the live indicator slugs from `GET /canonical-indicators` rather than hard-coding which events exist. Both feeds are rights-aware. Every event carries an `exposure` class, and only redistribution-safe events appear where the public surface applies. Licensed vendor data never appears on the public surface. ## Authentication Send your key as `x-api-key` (or `Authorization: Bearer`). Both endpoints require the `data:read` scope. See [Authentication](/authentication). ## The economic calendar `GET /economic-calendar` returns scheduled and released macro events. Each row carries the release time, the period it covers, and the value series: actual, forecast, consensus, previous, and (where applicable) revised. ### Filters The calendar accepts the standard list filters plus the observation filters relevant to events. Unknown query parameters are rejected with `bad_request`. ### Example: high-importance US releases ```bash cURL theme={"theme":"css-variables"} curl "https://api.financialdatapi.com/economic-calendar?country=USA&importance=high&limit=5&order=desc" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` ```typescript TypeScript (@financialdatapi/client) theme={"theme":"css-variables"} import { FinancialDataApiClient } from "@financialdatapi/client"; const client = new FinancialDataApiClient({ apiKey: process.env.FINANCIALDATA_API_KEY! }); const { data } = await client.economicCalendar({ country: "USA", importance: "high", limit: 5, order: "desc", }); for (const event of data) { console.log(event.releaseTime, event.eventName, event.actualValue, event.forecastValue); } ``` ```json Response theme={"theme":"css-variables"} { "data": [ { "id": "ecal_us_cpi_2026_05", "providerEventId": "...", "sourceId": "bls", "providerId": "bls", "entityId": "country_usa", "countryIso3": "USA", "indicatorId": "cpi_inflation_yoy", "eventName": "CPI (YoY)", "eventType": "economic_release", "importance": "high", "status": "released", "releaseTime": "2026-06-11T12:30:00Z", "releaseTimeZone": "America/New_York", "period": "2026-05", "periodStart": "2026-05-01", "periodEnd": "2026-05-31", "actualValue": 3.1, "forecastValue": 3.2, "consensusValue": 3.2, "previousValue": 3.3, "revisedValue": null, "unit": "percent", "currency": null, "sourceUrl": "https://www.bls.gov/...", "attribution": "U.S. Bureau of Labor Statistics", "observationId": "obs_...", "exposure": "public" } ], "meta": { "api_version": "v1", "pagination": { "limit": 5, "cursor": null, "next_cursor": null, "has_more": false } }, "requestId": "..." } ``` Example figures above are illustrative. Pull live values from the endpoint. ### Calendar event fields ### Get a single calendar event `GET /economic-calendar/{id}` returns one calendar event by its `id`. ```bash cURL theme={"theme":"css-variables"} curl "https://api.financialdatapi.com/economic-calendar/ecal_us_cpi_2026_05" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` ```typescript TypeScript (@financialdatapi/client) theme={"theme":"css-variables"} const { data: event } = await client.request( "/economic-calendar/ecal_us_cpi_2026_05" ); console.log(event.eventName, event.actualValue); ``` ## First-release vs revised Macro series are revised after their first print. Financial Data API keeps both, and the calendar exposes the distinction so you can model surprises honestly. `previousValue` carries the prior period value as it was known at this release, not the latest revised figure. That is what a forecast was measured against at the time, so it is the correct base for surprise and momentum calculations. When an event reports a revision, `revisedValue` is populated and `status` is `revised`. The original `actualValue` is preserved. Revisions are retained, never overwritten in place. To see the value set as known on a given date, use the knowledge-time filters (`start_date` and `end_date`) and `as_of` on the observations API. Honest caveat: `as_of` currently approximates the ingestion timestamp, not full provider-vintage reconstruction. Full vintage reconstruction is future work. ## Unified official events `GET /events` merges the economic calendar with every other official event into one normalized response shape. It covers macro releases, central-bank actions, and issuer filings (for example SEC filings) under one schema. Use it when you want a single stream and one set of fields across event classes. ### Filters ### Example: released US macro events ```bash cURL theme={"theme":"css-variables"} curl "https://api.financialdatapi.com/events?event_class=macro_release&country=USA&status=released&limit=5" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` ```typescript TypeScript (@financialdatapi/client) theme={"theme":"css-variables"} import { FinancialDataApiClient } from "@financialdatapi/client"; const client = new FinancialDataApiClient({ apiKey: process.env.FINANCIALDATA_API_KEY! }); const { data } = await client.officialEvents({ event_class: "macro_release", country: "USA", status: "released", limit: 5, }); for (const event of data) { console.log(event.eventClass, event.eventType, event.title, event.observedAt); } ``` ```json Response theme={"theme":"css-variables"} { "data": [ { "id": "obs_or_ecal_id", "canonicalEventId": "...", "eventClass": "macro_release", "eventType": "economic_release", "eventLabel": "CPI (YoY)", "eventStatus": "released", "entityId": "country_usa", "countryIso3": "USA", "indicatorId": "cpi_inflation_yoy", "observedAt": "2026-06-11T12:30:00Z", "releasedAt": "2026-06-11T12:30:00Z", "effectiveAt": null, "periodStart": "2026-05-01", "periodEnd": "2026-05-31", "title": "CPI (YoY)", "summary": null, "tags": ["economic_release", "USA", "cpi_inflation_yoy"], "sourceId": "bls", "providerId": "bls", "sourceUrl": "https://www.bls.gov/...", "attribution": "U.S. Bureau of Labor Statistics", "exposure": "public", "linkedObservationId": "obs_...", "metadata": { "importance": "high", "actualValue": 3.1, "forecastValue": 3.2, "consensusValue": 3.2, "previousValue": 3.3, "revisedValue": null, "unit": "percent", "currency": null } } ], "meta": { "api_version": "v1", "pagination": { "limit": 5, "cursor": null, "next_cursor": null, "has_more": false } }, "requestId": "..." } ``` ### Unified event fields ### Get a single event `GET /events/{id}` returns one unified event by its `id`. ```bash cURL theme={"theme":"css-variables"} curl "https://api.financialdatapi.com/events/obs_or_ecal_id" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` ```typescript TypeScript (@financialdatapi/client) theme={"theme":"css-variables"} const { data: event } = await client.request("/events/obs_or_ecal_id"); console.log(event.title, event.eventStatus); ``` ## Calendar vs unified events: which to use You want macro-release rows with surprise inputs (actual, forecast, consensus, previous, revised) and release-time semantics. Filter by `country`, `indicator`, `importance`, `status`, `event_type`, and `period`. You want one stream across event classes (macro releases plus central-bank actions and issuer filings) under a single schema. Filter by `event_class`, `event_type`, `status`, `exposure`, and time. ## Related Follow `observationId` (or `linkedObservationId`) to the point-in-time value the event released, with full filters and provenance. Issuer filings surface as `issuer_filing` events here; the structured statements behind them live in the financials endpoint. Surprise indices and other analytics are computed from calendar inputs and stored as derived observations. # Energy & commodities Source: https://docs.financialdatapi.com/apis/energy-commodities Official energy market data from the US EIA, covering spot prices, inventories, production and refining, in the same observation model as macro. Financial Data API carries official **energy and commodity** series from the U.S. Energy Information Administration (EIA): benchmark spot prices, stock levels, production, and refining activity. They sit under the `commodities` category and flow through the same observation envelope, freshness gating, and provenance as macro indicators, so an oil-inventory print joins cleanly against CPI, rates, or positioning. ## What data is available Benchmark energy spot prices — for example WTI and Brent crude, and Henry Hub natural gas. Refined product spot prices — for example NY Harbor gasoline and distillate. Stock levels — crude oil, gasoline, distillate, and natural gas inventories. Production volumes — for example US crude oil production. Refinery inputs / throughput. Refinery capacity utilization. These are global-commodity series, so most carry no `country` (the value is a market benchmark, not a national statistic). The specific product or benchmark is identified in the observation metadata and provenance. The publisher is the U.S. Energy Information Administration. ## Query energy data ```bash cURL theme={"theme":"css-variables"} # Latest reading for a series curl "https://api.financialdatapi.com/observations/latest?indicator_id=energy_spot_price" \ -H "x-api-key: $FINANCIALDATA_API_KEY" # Inventory history curl "https://api.financialdatapi.com/observations?indicator_id=energy_inventory&limit=20&order=desc" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` ```typescript TypeScript theme={"theme":"css-variables"} import { FinancialDataApiClient } from "@financialdatapi/client"; const client = new FinancialDataApiClient({ apiKey: process.env.FINANCIALDATA_API_KEY }); const { data } = await client.getLatestObservations({ indicator_id: "energy_spot_price" }); console.log(data); ``` ## Response shape Each row is a standard public observation. The fields most relevant here: One of the series above, for example `energy_inventory`. `commodities`. The value (price, volume, or percent depending on the series). For example dollars per barrel, million barrels, or percent. `U.S. Energy Information Administration`. The period the reading describes. The exact benchmark or product (WTI vs Brent, gasoline vs distillate, crude vs natural gas) is carried in the observation metadata. Read it from the row, or trace it with `GET /provenance/observations/{observationId}`. ## Related CFTC futures positioning, including energy contracts. Trace any value to its EIA release. # Equity screener Source: https://docs.financialdatapi.com/apis/equity-screener Screen the scored US equity universe (S&P 500 union Nasdaq-100) by valuation multiples, financial ratios, and price analytics with the compact filter DSL. The equity screener is the company-level counterpart of the [macro screener](/guides/screener). Instead of filtering countries by indicator values, you filter the [scored universe](/apis/companies) of US companies by the latest values of 34 screenable fields — valuation multiples, financial ratios, and price analytics — with the same compact `filter` DSL: "show me Technology companies with a trailing P/E below 25 and a positive 12-month return, ranked by free-cash-flow yield." The screener screens **public values only**: the latest published value per company per field, all of it derived from SEC fundamentals and Financial Data API's own [derived analytics](/apis/derived-analytics). It never exposes internal scoring and never touches licensed data. ## How it works Filters arrive as a single `filter` query parameter. Each clause is `field:operator:value`, clauses are comma-separated, and they are AND-ed together — identical semantics to the macro screener: ```text theme={"theme":"css-variables"} filter=sector:eq:Technology,trailing_pe_ratio:lt:25,equity_return_12m:gt:0 ``` The operators are `gt`, `lt`, `gte`, `lte`, `eq`, and `in`; `in` is the only one that takes more than one value, pipe-separated: ```text theme={"theme":"css-variables"} filter=sector:in:Technology|Health Care ``` A company qualifies only when every clause matches. A company **missing a value** for any filtered field does not satisfy that clause and is excluded — absence never counts as a match. ## Parameters | Param | Values | Description | | -------- | ---------------------------------------------------------------- | ------------------------------------------------------------------------- | | `filter` | DSL string, **required** | Comma-joined `field:operator:value` clauses, AND-ed. | | `sort` | Any screenable field, plus `ticker` and `name`; default `ticker` | Field to rank the results by. Companies missing the sort field sort last. | | `order` | `asc` / `desc`, default `asc` | Sort direction. | | `limit` | 1 to 200, default 50 | Cap the number of returned companies. | Unknown query parameters, malformed clauses, unknown operators, and out-of-range `limit` values are rejected with `bad_request`. The error message names the offending clause. ## Screenable fields The 34 fields fall into five groups. `sector` and `industry` are strings and accept `eq` and `in` only, matched case-insensitively; every other field is numeric and accepts all six operators. `sector`, `industry` (string; `eq`/`in`, case-insensitive), `market_cap`. `trailing_pe_ratio`, `price_to_book_ratio`, `price_to_sales_ratio`, `price_to_free_cash_flow_ratio`, `price_to_operating_cash_flow_ratio`, `ev_to_ebit_ratio`, `ev_to_ebitda_ratio`, `ev_to_sales_ratio`, `ev_to_free_cash_flow_ratio`, `earnings_yield`, `free_cash_flow_yield`, `dividend_yield`, `peg_ratio`. `gross_margin`, `operating_margin`, `profit_margin`, `free_cash_flow_margin`, `current_ratio`, `quick_ratio`, `cash_ratio`, `debt_to_equity`, `return_on_assets`, `return_on_equity`. `equity_return_1m`, `equity_return_3m`, `equity_return_6m`, `equity_return_12m`, `equity_realized_vol_30d`, `equity_realized_vol_90d`, `equity_max_drawdown_1y`, `equity_trend_zscore_90d`. ### Discovering fields The authoritative list, with operators, syntax, and an example, lives at `GET /public/equity-screener/filters`: ```bash cURL theme={"theme":"css-variables"} curl "https://api.financialdatapi.com/public/equity-screener/filters" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` ```typescript TypeScript (@financialdatapi/client) theme={"theme":"css-variables"} import { FinancialDataApiClient } from "@financialdatapi/client"; const client = new FinancialDataApiClient({ apiKey: process.env.FINANCIALDATA_API_KEY! }); const { data } = await client.request("/public/equity-screener/filters"); for (const f of data.fields) { console.log(f.field, "-", f.name); } ``` Treat `/public/equity-screener/filters` as the source of truth for field names rather than hard-coding the list above — the same pattern as the macro screener's `/screener/filters`. ## Running a screen Send your clauses as the `filter` parameter to `GET /public/equity-screener`. The `filter` parameter is required. ```bash cURL theme={"theme":"css-variables"} curl "https://api.financialdatapi.com/public/equity-screener?filter=sector:eq:Technology,trailing_pe_ratio:lt:25,equity_return_12m:gt:0&sort=free_cash_flow_yield&order=desc" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` ```typescript TypeScript (@financialdatapi/client) theme={"theme":"css-variables"} import { FinancialDataApiClient } from "@financialdatapi/client"; const client = new FinancialDataApiClient({ apiKey: process.env.FINANCIALDATA_API_KEY! }); const { data } = await client.request("/public/equity-screener", { filter: "sector:eq:Technology,trailing_pe_ratio:lt:25,equity_return_12m:gt:0", sort: "free_cash_flow_yield", order: "desc", }); for (const row of data) { console.log(row.ticker, row.name, row.values); } ``` ### The response Each result is a company that satisfied every clause, with the evaluated values inlined so you can see what it screened on without a second call: ```json Response theme={"theme":"css-variables"} { "data": [ { "entityId": "ent_aapl", "ticker": "AAPL", "name": "Apple Inc.", "sector": "Technology", "industry": "Technology Hardware, Storage & Peripherals", "values": [ { "field": "trailing_pe_ratio", "value": 23.4, "unit": "ratio", "periodEnd": "2026-07-24" }, { "field": "equity_return_12m", "value": 8.6, "unit": "percent", "periodEnd": "2026-07-24" }, { "field": "free_cash_flow_yield", "value": 4.1, "unit": "percent", "periodEnd": "2026-07-24" } ] } ], "meta": { "api_version": "v1" }, "requestId": "..." } ``` Example values above are illustrative. Run the screen for live results. ## Authentication The equity screener lives on the public surface. Send your key as `x-api-key` (or `Authorization: Bearer`) as everywhere else; see [Authentication](/authentication). ## Notes and caveats The screener evaluates the scored universe — S\&P 500 union Nasdaq-100, the same membership as [`GET /companies`](/apis/companies). It does not screen the full US market. A company with no value for a **filtered** field is excluded from the results — absence never satisfies a clause. A company with no value for the **sort** field still qualifies but sorts last. Multiples and ratios are computed from SEC fundamentals and price inputs; the price analytics are Financial Data API's own [derived analytics](/apis/derived-analytics). The screener reads the latest published value per field — it is a filter over stored values, not a live calculator. The [MCP server](/ai-agents/mcp-server) exposes the screener as `screen_equities`, with `equity_screener_fields` for field discovery — the equity analogues of `screen_macro` and `screener_fields`. ## Related The cross-country original: same DSL, canonical macro indicators as fields. The valuation multiples and price analytics behind the screenable fields. The scored universe the screener evaluates. The SEC fundamentals underneath the multiples and ratios. # Financial statements Source: https://docs.financialdatapi.com/apis/financial-statements Structured income, balance-sheet, and cash-flow statements assembled from SEC XBRL filings, annual or quarterly, by ticker or CIK. Financial Data API serves US company fundamentals as structured, period-keyed statements assembled from public SEC XBRL filings. One call returns three arrays (income statements, balance sheets, and cash-flow statements) for any company in the [scored universe](/apis/companies), with stable line-item keys mapped from XBRL concepts. All fundamentals are derived from public SEC XBRL filings, so values are official-source and redistribution-safe. The financials endpoint requires the `data:read` scope. ## What data is available `GET /companies/{idOrLookup}/financials` returns three statement arrays, each element a single reporting period, newest first. Line items are mapped from SEC XBRL concepts into stable keys, so the same field name works across companies and periods. A line item is absent when the company did not report that concept for the period. `revenue`, `cost_of_revenue`, `gross_profit`, `operating_expenses`, `research_and_development`, `selling_general_and_administrative`, `operating_income`, `net_income`, `earnings_per_share_diluted`, `weighted_average_shares_diluted`. `total_assets`, `current_assets`, `cash_and_equivalents`, `inventory`, `accounts_receivable`, `accounts_payable`, `current_liabilities`, `total_liabilities`, `long_term_debt`, `shareholders_equity`. `net_cash_flow_from_operations`. Statements are available at annual or quarterly frequency. Coverage is the S\&P 500 union Nasdaq-100 scored universe of US issuers; see the [companies endpoint](/apis/companies) for membership and use `GET /coverage` for live breadth. A missing line-item key means "not reported", not zero. Treat absent keys as no value rather than assuming a value of zero. ## Authentication Send your key as `x-api-key` (or `Authorization: Bearer`) with the `data:read` scope. See [Authentication](/authentication). ## Look up by ticker, CIK, or entity id The `idOrLookup` path segment accepts a Financial Data API entity id, a ticker, or a CIK. There is no separate resolve step required: `GET /companies/AAPL/financials` `GET /companies/0000320193/financials` `GET /companies/ent_aapl/financials` If you want to confirm the entity first, resolve a ticker or CIK with `GET /entities/resolve`. See the [companies endpoint](/apis/companies#resolve-by-ticker-or-cik). It is optional: the path lookup matches ticker and CIK directly. ## Parameters Unknown query parameters are rejected with `bad_request`. Only `period` and `limit` are accepted here. ## Example: AAPL annuals ```bash cURL theme={"theme":"css-variables"} curl "https://api.financialdatapi.com/companies/AAPL/financials?period=annual&limit=3" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` ```typescript TypeScript (@financialdatapi/client) theme={"theme":"css-variables"} import { FinancialDataApiClient } from "@financialdatapi/client"; const client = new FinancialDataApiClient({ apiKey: process.env.FINANCIALDATA_API_KEY! }); const { data: financials } = await client.request( "/companies/AAPL/financials", { period: "annual", limit: 3 } ); for (const stmt of financials.income_statements) { console.log(stmt.periodEnd, stmt.revenue, stmt.net_income); } ``` ```json Response theme={"theme":"css-variables"} { "data": { "entity_id": "ent_aapl", "ticker": "AAPL", "cik": "0000320193", "income_statements": [ { "period": "annual", "periodEnd": "2025-09-27", "currency": "USD", "revenue": 416161000000, "cost_of_revenue": 210352000000, "gross_profit": 205809000000, "operating_income": 132972000000, "net_income": 112010000000, "earnings_per_share_diluted": 7.39, "weighted_average_shares_diluted": 15150000000 } ], "balance_sheets": [ { "period": "annual", "periodEnd": "2025-09-27", "currency": "USD", "total_assets": 364980000000, "current_assets": 152987000000, "cash_and_equivalents": 30299000000, "total_liabilities": 290437000000, "long_term_debt": 85750000000, "shareholders_equity": 74543000000 } ], "cash_flow_statements": [ { "period": "annual", "periodEnd": "2025-09-27", "currency": "USD", "net_cash_flow_from_operations": 118254000000 } ] }, "meta": { "api_version": "v1" }, "requestId": "..." } ``` Example figures above are illustrative. Pull live values from the endpoint. ## Response shape Every statement object shares three common fields plus its line items: ### Line items by statement `revenue`, `cost_of_revenue`, `gross_profit`, `operating_expenses`, `research_and_development`, `selling_general_and_administrative`, `operating_income`, `net_income`, `earnings_per_share_diluted`, `weighted_average_shares_diluted`. `total_assets`, `current_assets`, `cash_and_equivalents`, `inventory`, `accounts_receivable`, `accounts_payable`, `current_liabilities`, `total_liabilities`, `long_term_debt`, `shareholders_equity`. `net_cash_flow_from_operations`. A line item is absent from a statement object when the company did not report that concept for the period. Treat missing keys as "not reported", not zero. ## Worked example: resolve, then pull List `/companies` (or resolve a ticker) to get the identity and sector, and confirm membership before fetching statements. Call `/companies/{ticker}/financials` with `period=annual` and a `limit`. No separate id lookup is required, because the path accepts ticker and CIK. Iterate `income_statements`, `balance_sheets`, and `cash_flow_statements`. Each element is one period; line items are stable keys. Missing keys mean the concept was not reported. Each statement value originates from an observation. Pull the same fundamentals through `GET /entities/{entityId}/observations` and follow `GET /provenance/observations/{id}` to the named SEC source and ingestion run. ## Notes and caveats Statements are assembled from individual SEC XBRL fundamentals observations, one per line item per period. The financials endpoint groups them into per-period statement objects so you do not have to. When a period has multiple reported vintages, the most recent value is used for each line item. The full history, including superseded values, remains queryable through the observations API with the `as_of` and knowledge-time filters. Note that `as_of` currently approximates the ingestion timestamp rather than full provider-vintage reconstruction. The universe is US issuers in the S\&P 500 and Nasdaq-100. Use `GET /coverage` for the current catalog totals and covered categories rather than assuming a fixed count. ## Related The scored universe and entity resolution by ticker or CIK. Company filings surface as `issuer_filing` events in the unified events feed. Trace any statement value back to its named SEC source and ingestion run. # FX reference rates Source: https://docs.financialdatapi.com/apis/fx Official daily foreign-exchange reference rates (e.g. the ECB euro fixings), normalized into the same observation model as everything else. Financial Data API publishes official daily **FX reference rates** — the published fixings central banks and statistical agencies release once per business day, such as the European Central Bank's euro reference rates. They live under the `fx` category as the canonical indicator `fx_reference_rate` and flow through the same observation envelope, time model, and provenance chain as macro data. These are official **reference rates**, not raw real-time market price-tick FX. Tick-level vendor FX is redistribution-blocked and deliberately not part of the product. A reference rate is one authoritative value per currency pair per day — ideal for valuation, reporting, and point-in-time conversion, not for intraday trading. ## What data is available Daily reference exchange rate for a currency pair. Sourced from the official publisher (for example the European Central Bank). Each observation identifies the pair in its metadata and provenance. Unit: an exchange rate (units of one currency per unit of the other). The set of published pairs is live; resolve it from the data rather than hardcoding. The ECB reference set, for example, quotes the euro against major currencies (USD, GBP, JPY, CHF, CAD, AUD, NZD, SEK, NOK, and more). ## Query the latest reference rates ```bash cURL theme={"theme":"css-variables"} curl "https://api.financialdatapi.com/observations/latest?indicator_id=fx_reference_rate" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` ```typescript TypeScript theme={"theme":"css-variables"} import { FinancialDataApiClient } from "@financialdatapi/client"; const client = new FinancialDataApiClient({ apiKey: process.env.FINANCIALDATA_API_KEY }); const { data } = await client.getLatestObservations({ indicator_id: "fx_reference_rate" }); console.log(data); ``` For history, page through `GET /observations?indicator_id=fx_reference_rate` and follow the cursor. See [Pagination](/concepts/pagination). ## Response shape Each row is a standard public observation. The fields most relevant to FX: Always `fx_reference_rate`. `fx`. The reference rate for the pair. The publishing institution, for example `European Central Bank`. The rate date. Link to the originating release. The currency pair is carried in the observation metadata and provenance. Use `GET /provenance/observations/{observationId}` for the full auditable chain behind any rate. ## Related Policy rates, bond yields, and curve spreads. Knowledge time vs. period, and point-in-time queries. # Insider trades Source: https://docs.financialdatapi.com/apis/insider-trades SEC Forms 3, 4, and 5 insider transactions per company — who traded, when, and at what price — with signed transaction values and full provenance, by ticker or CIK. Financial Data API serves insider transaction activity for any company in the [scored universe](/apis/companies), assembled from public SEC Section 16 filings (Forms 3, 4, and 5). One call returns a company's insider trades newest first: who traded, their relationship to the issuer, the transaction date and code, shares and price, and a signed transaction value — with every row traceable to the filing it came from. All insider trades are derived from public SEC Forms 3, 4, and 5, so values are official-source and redistribution-safe. The insider-trades endpoint requires the `data:read` scope. ## What data is available `GET /companies/{idOrLookup}/insider-trades` returns one row per reported transaction, newest first by transaction date. All 15 SEC transaction codes are covered, and every row carries a human-readable `transaction_code_label` so you can render without a lookup table. `insider_name`, `insider_cik`, `is_director`, `is_officer`, `is_ten_percent_owner`, `officer_title`. `transaction_date`, `transaction_code`, `transaction_code_label`, `security_title`, `shares`, `price_per_share`, `value`, `acquired_disposed`, `shares_owned_following`, `direct_or_indirect`, `is_derivative`. `form`, `filed_at`, `accession_number`, `filing_url`, `source_id`, `attribution`, plus `observation_id` for the full provenance chain. `value` is signed USD: positive when shares were acquired, negative when shares were disposed. `acquired_disposed` carries the SEC's own `A`/`D` flag, so you can branch on either. ## Authentication Send your key as `x-api-key` (or `Authorization: Bearer`) with the `data:read` scope. See [Authentication](/authentication). ## Look up by ticker, CIK, or entity id The `idOrLookup` path segment accepts a Financial Data API entity id, a ticker, or a CIK — the same resolution as the [financials endpoint](/apis/financial-statements). There is no separate resolve step required: `GET /companies/AAPL/insider-trades` `GET /companies/0000320193/insider-trades` `GET /companies/ent_aapl/insider-trades` ## Parameters | Param | Values | Description | | -------------------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------ | | `limit` | 1 to 500, default 100 | Cap the number of returned trades. | | `start_date` | `YYYY-MM-DD` | Only trades with a **transaction date** on or after this date. | | `end_date` | `YYYY-MM-DD` | Only trades with a **transaction date** on or before this date. | | `transaction_code` | A single SEC code letter | Filter to one transaction code, for example `P` or `S`. Case-insensitive. | | `include_derivative` | `true` / `false`, default `true` | Set `false` to drop derivative transactions (options, RSUs, convertibles) and keep only non-derivative rows. | | `order` | `asc` / `desc`, default `desc` | Sort direction by transaction date. | `start_date` and `end_date` bound the **transaction date**, not the filing date: a late-filed Form 4 surfaces under the date the insider actually traded. As everywhere else, unknown query parameters are rejected with `bad_request`. ## Example: AAPL open-market sales ```bash cURL theme={"theme":"css-variables"} curl "https://api.financialdatapi.com/companies/AAPL/insider-trades?transaction_code=S&include_derivative=false&limit=2" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` ```typescript TypeScript (@financialdatapi/client) theme={"theme":"css-variables"} import { FinancialDataApiClient } from "@financialdatapi/client"; const client = new FinancialDataApiClient({ apiKey: process.env.FINANCIALDATA_API_KEY! }); const { data } = await client.request( "/companies/AAPL/insider-trades", { transaction_code: "S", include_derivative: false, limit: 2 } ); for (const trade of data.insider_trades) { console.log(trade.transaction_date, trade.insider_name, trade.shares, trade.value); } ``` ```json Response theme={"theme":"css-variables"} { "data": { "entity_id": "ent_aapl", "ticker": "AAPL", "cik": "0000320193", "insider_trades": [ { "observation_id": "obs_insider_aapl_0001234567_2026-04-02_s_1", "insider_name": "DOE JANE", "insider_cik": "0001234567", "is_director": false, "is_officer": true, "is_ten_percent_owner": false, "officer_title": "Chief Operating Officer", "transaction_date": "2026-04-02", "filed_at": "2026-04-03T18:31:12.000Z", "transaction_code": "S", "transaction_code_label": "Open market or private sale", "security_title": "Common Stock", "shares": 25000, "price_per_share": 245.1, "value": -6127500, "acquired_disposed": "D", "shares_owned_following": 412000, "direct_or_indirect": "D", "is_derivative": false, "form": "4", "accession_number": "0000320193-26-000045", "filing_url": "https://www.sec.gov/Archives/edgar/data/320193/000032019326000045/0000320193-26-000045-index.htm", "source_id": "src_sec_form345", "attribution": "U.S. Securities and Exchange Commission" } ] }, "meta": { "api_version": "v1" }, "requestId": "..." } ``` Example rows above are illustrative, with a placeholder insider. Pull live trades from the endpoint. ## Transaction codes The SEC's Section 16 code table has 15 transaction codes, and all of them are served. The most common: | Code | Label | | ---- | ---------------------------------------------------------- | | `P` | Open market or private purchase | | `S` | Open market or private sale | | `A` | Grant, award, or other acquisition | | `D` | Disposition to the issuer | | `F` | Payment of exercise price or tax liability with securities | | `M` | Exercise or conversion of a derivative security | | `C` | Conversion of a derivative security | | `G` | Bona fide gift | The remaining codes are served the same way; every row's `transaction_code_label` carries the human-readable label, and the `transaction_code` filter accepts any of the 15 letters, case-insensitively. For "real" conviction signals, most workflows start from `transaction_code=P` (open-market purchases) with `include_derivative=false` — grants, tax withholding, and option exercises are routine compensation mechanics rather than discretionary trades. ## Notes and caveats Rows are parsed from public SEC Forms 3 (initial ownership), 4 (changes), and 5 (annual). Each row keeps the `form`, `accession_number`, and `filing_url` of the filing it came from, and `observation_id` feeds `GET /provenance/observations/{id}` for the named source and ingestion run. Derivative transactions (options, RSUs, convertible securities) are included by default and flagged with `is_derivative: true`. Set `include_derivative=false` to keep only non-derivative rows. Derivative rows may omit `price_per_share` where the filing does not report one. Free-plan keys see the most recent 2 years of insider-trade history; the window is clamped server-side, not errored. Paid plans read the full history. The [MCP server](/ai-agents/mcp-server) exposes this endpoint as the `insider_trades` tool, so agents can pull the same rows conversationally. ## Related Quarterly SEC 13F holdings for 25 headline institutional filers. The scored universe and entity resolution by ticker or CIK. Structured statements for the same companies, from SEC XBRL filings. Trace any trade back to its named SEC filing and ingestion run. # Institutional ownership Source: https://docs.financialdatapi.com/apis/institutional-ownership Quarterly SEC 13F holdings for 25 headline institutional filers — position market value, shares, and filing detail per filer, issuer, and quarter — served through the observations API. Financial Data API carries quarterly SEC Form 13F holdings for a curated set of 25 headline institutional filers as first-class observations: one row per filer, issuer, and quarter, with the position's market value as the observation value and the filing detail in metadata. You can read a stock's institutional owners, or walk a single manager's whole book, in the same envelope as everything else. There is no dedicated REST route for 13F holdings yet — the recipe below reads them through the standard observations API, with the same pagination and provenance as any other series. Agents get a purpose-built [`institutional_holdings` MCP tool](/ai-agents/mcp-server) that wraps the same data, ticker- or filer-centric. ## What data is available Holdings live under the canonical indicator `indicator_institutional_holding`. Each observation is one **(filer, issuer, quarter)** position: the value is the position's market value in USD, and the metadata carries the rest of the 13F row. The position's market value in USD, as reported for the calendar quarter. `filerName`, `filerCik`, `cusip`, `shares`, `class`, `reportCalendarQuarter`, `putCall`. `filedAt`, `accessionNumber`, and `filingUrl` point at the exact 13F filing behind the row. Form 13F filings are public SEC documents, so holdings are official-source and redistribution-safe. Reports are quarterly, filed up to 45 days after quarter end, and the feed is amendment-aware: a 13F-HR/A supersedes the original where it restates a position. ### The curated filer set Coverage is a deliberate, curated set of 25 headline filers rather than the full 13F universe — the managers whose quarterly books move markets and headlines: Berkshire Hathaway, BlackRock, Vanguard, State Street. Bridgewater, Renaissance Technologies, Citadel Advisors, Millennium, D. E. Shaw, Two Sigma, AQR, Tiger Global, Coatue, Lone Pine, Viking Global, Baupost, Appaloosa. Elliott, Pershing Square, Icahn, Third Point, Soros Fund Management, Duquesne Family Office, Scion Asset Management, Greenlight Capital. ## Authentication Send your key as `x-api-key` (or `Authorization: Bearer`) with the `data:read` scope. See [Authentication](/authentication). ## Query holdings Pull the whole panel with the indicator filter, or make it issuer-centric by adding `entity_id`. ```bash cURL theme={"theme":"css-variables"} # Who holds Apple, most recent quarters first curl "https://api.financialdatapi.com/observations?indicator_id=indicator_institutional_holding&entity_id=ent_aapl&order=desc&limit=25" \ -H "x-api-key: $FINANCIALDATA_API_KEY" # The full holdings panel across all 25 filers curl "https://api.financialdatapi.com/observations?indicator_id=indicator_institutional_holding&limit=100" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` ```typescript TypeScript (@financialdatapi/client) theme={"theme":"css-variables"} import { FinancialDataApiClient } from "@financialdatapi/client"; const client = new FinancialDataApiClient({ apiKey: process.env.FINANCIALDATA_API_KEY! }); for await (const obs of client.paginate("/observations", { indicator_id: "indicator_institutional_holding", entity_id: "ent_aapl", order: "desc", })) { console.log(obs.metadata.filerName, obs.metadata.reportCalendarQuarter, obs.actual); } ``` ```json Response theme={"theme":"css-variables"} { "data": [ { "observationId": "obs_institutional_holding_brk_ent_aapl_2026q1", "indicatorId": "indicator_institutional_holding", "indicatorName": "Institutional holding (13F)", "entity": "ent_aapl", "actual": 63450000000, "unit": "USD", "periodEnd": "2026-03-31", "metadata": { "filerName": "Berkshire Hathaway Inc", "filerCik": "0001067983", "cusip": "037833100", "shares": 300000000, "class": "COM", "reportCalendarQuarter": "2026-Q1", "filedAt": "2026-05-14T21:05:00.000Z", "accessionNumber": "0000950123-26-004567", "filingUrl": "https://www.sec.gov/Archives/edgar/data/1067983/000095012326004567/0000950123-26-004567-index.htm", "putCall": null }, "provider": "U.S. Securities and Exchange Commission", "rawAvailable": true } ], "meta": { "api_version": "v1", "pagination": { "limit": 25, "cursor": null, "next_cursor": "...", "has_more": true } }, "requestId": "..." } ``` Example values above are illustrative. Pull live holdings from the endpoint. Filer-centric reads work the same way: filter the panel client-side on `metadata.filerCik` (or use the `institutional_holdings` MCP tool, which accepts a filer directly). One filer's book for one quarter is the set of rows sharing `filerCik` and `reportCalendarQuarter`. ## Monitoring activist stakes 13F holdings are quarterly and lag the quarter end by up to 45 days. Activist positions usually surface faster through **Schedule 13D and 13G** filings, which Financial Data API serves as `issuer_disclosure` events in the unified events feed: ```bash cURL theme={"theme":"css-variables"} curl "https://api.financialdatapi.com/events?event_class=issuer_disclosure&limit=20" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` Combine the two and you approximate an activist-watch feed: the 13D/G event tells you a stake crossed a disclosure threshold now, and the following quarter's 13F rows (Elliott, Pershing Square, Icahn, Third Point, and the rest of the curated set) show how the position evolved. ## Notes and caveats 13F reports are filed up to 45 days after each calendar quarter end, so positions are stale by design. `reportCalendarQuarter` is the quarter the holdings describe; `filedAt` is when the SEC received the filing. Use the events feed above for faster disclosure signals. The feed is amendment-aware: when a filer submits a 13F-HR/A, the restated rows supersede the originals for that quarter, and `accessionNumber` and `filingUrl` point at the filing each row actually came from. 13F reports cover long US-listed equity positions (plus listed options, flagged via `putCall`). Short positions, swaps, and non-US holdings are not reportable, so a manager's 13F book is not their whole portfolio. Coverage is the 25 headline filers listed above, not every 13F filer. The set is curated for signal density; treat it as a panel of notable books rather than total institutional ownership of a stock. ## Related SEC Forms 3/4/5 insider transactions for the same companies. The unified events feed that carries `issuer_disclosure` (13D/G) events. The scored universe and entity resolution by ticker or CIK. Trace any holding back to its named SEC filing and ingestion run. # Interest rates Source: https://docs.financialdatapi.com/apis/interest-rates Policy rates, money-market benchmarks, 10-year government bond yields, and the 10Y-3M curve spread, per country, as point-in-time observations. The `rates` family is Financial Data API's interest-rate factor set: the short end (policy and money-market rates), the long end (10-year government bond yields), and a curve measure (the 10Y-3M spread), each with a stable canonical indicator ID that means the same thing in every country. Query the UK policy rate, the US 10-year yield, and a country's curve spread with the same slugs and filters, and join across countries cleanly. This page leads with the rate series that are available and their units, then shows how to read them through the two observation endpoints. ## What data is available The `rates` family spans the covered countries, built from a small set of canonical rate shapes, one per country where it exists: The central bank's headline policy rate. Unit: `percent`. The short-end money-market benchmark. Unit: `percent`. The 10-year sovereign benchmark yield. Unit: `percent`. The slope of the curve: 10-year yield minus the 3-month rate. Unit: `percentage_points`. These shapes span the covered countries (plus 2/5/30-year yields where published); the exact per-country availability is live, so treat this as a map and read the authoritative, machine-readable list from `GET /canonical-indicators` and the breadth summary from `GET /coverage`. ### Units Rate series carry an explicit `unit`. Two units appear in this family, and branching on `unit` matters because levels and spreads are not the same thing: Rate levels: Policy Rate, 3-Month Money-Market Benchmark Rate, 10-Year Government Bond Yield. A value of `4.5` means 4.5 percent. Differences between two rates: the 10Y-3M Yield-Curve Spread. A value of `-0.4` means the 10-year yield is 0.4 percentage points below the 3-month rate (an inverted curve). A `percent` value is a level you can read directly. A `percentage_points` value is a gap: it can be negative when the curve is inverted (short rates above long rates). Do not treat the two units as interchangeable. ### Country coverage Rate series are keyed by ISO 3166-1 alpha-3 country code, drawn from the same covered macro universe: ```text theme={"theme":"css-variables"} ARE AUS CAN CHE DEU EUR GBR HKG JPN KOR NOR NZL QAT SAU SGP SWE USA ``` Coverage is not uniform: not every country carries all four rate series, so the family totals fewer series than four times the country count. Confirm exactly which rate series a country carries with `GET /coverage` and resolve the live indicator universe with `GET /canonical-indicators`. These are rate and yield series sourced from institutions of record. Financial Data API publishes official daily [FX reference rates](/apis/fx) separately, but it does not sell raw vendor or real-time market price-tick data: that is redistribution-blocked and deliberately not part of the product. ## Canonical indicator IDs Each rate series has a canonical indicator ID, a stable slug identical across countries, returned on every observation as `indicatorId`. You query by it and join on it. The complete, current list of rate indicator IDs (with names, families, and units) is served live: ```bash cURL theme={"theme":"css-variables"} curl -s "https://api.financialdatapi.com/canonical-indicators" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` ```typescript TypeScript (@financialdatapi/client) theme={"theme":"css-variables"} import { FinancialDataApiClient } from "@financialdatapi/client"; const client = new FinancialDataApiClient({ apiKey: process.env.FINANCIALDATA_API_KEY }); const indicators = await client.listIndicators(); const rates = indicators.data.filter((ind) => ind.category === "rates"); for (const ind of rates) { console.log(ind.indicatorId, ind.indicatorName, ind.unit); } ``` Use `GET /canonical-indicators` to confirm the exact rate slug for the country you want before building queries. Financial Data API fails closed on unknown query parameters and rejects unrecognized indicators with `bad_request`. ## Querying the data Rate values are served as observations, the same as every other macro factor. An observation is a single value a series describes for a single period, for example the US 10-year government bond yield on a given day. Two public endpoints cover the two shapes you need: a time series, and the latest value per indicator. The history. Time series of public rate observations across periods and vintages. Cursor-paginated. The snapshot. The single latest public reading per rate indicator. The fastest way to ask "where are rates now." Both endpoints go to `https://api.financialdatapi.com`, require a key with the `data:read` scope, and send the key in the `x-api-key` header (or `Authorization: Bearer`). They share one filter set and one response shape. ### Authentication ```bash theme={"theme":"css-variables"} -H "x-api-key: $FINANCIALDATA_API_KEY" ``` A `data:read` scope is required. See [Authentication](/authentication). ### Filters Both endpoints accept the same filters. Combine them freely; they are AND-ed. Unknown query parameters are rejected with `bad_request` (Financial Data API fails closed). ISO 3166-1 alpha-3 country code, for example `USA`, `GBR`, `DEU`. One of the covered countries. Canonical rate indicator slug. Also accepted as `indicator_id`. Omit it to pull a country's full set of latest readings in one query, then keep the rate series by matching each row's `indicatorId` against the rate indicator IDs from `/canonical-indicators` (where `category` is `rates`). Publication cadence: `daily`, `weekly`, `monthly`, `quarterly`, or `annual`. Keep only readings with a given freshness label: `fresh`, `stale`, or `unknown`. The label is set by a per-frequency age gate, independent of any source self-report. Financial Data API source id. Filter to a single institution of record. Financial Data API provider id or name. Also accepted as `provider`. Time filters run on two axes (period: what a value describes; knowledge-time: when it became known): Convenience filter on the described period: `YYYY`, `YYYY-MM`, or `YYYY-Qn`. Upper bound on the described period (`YYYY-MM-DD`). Lower bound on knowledge-time (`observed_at`). Upper bound on knowledge-time (`observed_at`). Returns the latest vintage known on or before a timestamp. See the caveat below. Page size, 1 to 500. Defaults to 100. Follow `meta.pagination.next_cursor` with `cursor` while `has_more` is true. `sort` and `order` (`asc`, `desc`) control ordering. `as_of` currently approximates the ingestion timestamp, not full provider-vintage reconstruction. Revisions are retained and never overwritten, so the revision history is visible, but reconstructing the exact value a provider had published at an arbitrary past instant is future work. Read `as_of` as "what Financial Data API knew by this time." ### Response fields Public observations come back in camelCase. The fields most relevant to rate series: Stable ID for this observation. Pass it to `GET /provenance/observations/{observationId}` for the full source chain. Canonical rate indicator slug. Use it to query and join across countries. Human-readable indicator name, for example `10-Year Government Bond Yield`. ISO 3166-1 alpha-3 country code. The headline numeric value. A rate level (in `percent`) or a spread (in `percentage_points`), per `unit`. `percent` for rate levels, `percentage_points` for the curve spread. Label for the period the value describes, for example `2026-06-10`. End of the described period (`YYYY-MM-DD`). Publication cadence. Knowledge-time: the point at which the value is observed. Freshness label: `fresh`, `stale`, or `unknown`. The provider name behind the source, for example `Bank of England`. The official source URL for the series. Whether a raw payload reference is exposed for this observation through the provenance endpoint. ## Examples ### A country's full rates set (latest) Pull every rate series Financial Data API holds for one country in a single latest call, then keep the `rates` family. Because `/observations/latest` returns the latest reading per canonical indicator, one country query gives you the policy rate, the money-market benchmark, the 10-year yield, and the curve spread together. ```bash cURL theme={"theme":"css-variables"} curl -s "https://api.financialdatapi.com/observations/latest?country=USA" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` ```typescript TypeScript (@financialdatapi/client) theme={"theme":"css-variables"} import { FinancialDataApiClient } from "@financialdatapi/client"; const client = new FinancialDataApiClient({ apiKey: process.env.FINANCIALDATA_API_KEY }); // Discover the rate indicator IDs once, then keep only those from the latest readings. const catalog = await client.listIndicators(); const rateIds = new Set(catalog.data.filter((ind) => ind.category === "rates").map((ind) => ind.indicatorId)); const { data } = await client.getLatestObservations({ country: "USA" }); const rates = data.filter((obs) => rateIds.has(obs.indicatorId)); for (const obs of rates) { console.log(obs.indicatorName, obs.actual, obs.unit); } ``` A latest rates response looks like this: ```json theme={"theme":"css-variables"} { "data": [ { "observationId": "obs_us_policy_rate_2026_06_10", "indicatorId": "policy_rate", "indicatorName": "Policy Rate", "country": "USA", "actual": 4.5, "unit": "percent", "period": "2026-06-10", "periodEnd": "2026-06-10", "frequency": "daily", "observedAt": "2026-06-10T00:00:00Z", "freshnessStatus": "fresh", "provider": "Federal Reserve (via FRED)", "sourceUrl": "https://fred.stlouisfed.org/", "rawAvailable": false }, { "observationId": "obs_us_govt_bond_yield_10y_2026_06_10", "indicatorId": "govt_bond_yield_10y", "indicatorName": "10-Year Government Bond Yield", "country": "USA", "actual": 4.1, "unit": "percent", "period": "2026-06-10", "periodEnd": "2026-06-10", "frequency": "daily", "observedAt": "2026-06-10T00:00:00Z", "freshnessStatus": "fresh", "provider": "Federal Reserve (via FRED)", "sourceUrl": "https://fred.stlouisfed.org/", "rawAvailable": false } ], "meta": { "request_id": "a1b2...", "requestId": "a1b2...", "api_version": "v1", "pagination": { "limit": 100, "cursor": null, "next_cursor": null, "has_more": false } }, "requestId": "a1b2..." } ``` The `indicatorId` values above (`policy_rate`, `govt_bond_yield_10y`) illustrate the shape of a rate slug. Confirm the exact IDs from `GET /canonical-indicators` for the country you query. ### 10-year yield history Pull the time series of a country's 10-year government bond yield, oldest first. ```bash cURL theme={"theme":"css-variables"} curl -s "https://api.financialdatapi.com/observations?country=USA&indicator=govt_bond_yield_10y&period=2025&order=asc&limit=500" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` ```typescript TypeScript (@financialdatapi/client) theme={"theme":"css-variables"} import { FinancialDataApiClient } from "@financialdatapi/client"; const client = new FinancialDataApiClient({ apiKey: process.env.FINANCIALDATA_API_KEY }); for await (const obs of client.paginate("/observations", { country: "USA", indicator: "govt_bond_yield_10y", order: "asc", })) { console.log(obs.periodEnd, obs.actual); } ``` ### The curve-spread series The 10Y-3M Yield-Curve Spread is a first-class series in `percentage_points`: read it directly rather than computing it. A negative value means an inverted curve (short rates above long rates). ```bash cURL theme={"theme":"css-variables"} curl -s "https://api.financialdatapi.com/observations/latest?country=USA&indicator=yield_curve_spread_10y_3m" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` ```typescript TypeScript (@financialdatapi/client) theme={"theme":"css-variables"} import { FinancialDataApiClient } from "@financialdatapi/client"; const client = new FinancialDataApiClient({ apiKey: process.env.FINANCIALDATA_API_KEY }); const { data } = await client.getLatestObservations({ country: "USA", indicator: "yield_curve_spread_10y_3m", }); const spread = data[0]; console.log( spread.actual, spread.unit, spread.actual < 0 ? "inverted" : "upward sloping", ); ``` Financial Data API also serves stored rates analytics (curve spreads and more) as derived indicators, where each derived value records its input observation IDs and source refs. See [Derived analytics](/apis/derived-analytics). ## Provenance Every rate value traces back to an official release. Pass an `observationId` to the provenance endpoint for the named source, source URL, raw payload reference metadata, and the ingestion run. ```bash theme={"theme":"css-variables"} curl -s "https://api.financialdatapi.com/provenance/observations/obs_us_policy_rate_2026_06_10" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` Rate series draw on institutions of record, including FRED, ECB, BIS, Bank of England, and Bank of Japan, across roughly 87 source connectors (53 providers). ## Errors Non-2xx responses share the standard envelope with a stable, machine-readable `code`. | Code | Status | Meaning | | ---------------- | ------ | -------------------------------------------------------------------------- | | `bad_request` | 400 | Malformed query, an unknown query parameter, or an unrecognized indicator. | | `unauthorized` | 401 | Missing or invalid API key. | | `forbidden` | 403 | Key lacks the `data:read` scope. | | `not_found` | 404 | Resource does not exist. | | `rate_limited` | 429 | Rate limit exceeded; see `details`. | | `internal_error` | 500 | Unexpected server error. | ## Related Inflation, labor, growth, housing, external, income, and consumption factors. Stored rates analytics, curve spreads, and other derived indicators with input provenance. Central-bank actions and scheduled rate decisions as official events. # Macro indicators Source: https://docs.financialdatapi.com/apis/macro-indicators Canonical macro factors (inflation, labor, growth, housing, external, income, consumption) as point-in-time observations across 17 countries. Financial Data API's macro factor data is a set of canonical economic indicators, each with a stable ID that means the same thing in every country. Query US CPI, UK unemployment, and German GDP growth with the same indicator slugs and the same filters, and join across countries without reconciling vendor field names. This page leads with the data that is available (the indicator families, the real series in each, and the country coverage), then shows how to read it through the two observation endpoints. ## What data is available Public canonical indicators are grouped into families. The counts and series below describe the macro families (interest rates have [their own page](/apis/interest-rates)). The catalog is live, so treat the table as a map and read the authoritative, machine-readable list from `GET /canonical-indicators` and the breadth summary from `GET /coverage`. | Family | Indicators | Real series in this family | | ------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `inflation` | 13 | CPI Inflation YoY, Core CPI, CPI index, Core CPI index, PCE Price Index, Core PCE Price Index, Producer Price Index (PPI), plus per-country CPI YoY (US, Euro Area, UK, Japan, and more). | | `labor` | 11 | Unemployment Rate, Nonfarm Payroll Employment, Initial Jobless Claims, plus per-country unemployment. | | `growth` | 9 | Real GDP Growth and GDP Growth, per country. | | `housing` | 2 | Housing Starts, Building Permits (US). | | `external` | 3 | Trade Balance, Exports, Imports (US). | | `income` | 1 | Personal Income (US). | | `consumption` | 1 | Retail Sales (US). | Interest-rate series (Policy Rate, 3-Month Money-Market Benchmark Rate, 10-Year Government Bond Yield, and the 10Y-3M Yield-Curve Spread) live in the `rates` family. See [Interest rates](/apis/interest-rates). ### Units you will see Macro values carry an explicit `unit`. Across these families the units are: Rates of change and ratios: CPI Inflation YoY, Real GDP Growth, Unemployment Rate. Level indices: CPI index, Core CPI index, PCE Price Index. Counts in thousands: Nonfarm Payroll Employment, Initial Jobless Claims, Housing Starts, Building Permits. Headcounts reported in persons where the source publishes them that way. External-sector flows: Trade Balance, Exports, Imports. Always branch on the `unit` field rather than assuming. The same family can mix a rate (`percent`) and a level (`index`), and a count series can be reported in `thousands` or `persons` depending on the source. ### Country coverage The macro catalog spans 17 countries and region codes, keyed by ISO 3166-1 alpha-3 code. Per-country breadth varies — a core set (USA, the euro area, GBR, JPN, AUS, CAN, CHE, NZL) carries the full factor set, others a subset: ```text theme={"theme":"css-variables"} ARE AUS CAN CHE DEU EUR GBR HKG JPN KOR NOR NZL QAT SAU SGP SWE USA ``` Coverage is not uniform across every series. Some indicators (for example Housing Starts, Building Permits, Trade Balance, Personal Income, Retail Sales) are US-only in the catalog, while CPI Inflation YoY, Unemployment Rate, and GDP Growth are broad. Check exactly what a country carries with `GET /coverage`, and resolve the live indicator universe with `GET /canonical-indicators`. Financial Data API publishes official daily [FX reference rates](/apis/fx) (the `fx` category), but it does not sell raw vendor or real-time market price-tick data: that is redistribution-blocked and deliberately not part of the product. For derived rate analytics (curve spreads and more) see [Derived analytics](/apis/derived-analytics). ## Canonical indicator IDs Every series has a canonical indicator ID, a stable slug that is identical across countries. You query by it, you join on it, and you read it back on every observation as `indicatorId`. Examples: | Indicator ID | Indicator | Typical unit | | ------------------- | ----------------------------- | ------------ | | `cpi_inflation_yoy` | CPI Inflation, year over year | `percent` | | `unemployment_rate` | Unemployment Rate | `percent` | | `gdp_growth` | GDP Growth | `percent` | These three are illustrative, not the full set. The complete, current list of indicator IDs (with names, families, and units) is served live: ```bash cURL theme={"theme":"css-variables"} curl -s "https://api.financialdatapi.com/canonical-indicators" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` ```typescript TypeScript (@financialdatapi/client) theme={"theme":"css-variables"} import { FinancialDataApiClient } from "@financialdatapi/client"; const client = new FinancialDataApiClient({ apiKey: process.env.FINANCIALDATA_API_KEY }); const indicators = await client.listIndicators(); for (const ind of indicators.data) { console.log(ind.indicatorId, ind.category, ind.unit); } ``` Use `GET /canonical-indicators` as the source of truth for valid IDs before you build queries. Financial Data API fails closed on unknown query parameters and rejects nonexistent indicators with `bad_request`, so confirming the slug first saves a round trip. ## Querying the data Macro indicator values are served as observations. An observation is a single value a series describes for a single period, for example May 2026 US CPI Inflation YoY. Two public endpoints cover the two shapes you need: a time series, and the latest value per indicator. The history. Time series of public observations across periods and vintages. Cursor-paginated. The snapshot. The single latest public reading per canonical indicator. The fastest way to ask "where are things now." Both endpoints go to `https://api.financialdatapi.com`, require a key with the `data:read` scope, and send the key in the `x-api-key` header (or `Authorization: Bearer`). They share one filter set and one response shape. ### Authentication ```bash theme={"theme":"css-variables"} -H "x-api-key: $FINANCIALDATA_API_KEY" ``` A `data:read` scope is required. A handful of endpoints need no key (`/health`, `/ready`, `/openapi.json`, `/llms.txt`, `/llms-full.txt`), but the observation endpoints are not among them. See [Authentication](/authentication). ### Filters Both endpoints accept the same filters. Combine them freely; they are AND-ed. Unknown query parameters are rejected with `bad_request` (Financial Data API fails closed rather than silently ignoring typos). ISO 3166-1 alpha-3 country code, for example `USA`, `GBR`, `JPN`. One of the covered countries. Canonical indicator slug, for example `cpi_inflation_yoy`. Also accepted as `indicator_id`. Publication cadence: `daily`, `weekly`, `monthly`, `quarterly`, or `annual`. Keep only readings with a given freshness label: `fresh`, `stale`, or `unknown`. The label is set by a per-frequency age gate, independent of any source self-report. Financial Data API source id, for example `source_bls_public_api`. Filter to a single institution of record. Financial Data API provider id or name. Also accepted as `provider`. Time filters run on two axes (period: what a value describes; knowledge-time: when it became known): Convenience filter on the described period: `YYYY`, `YYYY-MM`, or `YYYY-Qn`. Upper bound on the described period (`YYYY-MM-DD`). Lower bound on knowledge-time (`observed_at`). Upper bound on knowledge-time (`observed_at`). Returns the latest vintage known on or before a timestamp. See the caveat below. Page size, 1 to 500. Defaults to 100. Follow `meta.pagination.next_cursor` with `cursor` while `has_more` is true. `sort` and `order` (`asc`, `desc`) control ordering. `as_of` currently approximates the ingestion timestamp, not full provider-vintage reconstruction. Revisions are retained and never overwritten, so the revision history is visible, but reconstructing the exact value a provider had published at an arbitrary past instant is future work. Read `as_of` as "what Financial Data API knew by this time." ### Response fields Public observations come back in camelCase. The fields most relevant to macro indicators: Stable ID for this observation. Pass it to `GET /provenance/observations/{observationId}` for the full source chain. Canonical indicator slug, for example `cpi_inflation_yoy`. Use it to query and join across countries. Human-readable indicator name, for example `CPI Inflation (YoY)`. ISO 3166-1 alpha-3 country code. The headline numeric value of the reading. Unit of the value, for example `percent`, `index`, `thousands`, `persons`, `USD millions`. Label for the period the value describes, for example `2026-05`. End of the described period (`YYYY-MM-DD`). Publication cadence: `daily`, `weekly`, `monthly`, `quarterly`, or `annual`. Knowledge-time: the point at which the value is observed. Freshness label: `fresh`, `stale`, or `unknown`. The provider name behind the source, for example `U.S. Bureau of Labor Statistics`. The official source URL for the series. Whether a raw payload reference is exposed for this observation through the provenance endpoint. ## Examples ### Latest US CPI inflation Get the single latest US CPI Inflation YoY reading. ```bash cURL theme={"theme":"css-variables"} curl -s "https://api.financialdatapi.com/observations/latest?country=USA&indicator=cpi_inflation_yoy" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` ```typescript TypeScript (@financialdatapi/client) theme={"theme":"css-variables"} import { FinancialDataApiClient } from "@financialdatapi/client"; const client = new FinancialDataApiClient({ apiKey: process.env.FINANCIALDATA_API_KEY }); const { data } = await client.getLatestObservations({ country: "USA", indicator: "cpi_inflation_yoy", }); console.log(data[0].actual, data[0].unit, data[0].period); ``` A public observation looks like this: ```json theme={"theme":"css-variables"} { "data": [ { "observationId": "obs_us_cpi_inflation_yoy_2026_05", "indicatorId": "cpi_inflation_yoy", "indicatorName": "CPI Inflation (YoY)", "country": "USA", "actual": 3.4, "unit": "percent", "period": "2026-05", "periodEnd": "2026-05-31", "frequency": "monthly", "observedAt": "2026-06-11T12:30:00Z", "freshnessStatus": "fresh", "provider": "U.S. Bureau of Labor Statistics", "sourceUrl": "https://www.bls.gov/cpi/", "rawAvailable": false } ], "meta": { "request_id": "0c8f...", "requestId": "0c8f...", "api_version": "v1", "pagination": { "limit": 100, "cursor": null, "next_cursor": null, "has_more": false } }, "requestId": "0c8f..." } ``` ### US CPI inflation history Pull the full vintage history of US CPI Inflation YoY, oldest first. ```bash cURL theme={"theme":"css-variables"} curl -s "https://api.financialdatapi.com/observations?country=USA&indicator=cpi_inflation_yoy&period=2020&order=asc&limit=500" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` ```typescript TypeScript (@financialdatapi/client) theme={"theme":"css-variables"} import { FinancialDataApiClient } from "@financialdatapi/client"; const client = new FinancialDataApiClient({ apiKey: process.env.FINANCIALDATA_API_KEY }); // paginate() auto-follows the cursor across every page for await (const obs of client.paginate("/observations", { country: "USA", indicator: "cpi_inflation_yoy", order: "asc", })) { console.log(obs.periodEnd, obs.actual); } ``` ### Latest unemployment across a country set, fresh only Compare the latest Unemployment Rate, keeping only values that pass the freshness gate. Query country by country with the shared `indicator` and `freshness` filters. ```bash cURL theme={"theme":"css-variables"} curl -s "https://api.financialdatapi.com/observations/latest?country=GBR&indicator=unemployment_rate&freshness=fresh" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` ```typescript TypeScript (@financialdatapi/client) theme={"theme":"css-variables"} import { FinancialDataApiClient } from "@financialdatapi/client"; const client = new FinancialDataApiClient({ apiKey: process.env.FINANCIALDATA_API_KEY }); const countries = ["USA", "GBR", "DEU", "JPN", "CAN"]; for (const country of countries) { const { data } = await client.getLatestObservations({ country, indicator: "unemployment_rate", freshness: "fresh", }); if (data.length) { console.log(country, data[0].actual, data[0].unit); } } ``` ## Provenance Every macro value traces back to an official release. Pass an `observationId` to the provenance endpoint for the named source, source URL, raw payload reference metadata, and the ingestion run. ```bash theme={"theme":"css-variables"} curl -s "https://api.financialdatapi.com/provenance/observations/obs_us_cpi_inflation_yoy_2026_05" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` Sources behind the macro families are institutions of record, including FRED, BLS, ECB, OECD, BIS, Eurostat, Bank of England, and Bank of Japan, across roughly 87 source connectors (53 providers). ## Errors Non-2xx responses share the standard envelope with a stable, machine-readable `code`. | Code | Status | Meaning | | ---------------- | ------ | -------------------------------------------------------------------------- | | `bad_request` | 400 | Malformed query, an unknown query parameter, or an unrecognized indicator. | | `unauthorized` | 401 | Missing or invalid API key. | | `forbidden` | 403 | Key lacks the `data:read` scope. | | `not_found` | 404 | Resource does not exist. | | `rate_limited` | 429 | Rate limit exceeded; see `details`. | | `internal_error` | 500 | Unexpected server error. | ## Related Policy Rate, 3-Month Money-Market Benchmark Rate, 10-Year Government Bond Yield, and the 10Y-3M Yield-Curve Spread. Scheduled and released macro events with actual, forecast, consensus, previous, and revised values. Surprise indices, COT positioning percentiles, valuation multiples, and rates analytics. # Positioning Source: https://docs.financialdatapi.com/apis/positioning Raw CFTC Commitments of Traders (COT) and Traders in Financial Futures (TFF) positioning, in the same observation model as macro. Financial Data API carries the U.S. Commodity Futures Trading Commission's weekly positioning reports as first-class observations: the **Commitments of Traders (COT)** report and the **Traders in Financial Futures (TFF)** report. They sit under the `positioning` category, with full history and provenance, so you can read how each trader cohort is positioned across futures markets and join it against price, macro, and rates. This page covers the **raw** positioning series. For positioning expressed as a historical percentile (how stretched a cohort is versus its own history), see the `cot_positioning_percentile` dataset on [Derived analytics](/apis/derived-analytics). ## What data is available CFTC Commitments of Traders — non-commercial (speculator) and commercial long/short positions and open interest, per reported futures market, weekly. Traders in Financial Futures — leveraged-funds and asset-manager long/short positioning (with the full breakdown and open interest in metadata), weekly. Positioning rows are keyed by the reported futures market (identified in the observation metadata and provenance), not by country. The reports are published weekly by the CFTC, typically on a Friday for the prior Tuesday. ## Query positioning ```bash cURL theme={"theme":"css-variables"} # Latest positioning rows curl "https://api.financialdatapi.com/observations/latest?indicator_id=cot_positioning" \ -H "x-api-key: $FINANCIALDATA_API_KEY" # TFF history curl "https://api.financialdatapi.com/observations?indicator_id=cot_tff&limit=20&order=desc" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` ```typescript TypeScript theme={"theme":"css-variables"} import { FinancialDataApiClient } from "@financialdatapi/client"; const client = new FinancialDataApiClient({ apiKey: process.env.FINANCIALDATA_API_KEY }); const { data } = await client.getLatestObservations({ indicator_id: "cot_positioning" }); console.log(data); ``` ## Response shape Each row is a standard public observation. The fields most relevant here: `cot_positioning` or `cot_tff`. `positioning`. The headline positioning value for the row (for example the cohort's net position). The per-cohort breakdown (long, short, open interest) and the futures market the row describes. `U.S. Commodity Futures Trading Commission`. The report (as-of-Tuesday) date. The cohort breakdown is in `metadata`; read it from the row, and use `GET /provenance/observations/{observationId}` for the full chain back to the CFTC release. ## Related COT positioning expressed as a historical percentile. EIA energy market data. # Authentication Source: https://docs.financialdatapi.com/authentication Authenticate Financial Data API requests with an API key, choose a header form, and understand scopes. Financial Data API authenticates every data request with an API key sent in an HTTP header. Create and manage keys in the [dashboard](https://app.financialdatapi.com): sign up, verify your email, and your key works immediately. See [Pricing](/pricing) for per-tier limits. Keys are SHA-256 hashed server-side and never shown again, so store yours securely the moment you create it. Treat your API key like a password. Keep it out of client-side code, public repositories, and shared logs. If a key is ever exposed, rotate it immediately in the dashboard. Anyone holding the key can make requests with its scopes. ## Send your key You can pass the key in either of two header forms. Both are equivalent. Pick one and use it consistently. ```bash x-api-key header theme={"theme":"css-variables"} curl "https://api.financialdatapi.com/observations/latest?country=USA" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` ```bash Authorization Bearer theme={"theme":"css-variables"} curl "https://api.financialdatapi.com/observations/latest?country=USA" \ -H "Authorization: Bearer $FINANCIALDATA_API_KEY" ``` In application code, set the header once on a client or session: ```python Python theme={"theme":"css-variables"} import os, requests session = requests.Session() session.headers["x-api-key"] = os.environ["FINANCIALDATA_API_KEY"] resp = session.get( "https://api.financialdatapi.com/observations/latest", params={"country": "USA"}, ) print(resp.json()["data"]) ``` ```typescript TypeScript theme={"theme":"css-variables"} import { FinancialDataApiClient } from "@financialdatapi/client"; // The SDK sends the key on every request for you. const client = new FinancialDataApiClient({ apiKey: process.env.FINANCIALDATA_API_KEY }); const res = await client.getLatestObservations({ country: "USA" }); console.log(res.data); ``` ## Scopes Each key is granted one or more scopes. A scope controls which families of routes the key may call. Calling a route your key lacks the scope for returns `403 forbidden`. | Scope | Grants access to | Typical use | | ----------- | ---------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | | `data:read` | Product and data routes (observations, indicators, countries, entities, the screener, fundamentals, derived analytics) | Application and research workloads | | `ops:read` | Operational routes (liveness, manifest, snapshot, source health) | Monitoring feed freshness and sync status | | `admin` | Sensitive admin routes | Administration. `admin` also satisfies the lower scopes | `admin` is a superset: a key with `admin` can also call `data:read` and `ops:read` routes. Request the narrowest scope that covers your use case. ## Endpoints that need no key A small set of discovery and health endpoints are open and require no authentication: * `GET /health` * `GET /ready` * `GET /openapi.json` * `GET /llms.txt` * `GET /llms-full.txt` The `/llms.txt` and `/llms-full.txt` files are agent-readable indexes of the API, designed so an AI agent can discover Financial Data API before it ever holds a key. ## Errors Authentication and authorization failures use the standard Financial Data API error envelope with a stable machine-readable `code`: No key was supplied, or the key is invalid. Check that the header is present and the value is correct. The key is valid but lacks the scope required by the route. Request a key with the needed scope (or use an `admin` key). ```json 401 unauthorized theme={"theme":"css-variables"} { "error": { "code": "unauthorized", "message": "Missing or invalid API key.", "request_id": "0c8f...", "requestId": "0c8f...", "details": {} }, "requestId": "0c8f..." } ``` ## Rate limits Rate limits are enforced per client, per required scope, in a fixed window. Every API response includes the current limit state in headers: | Header | Meaning | | ----------------------- | ---------------------------------------- | | `x-ratelimit-policy` | The policy applied to this request | | `x-ratelimit-limit` | Maximum requests allowed in the window | | `x-ratelimit-remaining` | Requests remaining in the current window | | `x-ratelimit-reset` | When the window resets (ISO timestamp) | Default limits use a 60-second window: `data:read` allows 1000 requests per minute, `ops:read` allows 500 per minute, and `admin` allows 250 per minute. When you exceed a limit, Financial Data API returns `429 rate_limited` with `details` describing the breach: ```json 429 rate_limited theme={"theme":"css-variables"} { "error": { "code": "rate_limited", "message": "Rate limit exceeded.", "request_id": "0c8f...", "requestId": "0c8f...", "details": { "required_scope": "data:read", "limit": 1000, "window_seconds": 60 } }, "requestId": "0c8f..." } ``` Read `x-ratelimit-remaining` and `x-ratelimit-reset` from successful responses to pace your requests before you hit a `429`, and back off until the reset time when you do. ## Next steps Make your first authenticated call and page through results. Browse every endpoint, parameter, and response field. # Changelog Source: https://docs.financialdatapi.com/changelog Notable changes to the Financial Data API, newest first. This page records notable, user-facing changes to the Financial Data API. The contract itself always lives in [`openapi.json`](/api-reference/openapi.json), and live breadth is reported by [`/v1/public/coverage`](https://api.financialdatapi.com/v1/public/coverage). Deeper history across positioning, valuation, and US housing. All items below are served through the existing `GET /v1/public/observations` route (`indicator_id` plus `entity` / `start_date` / `end_date`) and the `get_observations` MCP tool. **Data surface** * **COT positioning percentile history.** `cot_positioning_percentile` now serves its full weekly panel — 1992 to today, 244,944 rows across 972 CFTC contracts (delisted contracts retained as valid history) — instead of the latest value only. The value is the 3-year midrank percentile (0–100) of net non-commercial positioning, derived from CFTC legacy COT stored back to 1986. `valueText` flags `crowded_long` (at or above 90) and `crowded_short` (at or below 10); metadata carries `net`, `weeklyChange`, `percentile1y`, `percentile3y`, and `zScore3y`. * **New indicator: `cot_tff_percentile`.** The same percentile statistics over Traders in Financial Futures leveraged-funds net positioning: weekly, 2006 to today, 41,398 rows across 117 financial futures (FX, rates, equity index). Same metadata shape. * **Valuation multiples: deep history.** All 13 trailing multiples (P/E, P/B, P/S, P/FCF, P/OCF, EV/EBITDA, EV/EBIT, EV/Sales, EV/FCF, earnings yield, FCF yield, dividend yield, PEG) now span 2007 to today — roughly 75,000 rows per headline multiple across \~500 US companies — computed from raw as-traded prices with point-in-time trailing-twelve-month fundamentals. * **US housing, deep and public.** `us_housing_starts` (monthly since 1959) and `us_building_permits` (monthly since 1960), both in thousands of units (SAAR), sourced from FRED `HOUST` and `PERMIT`. * **New indicator: `cb_statement_sentiment`.** Deterministic hawk/dove sentiment for every FOMC policy statement — 244 statements, February 1994 to today, keyed to `country_usa`. Score in \[−1, +1] from a versioned phrase lexicon (`fdapi_hawk_dove_v1`); `valueText` labels `hawkish` / `dovish` / `neutral`; metadata carries the matched phrases, counts, and `deltaVsPrior` for a full audit trail. December 2008 scores −1.0, June 2022 scores +1.0. See [Derived analytics](/apis/derived-analytics#fomc-statement-sentiment). * **OECD confidence, deep history.** `business_confidence` and `consumer_confidence` now reach back to 1960 where the OECD publishes it — about 43,000 rows across all covered countries (previously 2024 onward only). * **EIA energy series, full history.** All 13 EIA series now carry their complete published history: WTI spot since 1986, Brent since 1987, Henry Hub natural gas since 1997, and the weekly petroleum inventory, production, and refinery panels since 1982 where available. Plan history windows apply: free-tier keys see the trailing 24 months of any series. See [Derived analytics](/apis/derived-analytics) for worked examples. The first public release of the Financial Data API. The surface below is stable under `/v1`, and every response reports `meta.api_version = "v1"`. **Data surface** * **Macro observations.** Point-in-time, official-source macro readings. Redistribution-safe data on `GET /v1/public/observations` and `GET /v1/public/observations/latest`; the full observation surface with attribution, freshness, and rights metadata on `GET /v1/observations`, `/v1/observations/latest`, and `/v1/observations/changes`. * **Screener.** `GET /v1/public/screener` filters countries and entities by latest canonical-indicator values, with the filter DSL fields discoverable at `GET /v1/public/screener/filters`. * **Coverage.** `GET /v1/public/coverage` returns a live breadth summary: catalog totals, public indicator categories, and covered countries. * **SEC fundamentals.** `GET /v1/public/companies` exposes the scored fundamentals universe (S\&P 500 union Nasdaq-100) with sector and industry inline. `GET /v1/companies/{idOrLookup}/financials` returns structured income, balance-sheet, and cash-flow statements from SEC XBRL. * **Derived analytics.** `GET /v1/derived-indicators` and `GET /v1/derived-observations` serve stored derived analytics, each carrying `inputObservationIds` and `sourceRefs`. * **Calendar and events.** `GET /v1/economic-calendar` and `GET /v1/events` (each with a `/{eventId}` detail route) cover the economic calendar and unified official events. * **Catalog routes.** `GET /v1/canonical-indicators`, `/v1/entities` (plus `/resolve`, `/{idOrSlug}`, and `/{entityId}/observations`), `/v1/countries` (plus `/{idOrIso}` and `/available-indicators`), and `/v1/indicators` (plus `/series` and `/entities`). **Trust and operations** * **Provenance.** `GET /v1/provenance/observations/{observationId}` returns an auditable chain from official release to API response: named source, source URL, raw payload reference metadata, and the ingestion run. * **Sync and manifest.** `GET /v1/manifest`, `/v1/snapshot`, and `/v1/source-health` support sync workflows and report source and connector freshness. * **Liveness.** `GET /v1/ops/liveness` runs a per-series cadence check to flag silently-frozen feeds. **Platform** * **Response envelope.** One shape for every response, with `data`, `meta`, and a `request_id` on success, and stable machine-readable `error.code` values on failure. Unknown query parameters fail closed. * **Bi-temporal time model.** Period filters describe the period a value covers; knowledge-time bounds and `as_of` describe when a value became known, with revisions retained, never overwritten. * **Authentication and scopes.** API keys via `x-api-key` or `Authorization: Bearer`, with `data:read`, `ops:read`, and `admin` scopes and per-scope rate limits. * **MCP server.** A native Model Context Protocol server with read-only tools (for example `screen_macro`, `get_latest_observations`, `cross_country`, `rates_analytics`, and `observation_provenance`) for Claude Code, Claude Desktop, and Cursor. * **TypeScript SDK.** The official `@financialdatapi/client` package with cursor auto-pagination and a `buildScreenerFilter` helper. * **Agent-readable index.** `GET /llms.txt` and `GET /llms-full.txt` publish a key-free API index for agents. This changelog starts at the first public release. Future entries will be added here, newest first, as the public surface changes. # Errors Source: https://docs.financialdatapi.com/concepts/errors The error envelope, every error code with its HTTP status, and how to use request_id with support. When a request fails, Financial Data API returns a JSON body with a stable, machine-readable error code and the same request identifier you would get on success. You can branch on `error.code` programmatically and quote `request_id` when you contact support. This page covers the error envelope, the full code table, the fail-closed behavior on unknown parameters, and how to use the request identifier. ## The error envelope Errors mirror the success [envelope](/concepts/response-envelope): an `error` object replaces `data`, and the request identifier is preserved at both the top level and inside `error`. ```json theme={"theme":"css-variables"} { "error": { "code": "bad_request", "message": "Unknown query parameter: 'contry'", "request_id": "8f1c2e90-7a4b-4c3d-9e21-2b6f0a1c4d55", "requestId": "8f1c2e90-7a4b-4c3d-9e21-2b6f0a1c4d55", "details": {} }, "requestId": "8f1c2e90-7a4b-4c3d-9e21-2b6f0a1c4d55" } ``` The error payload. Present instead of `data` on any failed request. A stable, machine-readable code. Branch on this, not on the human-readable message. See the table below. A human-readable description of what went wrong. Subject to change. Do not parse it. The request identifier, for tracing this failure server-side. The same identifier in camelCase. Optional structured context for the error. For example, a `rate_limited` error carries `required_scope`, `limit`, and `window_seconds`. May be empty. The request identifier, repeated at the envelope root. Identical to `error.request_id`. ## Error codes Codes are stable. The HTTP status always matches the code as listed here. | Code | HTTP status | Meaning | | ---------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------ | | `bad_request` | 400 | The request was malformed: an invalid value, a missing required field, or an unknown query parameter. | | `unauthorized` | 401 | No API key was provided, or the key is invalid. Send a valid key via `x-api-key` or `Authorization: Bearer`. | | `forbidden` | 403 | The key is valid but lacks the scope required for the route (for example, calling an `ops:read` route with a `data:read` key). | | `not_found` | 404 | The requested resource does not exist (for example, an unknown entity, observation, or event id). | | `rate_limited` | 429 | You exceeded the rate limit for your client and scope in the current window. See [Rate limits](/concepts/rate-limits). | | `internal_error` | 500 | An unexpected server error. Retry with backoff; if it persists, contact support with the `request_id`. | Branch your error handling on `error.code`, never on the HTTP status alone and never on the `message` string. The code is the part of the contract that is guaranteed stable. ## Fail closed on unknown parameters Financial Data API rejects unknown query parameters rather than silently ignoring them. If you send a parameter the endpoint does not recognize (for example, a typo like `contry` instead of `country`), the request fails with `bad_request` and a `400` status. This is deliberate. Silently ignoring a misspelled filter would return data that does not match what you asked for, which is worse than a clear error. Fail-closed means a typo surfaces immediately instead of quietly returning the wrong rows. ```bash A typo fails closed (cURL) theme={"theme":"css-variables"} curl -s "https://api.financialdatapi.com/observations?contry=USA" \ -H "x-api-key: $FINANCIALDATA_API_KEY" # -> 400 bad_request: Unknown query parameter: 'contry' ``` Check parameter spelling against the [OpenAPI spec](https://api.financialdatapi.com/openapi.json) when you get an unexpected `bad_request`. A rejected unknown parameter is the most common cause. ## Handling errors in code ```python Python (requests) theme={"theme":"css-variables"} import os import requests resp = requests.get( "https://api.financialdatapi.com/observations", headers={"x-api-key": os.environ["FINANCIALDATA_API_KEY"]}, params={"country": "USA", "indicator": "cpi_inflation_yoy"}, ) if not resp.ok: err = resp.json()["error"] print(f"[{err['code']}] {err['message']} (request_id={err['request_id']})") # branch on err["code"]: "rate_limited", "unauthorized", "bad_request", ... else: data = resp.json()["data"] ``` ```typescript TypeScript (fetch) theme={"theme":"css-variables"} const res = await fetch( "https://api.financialdatapi.com/observations?country=USA&indicator=cpi_inflation_yoy", { headers: { "x-api-key": process.env.FINANCIALDATA_API_KEY! } }, ); const body = await res.json(); if (!res.ok) { const { code, message, request_id } = body.error; console.error(`[${code}] ${message} (request_id=${request_id})`); // switch on code to decide whether to retry, re-auth, or fix the request } else { const data = body.data; } ``` ## Using request\_id with support Every error response carries a `request_id` (and its `requestId` twin). The value identifies your exact request in the server logs. When something looks wrong and you reach out for help, include: * the `request_id` from the failing response, * the `error.code` you received, * the full URL you called (with parameters). That triple lets support locate your request immediately, without guesswork. The 429 body, the limit headers, and backoff guidance. How errors mirror the success envelope. # Freshness and liveness Source: https://docs.financialdatapi.com/concepts/freshness-and-liveness Every observation carries a freshness label, gated per frequency. A separate liveness check detects feeds that have silently stopped updating. A value can be wrong in two ways: it can be old, or its source can have quietly died. Financial Data API addresses both. Every observation carries a **freshness label** computed against a per-frequency gate, and a separate **liveness check** watches every series for sources that have silently stopped updating. The first tells you about a single value. The second tells you about the health of the pipe feeding it. ## The freshness label Every observation includes a freshness label with one of three values: The value is recent enough for its frequency. The source is delivering on cadence. The value is older than its frequency gate allows. Usable, but treat with caution. Freshness could not be determined for this value. The label travels inline on the observation, so you can branch on it without a second request. ```bash theme={"theme":"css-variables"} # Latest US inflation, with its freshness label inline curl -G "https://api.financialdatapi.com/observations/latest" \ -H "x-api-key: $FINANCIALDATA_API_KEY" \ --data-urlencode "country=USA" \ --data-urlencode "indicator=cpi_inflation_yoy" ``` ### Filtering by freshness Most observation routes accept a `freshness` filter, so you can ask for only the values that pass the gate. One of `fresh`, `stale`, or `unknown`. Returns only observations with the matching label. ```bash cURL theme={"theme":"css-variables"} curl -G "https://api.financialdatapi.com/observations" \ -H "x-api-key: $FINANCIALDATA_API_KEY" \ --data-urlencode "country=USA" \ --data-urlencode "indicator=cpi_inflation_yoy" \ --data-urlencode "freshness=fresh" ``` ```python Python theme={"theme":"css-variables"} import os, requests resp = requests.get( "https://api.financialdatapi.com/observations", headers={"x-api-key": os.environ["FINANCIALDATA_API_KEY"]}, params={ "country": "USA", "indicator": "cpi_inflation_yoy", "freshness": "fresh", }, ) resp.raise_for_status() print(resp.json()["data"]) ``` ```typescript TypeScript theme={"theme":"css-variables"} import { FinancialDataApiClient } from "@financialdatapi/client"; const client = new FinancialDataApiClient({ apiKey: process.env.FINANCIALDATA_API_KEY }); const { data } = await client.getObservations({ country: "USA", indicator: "cpi_inflation_yoy", freshness: "fresh", }); console.log(data); ``` The public screener also accepts `freshness=fresh`, so you can screen countries on values that are confirmed current. See the screener guide for the filter DSL. ## Per-frequency freshness gates "Recent" means different things for different series. A daily FX reference rate that is a week old is badly stale; a quarterly GDP figure that is a week old is brand new. Financial Data API applies the freshness gate **per frequency**, so each series is judged against a window appropriate to how often it is published. A daily series and a quarterly series can both be labeled `fresh` while having very different ages, because each is measured against its own gate. The label answers "is this on cadence for its frequency?", not "how many days old is this in absolute terms?" This is why freshness is a label rather than a raw age: the gate encodes the expected cadence so you do not have to maintain a table of acceptable staleness per indicator yourself. ## Liveness: catching silently-frozen feeds Freshness tells you whether a value is recent. It does not, on its own, tell you whether a source has *stopped*. A feed that froze last month can keep returning the same last-known value, and each individual observation might still look defensible. Liveness exists to catch exactly that failure mode. Financial Data API runs a per-series liveness check that detects feeds which have silently stopped updating, across the connector fleet. You can read its results: ``` GET /ops/liveness ``` The operational routes require the `ops:read` scope. A key scoped only for `data:read` will receive `403 forbidden`. Request `ops:read` if you need to monitor feed health programmatically. ```bash cURL theme={"theme":"css-variables"} curl -G "https://api.financialdatapi.com/ops/liveness" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` ```python Python theme={"theme":"css-variables"} import os, requests resp = requests.get( "https://api.financialdatapi.com/ops/liveness", headers={"x-api-key": os.environ["FINANCIALDATA_API_KEY"]}, ) resp.raise_for_status() print(resp.json()["data"]) ``` ```typescript TypeScript theme={"theme":"css-variables"} import { FinancialDataApiClient } from "@financialdatapi/client"; const client = new FinancialDataApiClient({ apiKey: process.env.FINANCIALDATA_API_KEY }); const { data } = await client.request("/ops/liveness"); console.log(data); ``` Freshness and liveness answer different questions and you should monitor both. A value can be labeled `stale` simply because nothing new was due yet, and a value can look `fresh` while the source behind it has frozen. Use the freshness label per observation and the liveness check per series. ## Choosing the right signal Read the inline `freshness` label, or pass `freshness=fresh` to exclude anything past its gate. This is the per-value check. Poll `GET /ops/liveness` to catch sources that have silently frozen before they quietly corrupt your inputs. This is the per-series, fleet-wide check. `GET /source-health` reports source and connector freshness at the source level, complementing the per-series liveness check. Use the freshness label to judge a value and the liveness check to judge the pipe. Together they keep stale numbers and dead feeds out of your decisions. ## Related How knowledge time and vintage relate to when a value became known. Trace any observation back to its source and ingestion run. # Pagination Source: https://docs.financialdatapi.com/concepts/pagination Cursor-based pagination: follow next_cursor while has_more is true. Financial Data API list endpoints paginate with opaque cursors. You request a page, read `meta.pagination`, and follow `next_cursor` until `has_more` is `false`. Cursors are stable for the result set you started, so paging stays consistent even as new observations arrive. This page covers the query parameters, the `meta.pagination` block, and a complete loop in cURL and TypeScript. ## Query parameters All list endpoints accept the same paging controls. Page size, from 1 to 500. Defaults to 100. Larger pages mean fewer round trips; smaller pages mean lower latency per request. An opaque cursor that marks where the next page begins. Omit it on your first request. On every subsequent request, pass the `next_cursor` value from the previous response. Do not construct or parse cursor values: treat them as opaque tokens. The field to sort by. The set of sortable fields depends on the endpoint. Consult the [OpenAPI spec](https://api.financialdatapi.com/openapi.json) for what each endpoint supports. Sort direction: `asc` or `desc`. Defaults to `asc`. Unknown query parameters are rejected, not ignored. A misspelled parameter returns `bad_request`. See [Errors](/concepts/errors#fail-closed-on-unknown-parameters). ## The pagination block List responses carry the cursor state under `meta.pagination`. (Item responses do not paginate and omit this block.) The page size applied to this request. The cursor you supplied for this page, or `null` on the first page. The cursor to pass on your next request. `null` when there are no more pages. `true` when more pages remain. Loop while this is `true`. ```json First page response (truncated) theme={"theme":"css-variables"} { "data": [ /* up to `limit` observations */ ], "meta": { "request_id": "8f1c2e90-7a4b-4c3d-9e21-2b6f0a1c4d55", "requestId": "8f1c2e90-7a4b-4c3d-9e21-2b6f0a1c4d55", "api_version": "v1", "pagination": { "limit": 100, "cursor": null, "next_cursor": "eyJvIjoxMDB9", "has_more": true } }, "requestId": "8f1c2e90-7a4b-4c3d-9e21-2b6f0a1c4d55" } ``` ## The loop The rule is one line: while `meta.pagination.has_more` is `true`, repeat the request with `cursor` set to the previous `next_cursor`. Stop when `has_more` is `false` (equivalently, when `next_cursor` is `null`). Call the endpoint with your filters and an optional `limit`. Do not send `cursor`. Read the items from `data`. If `meta.pagination.has_more` is `false`, you are done. Otherwise, request again with `cursor` set to `meta.pagination.next_cursor`, keeping the same filters, and return to step 2. ```bash cURL theme={"theme":"css-variables"} # Walk every page of USA CPI observations, 500 rows at a time. BASE="https://api.financialdatapi.com/observations" QUERY="country=USA&indicator=cpi_inflation_yoy&limit=500" CURSOR="" while : ; do if [ -z "$CURSOR" ]; then URL="$BASE?$QUERY" else URL="$BASE?$QUERY&cursor=$CURSOR" fi RESP=$(curl -s -H "x-api-key: $FINANCIALDATA_API_KEY" "$URL") echo "$RESP" | jq '.data[]' # process the page HAS_MORE=$(echo "$RESP" | jq -r '.meta.pagination.has_more') if [ "$HAS_MORE" != "true" ]; then break fi CURSOR=$(echo "$RESP" | jq -r '.meta.pagination.next_cursor') done ``` ```python Python (requests) theme={"theme":"css-variables"} import os import requests BASE = "https://api.financialdatapi.com/observations" HEADERS = {"x-api-key": os.environ["FINANCIALDATA_API_KEY"]} params = {"country": "USA", "indicator": "cpi_inflation_yoy", "limit": 500} cursor = None while True: page_params = {**params, **({"cursor": cursor} if cursor else {})} resp = requests.get(BASE, headers=HEADERS, params=page_params) resp.raise_for_status() body = resp.json() for obs in body["data"]: ... # process each observation page = body["meta"]["pagination"] if not page["has_more"]: break cursor = page["next_cursor"] ``` ```typescript TypeScript (@financialdatapi/client) theme={"theme":"css-variables"} import { FinancialDataApiClient } from "@financialdatapi/client"; const client = new FinancialDataApiClient({ apiKey: process.env.FINANCIALDATA_API_KEY! }); // The SDK auto-paginates: async iteration transparently follows // next_cursor while has_more is true, so you never touch a cursor. for await (const obs of client.paginate("/observations", { country: "USA", indicator: "cpi_inflation_yoy", limit: 500, })) { // process each observation across all pages console.log(obs.period, obs.actual); } ``` The official TypeScript SDK `@financialdatapi/client` handles the cursor loop for you. Async iteration walks every page behind the scenes, so the manual loop above is only needed when you call the API directly. ## Notes * Cursors are opaque. Their internal format is not part of the contract and may change. Read them from `next_cursor` and pass them back verbatim. * Keep your filters identical across pages. Changing `country`, `indicator`, `sort`, or `order` mid-walk invalidates the cursor. * A page may contain fewer than `limit` items and still have `has_more: true`. Always trust `has_more`, never the item count, to decide whether to continue. Where `meta.pagination` lives within the shared envelope. # Provenance Source: https://docs.financialdatapi.com/concepts/provenance Every observation traces back to its named source, source URL, raw payload reference, and ingestion run. One endpoint gives you an auditable chain from official release to API response. When a number drives a decision, you need to be able to defend where it came from. Financial Data API attaches provenance to every observation and exposes a dedicated endpoint that returns the full chain: the **named source**, the **source URL**, a **raw payload reference**, and the **ingestion run** that recorded it. Together these let you walk backward from any value in an API response to the official release it originated from. ## What every observation already carries You do not have to make a second call to get basic attribution. Observation responses include, inline: The named publisher the value came from (for example, a central bank or statistics office). A URL pointing at the originating release or dataset. The required attribution string for the value. The freshness label: `fresh`, `stale`, or `unknown`. Whether a captured upstream payload is on record for this value. The raw body itself is never returned; this flag proves the value was derived from a specific captured response, retrievable through the provenance endpoint as a reference. Rights and exposure metadata governing how the value may be used. The raw payload reference is an identifier, not the payload. Financial Data API never re-serves upstream provider bodies; the reference exists only to prove a value was derived from a specific captured response. ## The provenance endpoint For the complete auditable chain on a single observation, call: ``` GET /provenance/observations/{observationId} ``` The identifier of the observation you want to trace. You get this from any observation response. It returns the named source, the source URL, raw payload reference metadata, and the ingestion run that produced the value: an auditable chain from the official release all the way to the API response you received. ```bash cURL theme={"theme":"css-variables"} curl -G "https://api.financialdatapi.com/provenance/observations/obs_01HZX9K2P7QF3M4N5R6S7T8U9V" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` ```python Python theme={"theme":"css-variables"} import os, requests observation_id = "obs_01HZX9K2P7QF3M4N5R6S7T8U9V" resp = requests.get( f"https://api.financialdatapi.com/provenance/observations/{observation_id}", headers={"x-api-key": os.environ["FINANCIALDATA_API_KEY"]}, ) resp.raise_for_status() print(resp.json()["data"]) ``` ```typescript TypeScript theme={"theme":"css-variables"} import { FinancialDataApiClient } from "@financialdatapi/client"; const client = new FinancialDataApiClient({ apiKey: process.env.FINANCIALDATA_API_KEY }); const { data } = await client.getProvenance( "obs_01HZX9K2P7QF3M4N5R6S7T8U9V", ); console.log(data); ``` ### Example response ```json theme={"theme":"css-variables"} { "data": { "observation": { "observationId": "obs_01HZX9K2P7QF3M4N5R6S7T8U9V", "indicatorId": "cpi_inflation_yoy", "country": "USA", "actual": 3.2, "unit": "percent", "period": "May 2026", "periodEnd": "2026-05-31", "observedAt": "2026-06-11T12:30:00Z", "provider": "U.S. Bureau of Labor Statistics", "sourceUrl": "https://www.bls.gov/news.release/cpi.htm", "freshnessStatus": "fresh", "rawAvailable": true, "rights": { "exposureClass": "public" } }, "rawPayload": { "rawPayloadId": "raw_01HZX8B0C1D2E3F4G5H6J7K8M9", "sourceId": "src_bls_cpi", "providerId": "prv_bls", "ingestionRunId": "run_01HZX7A0YBQ2C3D4E5F6G7H8J9", "contentHash": "sha256:9f2c…", "retrievedAt": "2026-06-11T12:30:04Z", "rawAvailable": true }, "source": { "id": "src_bls_cpi", "name": "U.S. Bureau of Labor Statistics" }, "provider": { "id": "prv_bls", "name": "U.S. Bureau of Labor Statistics" }, "ingestionRun": { "id": "run_01HZX7A0YBQ2C3D4E5F6G7H8J9", "status": "completed", "startedAt": "2026-06-11T12:30:04Z", "completedAt": "2026-06-11T12:30:09Z" } }, "meta": { "api_version": "v1", "request_id": "f2b1c4a0-7d3e-4a8b-9c10-2e5f6a7b8c9d" }, "requestId": "f2b1c4a0-7d3e-4a8b-9c10-2e5f6a7b8c9d" } ``` Field names and the exact shape are defined by the OpenAPI spec at `GET /openapi.json`. Treat the spec as authoritative and read fields defensively. ## The auditable chain Provenance is not a single label. It is a chain of four linked facts, each answering a different audit question. Who published this? Identifies the official issuer, for example a central bank or a national statistics office. Where can a human verify it? Points at the originating release or dataset so a reviewer can cross-check by hand. Exactly which upstream response produced this value? A reference to the captured payload, proving the value was not hand-edited, without re-serving the upstream body. When and by which run did Financial Data API record it? Ties the value to a specific, timestamped ingestion, which connects provenance to the [time model](/concepts/time-model). Pair provenance with the [time model](/concepts/time-model). The ingestion run timestamp is what `as_of` approximates today, so the provenance chain and a point-in-time query describe the same moment from two angles: one tells you *where* a value came from, the other *when* it became known. ## A typical audit flow Query any observation route and read the inline `provider`, `sourceUrl`, and `rawAvailable`. For many audits this is already enough. Call `GET /provenance/observations/{observationId}` to retrieve the named source, source URL, raw payload reference metadata, and ingestion run together. Open the `sourceUrl` and confirm the published figure matches. The raw payload reference and ingestion run document the path in between. Every value Financial Data API returns is traceable to an official release. There are no orphan numbers. ## Related How Financial Data API flags stale and silently-frozen feeds. # Rate limits Source: https://docs.financialdatapi.com/concepts/rate-limits Per-client, per-scope, fixed-window limits, the x-ratelimit-* headers, the 429 body, defaults, and retry guidance. Financial Data API enforces rate limits per client in a fixed time window, against a ceiling set by your plan or, for enterprise and internal keys, by the scope a route requires. Every API response tells you where you stand through four response headers, and exceeding a limit returns a `429 rate_limited` error with the relevant details. This page covers the model, which ceiling applies to your key, monthly caps, the headers, the 429 body, and how to back off and retry. ## The model Limits are counted along three dimensions at once: Your API key. Each key has its own counter. The scope the route requires (`data:read`, `ops:read`, or `admin`). Each scope has its own limit, so heavy product traffic on `data:read` does not consume your `ops:read` budget. A fixed time window. The current window length is 60 seconds. Your counter resets at the start of each window. In other words: each key gets a separate quota for each scope, refreshed every window. ## Rate limit headers Every API response (success or error) carries four headers describing your current budget. Read them on every response and let them drive your pacing. A description of the policy applied to this request (the limit and window in effect for the matched scope). The maximum number of requests allowed in the current window for this client and scope. The number of requests you have left in the current window. When this reaches 0, further requests return `429` until the window resets. The timestamp when the current window resets and `remaining` refills. Use this to schedule retries. ```http Example response headers theme={"theme":"css-variables"} x-ratelimit-policy: 1000 per 60s (scope data:read) x-ratelimit-limit: 1000 x-ratelimit-remaining: 987 x-ratelimit-reset: 2026-06-24T18:42:00Z ``` ## The 429 response When you exceed your limit, the request fails with HTTP `429` and the `rate_limited` code. The `details` object tells you which scope was limited, the ceiling, and the window length. ```json 429 rate_limited theme={"theme":"css-variables"} { "error": { "code": "rate_limited", "message": "The Financial Data API rate limit has been exceeded.", "request_id": "8f1c2e90-7a4b-4c3d-9e21-2b6f0a1c4d55", "requestId": "8f1c2e90-7a4b-4c3d-9e21-2b6f0a1c4d55", "details": { "required_scope": "data:read", "limit": 1000, "window_seconds": 60 } }, "requestId": "8f1c2e90-7a4b-4c3d-9e21-2b6f0a1c4d55" } ``` The scope whose limit you exceeded. The request ceiling for that scope in one window. The window length in seconds. ## Which limit applies to your key There are two ceilings, and which one governs depends on the kind of key you hold. This is the most common source of confusion, so it is worth being explicit. **Self-serve plan keys** (Free, Advance, Scale) are limited by plan. This is what applies if you signed up at app.financialdatapi.com: | Plan | Per-minute limit | Monthly call cap | | ------- | ---------------- | ---------------- | | Free | 60 requests | 2,500 | | Advance | 600 requests | 2,000,000 | | Scale | 2,400 requests | 10,000,000 | **Enterprise, internal and system keys** have no self-serve plan attached, so they fall back to the per-scope baseline instead: | Scope | Per-minute limit | Applies to | | ----------- | ---------------- | ---------------------------------------------------------------------- | | `data:read` | 1,000 requests | Product and data routes, most of the API. | | `ops:read` | 500 requests | Operational routes: liveness, source health, manifest. | | `admin` | 250 requests | Sensitive admin routes. The `admin` scope also satisfies lower scopes. | Enterprise keys have no monthly cap. Both tables are correct; they describe different kinds of key. If you are on a Free, Advance or Scale plan, read the first and ignore the second. Whichever applies, the live `x-ratelimit-*` headers and the `details` block in a `429` are authoritative, so trust those over any number hard-coded in a client. ### The /v1/ask endpoint has its own budget `/v1/ask` runs a language model on every call, which costs far more than a data read, so it is metered separately and does not consume your data-read allowance: | Plan | `/v1/ask` per-minute limit | | ------- | -------------------------- | | Free | 5 requests | | Advance | 60 requests | | Scale | 240 requests | ### Monthly caps Monthly caps reset at the start of each calendar month, UTC. Exceeding one also returns `429`, but with a distinct message, `Monthly request cap for your plan has been reached.`, and a `details` block carrying your `plan` and `monthly_cap`. That lets you tell a monthly exhaustion apart from a per-minute burst without guessing. ## Backoff and retry Retry on `429` and on `5xx` (`internal_error`). Do not retry on `4xx` other than `429`: a `bad_request`, `unauthorized`, `forbidden`, or `not_found` will fail identically on retry, so fix the request instead. For a `429`, the cleanest strategy is to wait until the window resets: The response is `429`, or `x-ratelimit-remaining` has hit 0. Take `x-ratelimit-reset` from the response headers (or compute from `details.window_seconds`). Sleep until that timestamp before retrying. This avoids hammering a closed window. For `5xx`, use exponential backoff with jitter. Cap the number of attempts so a persistent failure surfaces instead of looping forever. ```python Python (requests) theme={"theme":"css-variables"} import os import time from datetime import datetime, timezone import requests URL = "https://api.financialdatapi.com/observations" HEADERS = {"x-api-key": os.environ["FINANCIALDATA_API_KEY"]} PARAMS = {"country": "USA", "indicator": "cpi_inflation_yoy"} def get_with_retry(max_attempts: int = 5): backoff = 1.0 for attempt in range(max_attempts): resp = requests.get(URL, headers=HEADERS, params=PARAMS) if resp.status_code == 429: reset = resp.headers.get("x-ratelimit-reset") if reset: reset_at = datetime.fromisoformat(reset.replace("Z", "+00:00")) wait = max(0.0, (reset_at - datetime.now(timezone.utc)).total_seconds()) else: wait = resp.json()["error"]["details"].get("window_seconds", 60) time.sleep(wait) continue if resp.status_code >= 500: time.sleep(backoff) backoff *= 2 # exponential backoff for 5xx continue resp.raise_for_status() return resp.json() raise RuntimeError("exhausted retries") ``` ```typescript TypeScript (fetch) theme={"theme":"css-variables"} const URL = "https://api.financialdatapi.com/observations?country=USA&indicator=cpi_inflation_yoy"; const headers = { "x-api-key": process.env.FINANCIALDATA_API_KEY! }; async function getWithRetry(maxAttempts = 5) { let backoff = 1000; for (let attempt = 0; attempt < maxAttempts; attempt++) { const res = await fetch(URL, { headers }); if (res.status === 429) { const reset = res.headers.get("x-ratelimit-reset"); const waitMs = reset ? Math.max(0, new Date(reset).getTime() - Date.now()) : 60_000; await new Promise((r) => setTimeout(r, waitMs)); continue; } if (res.status >= 500) { await new Promise((r) => setTimeout(r, backoff)); backoff *= 2; // exponential backoff for 5xx continue; } if (!res.ok) throw new Error(`request failed: ${res.status}`); return res.json(); } throw new Error("exhausted retries"); } ``` Stay ahead of the limit instead of reacting to it. Watch `x-ratelimit-remaining` and slow down before it hits 0. A short delay that keeps you under the ceiling beats a stall waiting out a `429`. The full error envelope and code table. The shared shape of every response. # Response envelope Source: https://docs.financialdatapi.com/concepts/response-envelope Every Financial Data API response shares one predictable JSON shape: data plus meta. Every response from the Financial Data API shares one shape. There is exactly one envelope. Whether you request a list or a single item, you read the payload from `data` and the bookkeeping from `meta`. You never have to special-case the parsing logic per endpoint. This page describes the envelope, every `meta` field, and how the request identifier flows through both successful and error responses for tracing. ## The two payload shapes `data` is the only field whose type varies, and it varies in exactly one way: * **List responses** put an array in `data`. List responses are the ones that paginate, so their `meta` carries a `pagination` block. * **Item responses** put a single object in `data`. Item responses describe one resource (for example one country, one entity, or one provenance chain) and do not paginate. Everything else (the `meta` block, the top-level `requestId`) is identical across both. ```json List response theme={"theme":"css-variables"} { "data": [ { "indicator": "cpi_inflation_yoy", "country": "USA", "value": 3.2, "period": "2026-05", "freshness": "fresh" } ], "meta": { "request_id": "8f1c2e90-7a4b-4c3d-9e21-2b6f0a1c4d55", "requestId": "8f1c2e90-7a4b-4c3d-9e21-2b6f0a1c4d55", "api_version": "v1", "pagination": { "limit": 100, "cursor": null, "next_cursor": null, "has_more": false } }, "requestId": "8f1c2e90-7a4b-4c3d-9e21-2b6f0a1c4d55" } ``` ```json Item response theme={"theme":"css-variables"} { "data": { "indicator": "cpi_inflation_yoy", "country": "USA", "value": 3.2, "period": "2026-05", "freshness": "fresh" }, "meta": { "request_id": "8f1c2e90-7a4b-4c3d-9e21-2b6f0a1c4d55", "requestId": "8f1c2e90-7a4b-4c3d-9e21-2b6f0a1c4d55", "api_version": "v1" }, "requestId": "8f1c2e90-7a4b-4c3d-9e21-2b6f0a1c4d55" } ``` Only list responses include `meta.pagination`. Item responses omit it because there is nothing to page through. ## Top-level fields The response payload. An array for list endpoints, a single object for item endpoints. This is the only field whose type changes between response kinds. Response metadata: the request identifier, the API version, and (on list responses) the pagination block. See below. The request identifier, repeated at the top level for convenience. Identical to `meta.request_id` and `meta.requestId`. Quote this value when you contact support. ## The `meta` block A UUID that uniquely identifies this request on the server. Logged server-side, so it lets support trace exactly what your call did. The same UUID as `meta.request_id`, provided in camelCase as well so clients in either naming convention can read it without transformation. The API version that served the response. Always `"v1"` for the current surface. Paths are versionless; this field reports the underlying API version. Present on list responses only. Carries the cursor state for paging through results. See the [Pagination](/concepts/pagination) page for the full loop. The page size that was applied to this request (1 to 500, default 100). The opaque cursor you supplied for this page, or `null` on the first page. The cursor to pass on your next request to fetch the following page. `null` when there are no more pages. `true` if more pages exist. Keep requesting with `next_cursor` while this is `true`. ## The request identifier Both successful and error responses carry the same identifier in three places: `meta.request_id`, `meta.requestId`, and the top-level `requestId`. They always hold the same value within one response. The redundancy exists so you can read the identifier whether your code expects snake\_case or camelCase, and whether it inspects the envelope root or the `meta` block. Capture it on every response, including errors. It is the fastest way for support to find your request in the logs. ```ts Capturing the request id (TypeScript) theme={"theme":"css-variables"} const res = await fetch( "https://api.financialdatapi.com/observations?country=USA&indicator=cpi_inflation_yoy", { headers: { "x-api-key": process.env.FINANCIALDATA_API_KEY! } }, ); const body = await res.json(); console.log("request id:", body.requestId); ``` ## Error responses Errors use a sibling envelope: `error` replaces `data`, and the request identifier is preserved so failures stay traceable. See the [Errors](/concepts/errors) page for the full shape and the code table. ```json Error envelope theme={"theme":"css-variables"} { "error": { "code": "bad_request", "message": "Unknown query parameter: 'contry'", "request_id": "8f1c2e90-7a4b-4c3d-9e21-2b6f0a1c4d55", "requestId": "8f1c2e90-7a4b-4c3d-9e21-2b6f0a1c4d55", "details": {} }, "requestId": "8f1c2e90-7a4b-4c3d-9e21-2b6f0a1c4d55" } ``` Follow `next_cursor` while `has_more` is true. The error envelope and the full code table. # Rights and exposure Source: https://docs.financialdatapi.com/concepts/rights-and-exposure Every source carries an exposure class. The public surface returns only redistribution-safe official and public-domain data, so your usage stays clean of licensing risk. Data is only useful if you can use it without legal exposure. Financial Data API attaches a **rights model** to every source so you always know what you are allowed to do with a value. The public API surface is deliberately scoped to data that is safe to redistribute. Licensed vendor and market price data exists inside Financial Data API for derived analytics, but it never crosses onto a public route, and raw provider payloads are never handed back at all. The result is simple: if a value reached you through `/v1/public/*`, you can build on it without inheriting someone else's licensing terms. ## Exposure classes Every source is tagged with one of four exposure classes. The class governs which routes can surface that source's observations. Redistribution-safe official or public-domain data. This is the only class that appears on `/v1/public/*`. Safe to surface, cache, and build products on. Licensed vendor or market price data used inside Financial Data API for derived analytics. Never returned on `/v1/public/*`. Data available only to specific authorized consumers under explicit terms. Not part of the public surface. Sources that must not be served by the product API at all. Every observation response carries rights metadata alongside its source attribution and freshness. You never have to guess the class of a value: it travels with the data. ## The public surface is the safe surface The `/v1/public/*` routes return **only** sources classed `public`. These are official releases and public-domain datasets: central-bank rates, national statistics offices, the economic calendar, SEC fundamentals, and Financial Data API's own derived signals over those inputs. ```bash theme={"theme":"css-variables"} # Public, redistribution-safe latest readings curl -G "https://api.financialdatapi.com/v1/public/observations/latest" \ -H "x-api-key: $FINANCIALDATA_API_KEY" \ --data-urlencode "country=USA" \ --data-urlencode "indicator=cpi_inflation_yoy" ``` Key public routes, all restricted to redistribution-safe data: | Route | Returns | | ------------------------------------ | --------------------------------------------------------------------- | | `GET /v1/public/observations` | Normalized observations by canonical indicator ID | | `GET /v1/public/observations/latest` | Latest public macro reading per canonical indicator | | `GET /v1/public/screener` | Screens countries and entities by latest public indicator values | | `GET /v1/public/coverage` | Breadth summary: catalog totals, public categories, covered countries | | `GET /v1/public/companies` | Scored fundamentals universe with sector and industry inline | Want to see exactly what the public surface covers without hard-coding totals? Call `GET /v1/public/coverage`. It returns the current catalog breadth so your integration stays correct as coverage grows. ## Licensed and price data stays internal Some inputs Financial Data API relies on are licensed: vendor feeds and market price data carry redistribution terms that forbid passing them through to your application. Financial Data API classes these `internal_only`. They can power **derived** analytics, where the output is Financial Data API's own computed signal rather than the licensed input itself, but the licensed values are never exposed on `/v1/public`. Do not expect raw market prices or licensed vendor series on any public route. If a value would carry redistribution risk, it is not on the public surface by design. This is the boundary that keeps your usage clean. ## Raw payload bodies are never exposed Financial Data API ingests raw provider payloads to build the auditable provenance chain, but the product API never returns those payload bodies. What you get instead is a **raw payload reference**: an identifier that lets you confirm a value was derived from a specific captured upstream response, without the API redistributing that upstream body. This keeps two things true at once: every observation is auditable back to its source, and no upstream provider's raw content is re-served through Financial Data API. See [Provenance](/concepts/provenance) for how the raw payload reference fits into the full chain from official release to API response. ## Usage clean of licensing risk Put together, the rights model gives you a clear contract: Everything on `/v1/public/*` is redistribution-safe official or public-domain data. Cache it, chart it, ship it. Rights and exposure travel with every observation. You can enforce your own policies programmatically off the response. Use the raw payload reference and the provenance endpoint to prove origin, without Financial Data API redistributing any upstream body. If a value came to you through a `/v1/public/*` route, it is redistribution-safe by construction. That is the entire point of the public surface. ## Related The auditable chain from official release to API response. Bi-temporal observations and point-in-time queries. # The time model Source: https://docs.financialdatapi.com/concepts/time-model Financial Data API is bi-temporal. Every value carries both the period it describes and the moment it became known, so you can reconstruct what was knowable at any point in time. Financial Data API is a point-in-time data API. The core differentiator is that every observation is **bi-temporal**: it records both *what period a value describes* and *when that value became known*. Keeping those two axes separate is what lets you answer questions like "what was the latest US CPI reading that I could have seen on 2026-03-15?" without contaminating the answer with data that was published later. This page explains the three time axes, how to filter on each, and the honest limits of the current `as_of` implementation. ## Three axes, never conflated `period`, `period_start`, `period_end`. The slice of real-world time the value is *about*: May 2026 CPI, Q1 2026 GDP, the trading day for a daily series. `start_date`, `end_date`. Bounds on `observed_at`: *when* the value became known to Financial Data API. This is the axis that prevents lookahead. `as_of`. Returns the latest vintage known on or before a timestamp. Revisions are retained, never overwritten, so you can replay history. The mistake most data APIs make is collapsing these into one timestamp. A figure released in June that describes May, then revised in July, has at least three distinct timestamps attached to it. Financial Data API keeps them apart so each query means exactly one thing. ### 1. The described period The period is the real-world interval a value measures. It does not move when the value is revised. * `period` is a convenience filter and accepts `YYYY`, `YYYY-MM`, or `YYYY-Qn`. * `period_start` and `period_end` are the explicit bounds on the response object. ```bash theme={"theme":"css-variables"} # All 2026 readings for US headline inflation, by described period curl -G "https://api.financialdatapi.com/observations" \ -H "x-api-key: $FINANCIALDATA_API_KEY" \ --data-urlencode "country=USA" \ --data-urlencode "indicator=cpi_inflation_yoy" \ --data-urlencode "period=2026" ``` `period=2026-Q1` selects observations whose described period falls in the first quarter. Use it for quarterly series such as GDP; use `period=2026-05` for monthly series such as CPI. ### 2. Knowledge time (the no-lookahead axis) `observed_at` is the moment a value became known to Financial Data API. You bound it with `start_date` and `end_date`. This is the axis you filter on when you care about *what was knowable*, not *what period it covers*. ```bash theme={"theme":"css-variables"} # Everything that became known in March 2026, regardless of which period it describes curl -G "https://api.financialdatapi.com/observations" \ -H "x-api-key: $FINANCIALDATA_API_KEY" \ --data-urlencode "country=USA" \ --data-urlencode "indicator=cpi_inflation_yoy" \ --data-urlencode "start_date=2026-03-01T00:00:00Z" \ --data-urlencode "end_date=2026-03-31T23:59:59Z" ``` A May CPI release that lands on 2026-06-11 has `period = 2026-05` but `observed_at` in June. Filtering on `period` and filtering on knowledge time answer different questions. Pick the one that matches your intent. ### 3. Vintage cutoff with `as_of` `as_of` asks: "give me the data as it stood at this moment." It returns, for each matching series, the latest vintage known on or before the supplied timestamp. Because Financial Data API retains revisions instead of overwriting them, two `as_of` queries with different cutoffs can return different values for the same period. ```bash cURL theme={"theme":"css-variables"} curl -G "https://api.financialdatapi.com/observations/latest" \ -H "x-api-key: $FINANCIALDATA_API_KEY" \ --data-urlencode "country=USA" \ --data-urlencode "indicator=cpi_inflation_yoy" \ --data-urlencode "as_of=2026-03-15T00:00:00Z" ``` ```python Python theme={"theme":"css-variables"} import os, requests resp = requests.get( "https://api.financialdatapi.com/observations/latest", headers={"x-api-key": os.environ["FINANCIALDATA_API_KEY"]}, params={ "country": "USA", "indicator": "cpi_inflation_yoy", "as_of": "2026-03-15T00:00:00Z", }, ) resp.raise_for_status() print(resp.json()["data"]) ``` ```typescript TypeScript theme={"theme":"css-variables"} import { FinancialDataApiClient } from "@financialdatapi/client"; const client = new FinancialDataApiClient({ apiKey: process.env.FINANCIALDATA_API_KEY }); const { data } = await client.getLatestObservations({ country: "USA", indicator: "cpi_inflation_yoy", as_of: "2026-03-15T00:00:00Z", }); console.log(data); ``` The same query with `as_of=2026-07-01T00:00:00Z` may return a different number for the same described period, because a revision became known in between. Both answers are correct, each for its own cutoff. **Honest caveat about `as_of`.** Today, `as_of` approximates the **ingestion timestamp**: the moment Financial Data API recorded a value. It is not yet a full provider-vintage reconstruction. If a provider published a figure before Financial Data API ingested it, the `as_of` cutoff reflects when Financial Data API knew, not the instant the provider released it. Full provider-vintage reconstruction is planned future work. For most backtests this distinction is small, but if your strategy is sensitive to intraday release timing, account for it. ## Why this matters for backtests Lookahead bias is the silent killer of historical research. If your backtest on 2026-03-15 quietly uses a CPI value that was only revised into existence in July, your results are fiction. Financial Data API removes that risk in two ways: Run each historical query with `as_of` set to the simulated decision time. You receive only the vintage that was known on or before that moment. Alternatively, constrain `end_date` to the decision time. Anything that became known later is excluded by construction. ```python theme={"theme":"css-variables"} import os, requests API = "https://api.financialdatapi.com" HEADERS = {"x-api-key": os.environ["FINANCIALDATA_API_KEY"]} def latest_known_at(decision_time: str): """The CPI vintage that was knowable at decision_time. No lookahead.""" resp = requests.get( f"{API}/observations/latest", headers=HEADERS, params={ "country": "USA", "indicator": "cpi_inflation_yoy", "as_of": decision_time, }, ) resp.raise_for_status() return resp.json()["data"] # Walk the decision dates of your backtest; each call is point-in-time clean. for t in ["2026-01-15T00:00:00Z", "2026-02-15T00:00:00Z", "2026-03-15T00:00:00Z"]: print(t, latest_known_at(t)) ``` Treat `period` as the x-axis of your chart and `as_of` (or `end_date`) as the lens you view it through. The period tells you *which* point you are plotting; the cutoff tells you *which vintage* of that point you are allowed to see. ## Quick reference | Axis | Parameters | Answers | Use when | | ---------------- | -------------------------------------- | ------------------------------------------------- | -------------------------------------------------------------- | | Described period | `period`, `period_start`, `period_end` | Which real-world interval the value is about | You want a specific month, quarter, or year | | Knowledge time | `start_date`, `end_date` | When the value became known | You need a clean as-of-then view or a release window | | Vintage cutoff | `as_of` | The latest vintage known on or before a timestamp | You are reconstructing a point-in-time snapshot for a backtest | All three axes compose. You can request a specific `period` while pinning `as_of` to see how that exact reading looked at an earlier moment. Unknown query parameters fail closed with `bad_request`, so a typo in a time parameter is rejected rather than silently ignored. ## Related Trace any observation back to its named source and ingestion run. Understand the freshness label and how silently-frozen feeds are detected. # Macro screener Source: https://docs.financialdatapi.com/guides/screener Screen countries by the latest values of canonical macro indicators with a compact filter DSL: field, operator, value, all AND-ed. The screener is the cross-country analogue of an equity stock screener. Instead of filtering tickers by fundamentals, you filter countries by the latest values of canonical macro indicators: "show me countries with CPI inflation above 3% and unemployment below 5%." Financial Data API evaluates the latest public reading of each indicator per country and returns the countries that satisfy every clause. The screener screens **public indicator values only**. It reads the latest public observation per canonical indicator and applies your filters to those numbers. It never exposes any internal scoring, and it never touches licensed or `internal_only` data. ## How it works The HTTP API is read-only and GET-only, so filters arrive as a single compact query parameter, the `filter` DSL. Each clause is `field:operator:value`, clauses are comma-separated, and they are AND-ed together. A country qualifies only when every clause matches one of its indicators and that indicator's latest value satisfies the operator. ```text theme={"theme":"css-variables"} filter=cpi_inflation_yoy:gt:3,unemployment_rate:lt:5 ``` This reads as: CPI inflation greater than 3 **and** unemployment rate less than 5. ## The filter DSL ### Anatomy of a clause A clause has three colon-separated parts: | Part | Example | Notes | | ---------- | ------------------- | -------------------------------------------------------------------------- | | `field` | `cpi_inflation_yoy` | A canonical indicator slug. Discover the full list at `/screener/filters`. | | `operator` | `gt` | One of the operators below. | | `value` | `3` | A number. The `in` operator takes pipe-separated numbers. | ### Operators | Operator | Meaning | Example | | | | -------- | -------------------------------- | ------------------------ | ---- | ----- | | `gt` | Greater than | `cpi_inflation_yoy:gt:3` | | | | `lt` | Less than | `unemployment_rate:lt:5` | | | | `gte` | Greater than or equal | `policy_rate:gte:4` | | | | `lte` | Less than or equal | `gdp_growth_yoy:lte:1` | | | | `eq` | Equal | `policy_rate:eq:0` | | | | `in` | Value is in a pipe-separated set | \`policy\_rate:in:0 | 0.25 | 0.5\` | The `in` operator is the only one that takes more than one value. Separate its values with the pipe character `|`: ```text theme={"theme":"css-variables"} filter=policy_rate:in:0|0.25|0.5 ``` ### AND semantics Clauses are joined with commas and every clause must hold. There is no `OR`; build the union you want client-side by issuing separate requests. A country with no reading for a clause's field, or a `null` latest value, does not satisfy that clause and is dropped. ```text theme={"theme":"css-variables"} # Inflation above 3 AND unemployment below 5 AND policy rate at or above 4 filter=cpi_inflation_yoy:gt:3,unemployment_rate:lt:5,policy_rate:gte:4 ``` ## Discovering fields Field names are canonical indicator slugs. The authoritative list, with the operators, the syntax reminder, and an example, lives at `GET /screener/filters`. ```bash cURL theme={"theme":"css-variables"} curl -s "https://api.financialdatapi.com/screener/filters" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` ```python Python (requests) theme={"theme":"css-variables"} import os, requests resp = requests.get( "https://api.financialdatapi.com/screener/filters", headers={"x-api-key": os.environ["FINANCIALDATA_API_KEY"]}, ) resp.raise_for_status() data = resp.json()["data"] print(data["operators"]) for f in data["fields"]: print(f["field"], "-", f["name"]) ``` ```typescript TypeScript (@financialdatapi/client) theme={"theme":"css-variables"} import { FinancialDataApiClient } from "@financialdatapi/client"; const client = new FinancialDataApiClient({ apiKey: process.env.FINANCIALDATA_API_KEY }); const { data } = await client.screenerFields(); console.log(data.fields); ``` The response: ```json theme={"theme":"css-variables"} { "data": { "operators": ["gt", "lt", "gte", "lte", "eq", "in"], "syntax": "filter=field:operator:value,field:operator:value (clauses are AND-ed; the 'in' operator takes pipe-separated values)", "example": "filter=cpi_inflation_yoy:gt:3,unemployment_rate:lt:5", "fields": [ { "field": "cpi_inflation_yoy", "indicatorId": "indicator_cpi_inflation_yoy", "name": "CPI inflation, year over year", "category": "inflation", "unit": "percent" } ] } } ``` Field matching is forgiving: it accepts the canonical slug, the `indicator_`-prefixed id, and registered aliases for the same indicator. When in doubt, use the `field` value exactly as returned by `/screener/filters`. ## Running a screen Send your clauses as the `filter` parameter to `GET /screener`. The `filter` parameter is required. ```bash cURL theme={"theme":"css-variables"} curl -s "https://api.financialdatapi.com/screener?filter=cpi_inflation_yoy:gt:3,unemployment_rate:lt:5" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` ```python Python (requests) theme={"theme":"css-variables"} import os, requests resp = requests.get( "https://api.financialdatapi.com/screener", headers={"x-api-key": os.environ["FINANCIALDATA_API_KEY"]}, params={"filter": "cpi_inflation_yoy:gt:3,unemployment_rate:lt:5"}, ) resp.raise_for_status() for hit in resp.json()["data"]: print(hit["country"], hit["name"]) ``` ```typescript TypeScript (@financialdatapi/client) theme={"theme":"css-variables"} import { FinancialDataApiClient, buildScreenerFilter } from "@financialdatapi/client"; const client = new FinancialDataApiClient({ apiKey: process.env.FINANCIALDATA_API_KEY }); // Pass structured filters; the SDK serializes them into the DSL for you. const { data } = await client.screen([ { field: "cpi_inflation_yoy", operator: "gt", value: 3 }, { field: "unemployment_rate", operator: "lt", value: 5 }, ]); console.log(data); // Equivalent with a raw DSL string: await client.screen("cpi_inflation_yoy:gt:3,unemployment_rate:lt:5"); // buildScreenerFilter() is exported if you want the string without calling screen(): const filter = buildScreenerFilter([ { field: "policy_rate", operator: "in", value: [0, 0.25, 0.5] }, ]); // filter === "policy_rate:in:0|0.25|0.5" ``` ### The response Each result is a country that satisfied every clause, with the matched indicator values inlined so you can see what it scored on without a second call. ```json theme={"theme":"css-variables"} { "data": [ { "entity": "USA", "country": "USA", "name": "United States", "values": [ { "field": "cpi_inflation_yoy", "indicatorId": "cpi_inflation_yoy", "indicatorName": "CPI inflation, year over year", "value": 3.1, "unit": "percent", "periodEnd": "2026-05-31", "observedAt": "2026-05-31" }, { "field": "unemployment_rate", "indicatorId": "unemployment_rate", "indicatorName": "Unemployment rate", "value": 4.2, "unit": "percent", "periodEnd": "2026-05-31", "observedAt": "2026-05-31" } ] } ], "meta": { "api_version": "v1" }, "requestId": "0c4f..." } ``` The matched entity key (the country ISO code). ISO alpha-3 country code. Country display name. One entry per clause, showing the indicator value that satisfied it. ## Optional parameters Besides the required `filter`, the screener accepts three optional parameters. | Param | Values | Description | | ----------- | --------------------- | ---------------------------------------------------------------------------------------------- | | `country` | ISO code | Restrict the screen to a single country (useful as a yes/no test). | | `freshness` | `fresh` | Only consider readings that pass the freshness gate, so stale prints cannot qualify a country. | | `limit` | 1 to 500, default 100 | Cap the number of returned countries. | ```bash theme={"theme":"css-variables"} # Same screen, but only over fresh readings, limited to 20 countries curl -s "https://api.financialdatapi.com/screener?filter=cpi_inflation_yoy:gt:3,unemployment_rate:lt:5&freshness=fresh&limit=20" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` `freshness=fresh` is recommended for live decision-making. Without it, a country can qualify on an old print that is past its publication cadence. With it, those stale readings are excluded before filtering. ## More examples ```bash Restrictive policy theme={"theme":"css-variables"} # Inflation above target and a tight policy stance curl -s "https://api.financialdatapi.com/screener?filter=cpi_inflation_yoy:gt:2,policy_rate:gte:4&freshness=fresh" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` ```bash Discrete policy rates theme={"theme":"css-variables"} # Countries at one of a set of policy rates curl -s "https://api.financialdatapi.com/screener?filter=policy_rate:in:0|0.25|0.5" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` ```bash Single-country test theme={"theme":"css-variables"} # Does the UK currently meet these conditions? curl -s "https://api.financialdatapi.com/screener?filter=cpi_inflation_yoy:gt:3&country=GBR" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` ## Errors The screener fails closed and returns a stable error `code` on bad input. | Situation | Code | Status | | -------------------------------------------------- | ------------- | ------ | | `filter` is missing | `bad_request` | 400 | | A clause is malformed (not `field:operator:value`) | `bad_request` | 400 | | An unknown operator | `bad_request` | 400 | | A non-numeric value (or empty `in` set) | `bad_request` | 400 | | `limit` out of the 1 to 500 range | `bad_request` | 400 | | An unknown query parameter | `bad_request` | 400 | The error message names the offending clause so you can fix it quickly. The `@financialdatapi/client` SDK throws a `FinancialDataApiError` carrying the `code`, HTTP `status`, and `requestId`: ```typescript theme={"theme":"css-variables"} import { FinancialDataApiError } from "@financialdatapi/client"; try { await client.screen("cpi_inflation_yoy:gt:notanumber"); } catch (error) { if (error instanceof FinancialDataApiError) { console.error(error.code, error.status, error.message); } } ``` ## Next steps The catalog guide covers the full indicator list the screener fields come from. Once a screen narrows your set, fetch the full point-in-time series with the observations API. # Sync & changes Source: https://docs.financialdatapi.com/guides/sync-and-changes Keep a downstream copy of Financial Data API fresh: check the manifest, pull a snapshot, monitor source health, and sync incrementally with the changes feed. If you maintain a local copy of Financial Data API data, you do not need to refetch everything. Four endpoints let you detect change cheaply and pull only what moved: `GET /manifest` is a cheap state fingerprint: a hash, the latest run, freshness markers, and source health. `GET /observations/changes` returns only observations that became known since a knowledge-time bound. `GET /snapshot` returns the current public observation set plus the matching manifest hash. `GET /source-health` reports per-connector freshness so you can detect silently-frozen feeds. ## The sync loop Pull `GET /snapshot` to load the current public observation set, and store the `manifestHash` and `asOf` it returns. On a schedule, call `GET /manifest`. If `manifestHash` is unchanged from your stored value, nothing moved and you can stop early. When the hash changes, call `GET /observations/changes?start_date=` to fetch only observations that became known on or after that date. Page through with the cursor. Periodically read `GET /source-health` to catch stale or failing connectors before they show up as silently missing data. ## 1. Check the manifest The manifest is the cheapest way to ask "did anything change?". Compare the returned `manifestHash` to the one you stored last; if it matches, you are up to date. Scope health and freshness to one source. Scope health and freshness to one provider. ```bash cURL theme={"theme":"css-variables"} curl "https://api.financialdatapi.com/manifest" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` ```python Python theme={"theme":"css-variables"} import requests BASE = "https://api.financialdatapi.com" headers = {"x-api-key": "your_key_here"} res = requests.get(f"{BASE}/manifest", headers=headers) res.raise_for_status() manifest = res.json()["data"] print(manifest["manifestHash"], manifest["latestObservationAt"]) ``` ```typescript TypeScript theme={"theme":"css-variables"} import { FinancialDataApiClient } from "@financialdatapi/client"; const client = new FinancialDataApiClient({ apiKey: process.env.FINANCIALDATA_API_KEY! }); const { data: manifest } = await client.request("/manifest"); console.log(manifest.manifestHash, manifest.latestObservationAt); ``` ```json Response theme={"theme":"css-variables"} { "data": { "manifestHash": "9f1c...e7", "asOf": "2026-06-24T08:00:00Z", "latestRunId": "run_...", "observationCount": 4800000, "latestObservationAt": "2026-06-24T07:55:00Z", "latestIngestedAt": "2026-06-24T07:56:12Z", "sourceHealth": [ { "connectorId": "bls-cpi", "sourceId": "bls", "providerId": "bls", "status": "healthy", "freshnessStatus": "fresh", "lastCompletedAt": "2026-06-24T07:50:00Z" } ] }, "meta": { "api_version": "v1" }, "requestId": "..." } ``` Fingerprint of current state. Store it; an unchanged hash means nothing moved. Timestamp the manifest was generated (ISO). Record it so you know the date to pass as `start_date` on your next incremental pull. Id of the most recent ingestion run. May be null. Total observations in scope. Most recent `observedAt` (when a value became known) across the set. Most recent ingestion timestamp across the set. Per-connector health summaries (same shape as `/source-health`). The manifest hash changes whenever the latest run, the latest observation/ingestion times, or source health change. Use it as a coarse change gate, then use the changes feed for the actual diff. ## Full snapshot `GET /snapshot` returns the current public observation set together with the manifest hash that describes it. Use it to seed a fresh downstream copy, or to reconcile if you suspect drift. ```bash cURL theme={"theme":"css-variables"} curl "https://api.financialdatapi.com/snapshot?country=USA" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` ```python Python theme={"theme":"css-variables"} res = requests.get( f"{BASE}/snapshot", params={"country": "USA"}, headers=headers, ) res.raise_for_status() snapshot = res.json()["data"] print(snapshot["manifestHash"], len(snapshot["observations"])) ``` ```typescript TypeScript theme={"theme":"css-variables"} const { data: snapshot } = await client.request("/snapshot", { country: "USA" }); console.log(snapshot.manifestHash, snapshot.observations.length); ``` ```json Response theme={"theme":"css-variables"} { "data": { "runId": null, "asOf": "2026-06-24T08:00:00Z", "manifestHash": "9f1c...e7", "observations": [ { "observationId": "obs_us_cpi_2026_05", "indicatorId": "cpi_inflation_yoy", "country": "USA", "period": "2026-05", "actual": 3.1, "observedAt": "2026-06-11T12:30:00Z", "freshnessStatus": "fresh" } ], "releases": [], "sourceHealth": [ { "connectorId": "bls-cpi", "status": "healthy" } ] }, "meta": { "api_version": "v1" }, "requestId": "..." } ``` When the snapshot was generated (ISO). Hash describing exactly this snapshot. Store it as your sync baseline. The public observation set in scope. Each observation carries attribution, freshness, and rights metadata. Per-connector health summaries. The snapshot returns only redistribution-safe public observations. Licensed vendor data is never included. Filter the scope with the standard observation filters (for example `country`, `indicator_id`). ## 3. Sync incrementally `GET /observations/changes` returns only observations whose knowledge time falls on or after a `start_date` bound, newest first. Pass the date of your last successful sync to fetch just the delta. Knowledge-time lower bound (date, `YYYY-MM-DD`). Returns observations whose `observedAt` is on or after this date. `as_of` is also accepted to retrieve the latest vintage known on or before a timestamp. Scope to one country (ISO 3). Scope to one or more canonical indicators (comma-separated). Page size, 1 to 500. Opaque pagination cursor from `meta.pagination.next_cursor`. ```bash cURL theme={"theme":"css-variables"} curl "https://api.financialdatapi.com/observations/changes?start_date=2026-06-24&limit=200" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` ```python Python theme={"theme":"css-variables"} def sync_changes(start_date: str): cursor = None while True: params = {"start_date": start_date, "limit": 500} if cursor: params["cursor"] = cursor res = requests.get(f"{BASE}/observations/changes", params=params, headers=headers) res.raise_for_status() body = res.json() for obs in body["data"]: upsert(obs) # write into your store, keyed by observationId pagination = body["meta"]["pagination"] if not pagination["has_more"]: break cursor = pagination["next_cursor"] sync_changes("2026-06-24") ``` ```typescript TypeScript theme={"theme":"css-variables"} // The SDK auto-paginates over cursor pages. for await (const obs of client.paginate("/observations/changes", { start_date: "2026-06-24", })) { upsert(obs); // write into your store, keyed by observationId } ``` Revisions appear in the changes feed as observations becoming known, not as in-place edits. Upsert by `observationId` and keep prior vintages if you need point-in-time history; Financial Data API retains revisions and never overwrites them. Honest caveat on knowledge time: `as_of` currently approximates the ingestion timestamp rather than full provider-vintage reconstruction. The changes feed reflects when Financial Data API learned of a value, which is the right basis for incremental sync. ## Monitor source health `GET /source-health` reports per-connector status and freshness so you can detect a feed that has gone stale or started failing, before it shows up downstream as quietly missing data. Filter to one source. Filter to one provider. Page size, 1 to 500. ```bash cURL theme={"theme":"css-variables"} curl "https://api.financialdatapi.com/source-health" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` ```python Python theme={"theme":"css-variables"} res = requests.get(f"{BASE}/source-health", headers=headers) res.raise_for_status() for src in res.json()["data"]: if src["status"] != "healthy" or src["freshnessStatus"] == "stale": print(src["connectorId"], src["status"], src["freshnessStatus"], src["issueCodes"]) ``` ```typescript TypeScript theme={"theme":"css-variables"} for await (const src of client.paginate("/source-health")) { if (src.status !== "healthy" || src.freshnessStatus === "stale") { console.warn(src.connectorId, src.status, src.issueCodes); } } ``` ```json Response theme={"theme":"css-variables"} { "data": [ { "connectorId": "bls-cpi", "sourceId": "bls", "providerId": "bls", "status": "healthy", "lastRunId": "run_...", "lastSuccessfulRunId": "run_...", "lastCompletedAt": "2026-06-24T07:50:00Z", "lastSuccessAt": "2026-06-24T07:50:00Z", "issueCodes": [], "lastError": null, "latestObservedAt": "2026-06-11T12:30:00Z", "latestPeriodEnd": "2026-05-31", "freshnessStatus": "fresh", "recordsInserted": 12, "recordsUpdated": 0, "warningCount": 0, "errorCount": 0, "nextRunAt": "2026-06-24T08:50:00Z" } ], "meta": { "api_version": "v1", "pagination": { "limit": 100, "cursor": null, "next_cursor": null, "has_more": false } }, "requestId": "..." } ``` Connector identifier. Connector status, e.g. `healthy`, `degraded`, `stale`, `disabled`, `never_run`, `unknown`. Per-frequency freshness verdict for the feed: `fresh`, `stale`, or `unknown`. When the last run finished (ISO). May be null. When the connector last succeeded. Null if it has not succeeded recently. Machine-readable issue codes, e.g. `stale_source`, `connector_errors`, `connector_warnings`. Most recent error message, when present. Newest knowledge-time the connector has produced. Newest period the connector has covered. When the connector is next scheduled to run. May be null. For a per-series liveness verdict across every connector, also check `GET /ops/liveness`, which flags feeds that have silently stopped updating even when the connector itself reports healthy. It requires the `ops:read` scope. ## Putting it together Seed with one snapshot. Poll the manifest on your refresh interval. When the hash changes, pull `observations/changes?start_date=` and upsert by `observationId`. Read source health on a slower cadence (for example hourly) to catch stalled feeds. Always key your store by `observationId`. The changes feed can re-deliver an observation (for example after a revision), so upsert rather than insert, and never assume a value is final. Snapshot and changes return only redistribution-safe public observations. Licensed vendor data never appears, so a synced copy inherits the same redistribution-safe boundary. Every list response carries `meta.pagination`. Follow `next_cursor` while `has_more` is true. The TypeScript SDK does this for you via async iteration. ## Related Derived datasets sync alongside raw observations and carry their own provenance. Keep a downstream copy of company fundamentals fresh the same way. # Overview Source: https://docs.financialdatapi.com/index Point-in-time macroeconomic, rates, calendar, fundamentals, and derived-analytics data from official sources, served as predictable JSON for developers and AI agents. Financial Data API is a point-in-time data API for macroeconomics and global markets. Every value carries the period it describes, the moment it became known, a freshness label, and a full provenance chain back to its official source, so the same query returns the same answer today, next quarter, and inside a five-year backtest. It is built for two audiences: developers shipping research tools, dashboards, and trading systems that cannot tolerate silent data drift, and AI agents that need a self-describing, redistribution-safe surface they can discover and call without bespoke glue. ## Start here Make your first authenticated request and page through results in a few minutes. Send your API key, understand scopes, and read the rate-limit headers. Every endpoint, parameter, and response field, generated from the live OpenAPI spec. Sign up and make your first call in under two minutes. 2,500 free requests a month, no card required. ## What Financial Data API gives you Every observation records both the period it describes and the moment it became known, so backtests are free of lookahead by construction. Walk from any value to the named source, source URL, raw payload reference, and ingestion run that produced it. Every endpoint returns `data`, `meta`, and a stable `requestId`. Write your parsing once. ## Data surface Inflation, labor, growth, housing, external, income, and consumption series across 17 countries. Policy rates, money-market benchmarks, 10-year sovereign yields, and the 10Y-3M curve spread. Scheduled and released macro events with actual, forecast, consensus, previous, and revised values. Income, balance-sheet, and cash-flow statements for the S\&P 500 ∪ Nasdaq-100 universe. Surprise indices, COT positioning percentiles, valuation multiples, rates analytics, and a statistical macro forecast baseline. ## Built for agents A native Model Context Protocol server with read-only macro tools for Claude Code, Claude Desktop, and Cursor. Keyless, self-describing text indexes an agent can read to discover the API before it holds a key. Need help? Email [support@financialdatapi.com](mailto:support@financialdatapi.com) or see the [Support](/support) page. Keys are self-serve at [app.financialdatapi.com](https://app.financialdatapi.com). # Acceptable Use Policy Source: https://docs.financialdatapi.com/legal/acceptable-use-policy The rules for using the Financial Data API responsibly. # Financial Data API — Acceptable Use Policy *Last updated: 26 June 2026.* This Acceptable Use Policy ("AUP") applies to everyone who uses the Financial Data API and related tools (the "Service"), and is incorporated into the Terms of Service. Capitalized terms not defined here have the meaning given in the Terms. ## 1. Use your own key, within your limits * Keep your API keys confidential and do not share them across unrelated organizations. * Do not exceed, evade, or attempt to circumvent the rate limits or quotas that apply to your plan, and do not distribute requests across many keys or accounts to bypass them. * Do not probe, scan, or test the security of the Service, or attempt to gain unauthorized access to it, other accounts, or related systems, without our prior written permission. ## 2. Respect data rights * Honor the source attribution returned with each observation, and comply with any terms the underlying source imposes on its data. * Do not bulk-extract the datasets in order to recreate, resell, or redistribute a substantially similar data product that competes with or substitutes for the Service. * Do not present derived analytics as the output of a third-party source, and do not strip or falsify provenance or rights metadata. ## 3. Do not misuse the Service * Do not use the Service for anything unlawful, fraudulent, or harmful, or to infringe the rights of others. * Do not interfere with or disrupt the integrity or performance of the Service, for example through excessive automated load, denial-of-service techniques, or injecting malicious code. * Do not reverse engineer, decompile, or attempt to extract source code from the Service except to the extent that restriction is prohibited by law. * Do not misrepresent the Service, or use it in a way that could reasonably damage our reputation or that of the data sources. ## 4. No reliance for high-risk uses The Service is provided for informational purposes and may contain errors, delays, or revisions. Do not use it as the sole basis for automated decisions in safety-critical systems, and understand that nothing in the Service is investment advice. ## 5. Enforcement We may investigate suspected violations and may throttle, suspend, or terminate access, with or without notice depending on the severity and on legal or security risk. Where practical we will give notice and an opportunity to cure. Suspension for abuse or non-payment does not entitle you to a refund of prepaid fees for the suspended period. ## 6. Reporting Report abuse, suspected key compromise, or security issues to [support@financialdatapi.com](mailto:support@financialdatapi.com). # Privacy Policy Source: https://docs.financialdatapi.com/legal/privacy-policy How Financial Data API handles personal data. # Financial Data API — Privacy Policy *Last updated: 26 June 2026.* This Privacy Policy explains how Financial Data API ("we", "us") handles personal data in connection with the Financial Data API and related tools (the "Service"). It covers the people who request access to and use the Service ("you"). For data-protection purposes, we act as the controller of the personal data described here. ## 1. Data we collect * **Account and contact data.** When you request an API key or contact us, we collect the name, email address, and any organization details you provide. * **API key metadata.** We store a one-way hash of each API key (never the key itself in readable form), plus a short non-secret prefix and fingerprint used to identify the key, and its status and lifecycle timestamps. * **Usage data.** For each request we record operational metadata such as the timestamp, endpoint, HTTP method, response status, latency, the associated client identifier, and the request IP address. This supports security, rate limiting, billing, and debugging. * **Communications.** Records of your support and access correspondence with us. We do not intentionally collect special-category personal data, and the market and macro data served by the Service is not personal data about you. ## 2. How and why we use data We use personal data to: * provision and authenticate API access, and operate and secure the Service; * enforce rate limits and the Acceptable Use Policy, and detect and prevent abuse; * meter usage and administer billing; * provide support and respond to your requests; and * comply with legal obligations. Where the GDPR or similar laws apply, our legal bases are: performance of a contract (providing the Service you requested), our legitimate interests (securing, operating, and improving the Service, and preventing abuse), and compliance with legal obligations. ## 3. Sub-processors and hosting The Service runs on Amazon Web Services (AWS) in the EU (London, `eu-west-2` region), which processes hosting and storage data on our behalf. We may use additional processors for email delivery, payments, and error monitoring; a current list is available on request. We require processors to protect personal data under terms consistent with this policy. ## 4. International transfers Where personal data is transferred outside your jurisdiction, we rely on an appropriate transfer mechanism (such as standard contractual clauses) where required by law. ## 5. Retention We retain account and key metadata for as long as your account is active and as needed to provide the Service. We retain usage logs for 12 months for security, billing, and operational purposes, after which they are deleted or aggregated. We retain records longer only where required for legal or accounting reasons. ## 6. Security We hash API keys, restrict access to operational data, redact secret-like fields and raw provider payloads from operational event logs, and apply encryption and access controls on our infrastructure. No method of transmission or storage is completely secure, and we cannot guarantee absolute security. ## 7. Your rights Subject to applicable law, you may request access to, correction of, export of, or deletion of your personal data, and may object to or restrict certain processing. To exercise these rights, contact us at [support@financialdatapi.com](mailto:support@financialdatapi.com); we will respond within the timeframe required by law. You also have the right to lodge a complaint with your data protection authority. ## 8. Data breaches If a personal-data breach occurs that is likely to result in a risk to your rights, we will notify the relevant supervisory authority and affected users where and within the timeframes required by applicable law. ## 9. Children The Service is not directed to children and is intended for business and developer use. We do not knowingly collect personal data from children. ## 10. Changes and contact We may update this policy; material changes will be notified by a reasonable means and take effect on the stated date. Questions or requests: [support@financialdatapi.com](mailto:support@financialdatapi.com). # Terms of Service Source: https://docs.financialdatapi.com/legal/terms-of-service The terms governing access to and use of the Financial Data API. # Financial Data API — Terms of Service *Last updated: 26 June 2026.* These Terms of Service ("Terms") govern access to and use of the Financial Data API and related documentation, SDKs, and tools (together, the "Service"), operated by Financial Data API ("we", "us"). By requesting an API key, creating an account, or otherwise accessing the Service, you ("Customer", "you") agree to these Terms. If you are agreeing on behalf of an organization, you represent that you have authority to bind that organization. ## 1. The Service Financial Data API is a read-only HTTP API that delivers macroeconomic and global-markets data: official-source indicators, interest rates, FX reference data, an economic calendar, SEC fundamentals, and derived analytics, served as JSON with provenance and rights metadata. The Service is provided over `https://api.financialdatapi.com`. We may add, change, or remove endpoints, data, and features over time. We aim to keep the versioned `/v1` surface backward compatible and to give reasonable notice of breaking changes, but we do not guarantee that any specific dataset, endpoint, or field will remain available. ## 2. API keys and accounts We issue one or more API keys to you. You are responsible for keeping keys confidential, for all activity under your keys, and for the security of your systems. Do not embed keys in public client-side code or public repositories. Notify us promptly at [support@financialdatapi.com](mailto:support@financialdatapi.com) if you believe a key has been exposed; we will revoke and reissue it. We may rotate or revoke keys where reasonably necessary to protect the Service. ## 3. Acceptable use Your use of the Service is subject to the [Acceptable Use Policy](/legal/acceptable-use-policy), which is incorporated into these Terms. We may suspend access for violations as described there. ## 4. Data, rights, and attribution The data served by Financial Data API is compiled from third-party sources, including government agencies, central banks, statistical offices, and other official publishers. Financial Data API's public surface is curated to return only data that those sources make available on a public-domain or otherwise redistribution-permitted basis, together with analytics that Financial Data API derives from that data. Subject to these Terms, we grant you a non-exclusive, non-transferable, revocable license to access the Service and to use the data you retrieve for your internal and product purposes, including in applications you build. You must: * preserve and honor the source attribution that accompanies each observation; and * comply with any terms imposed by the underlying source for that data. You may not represent derived analytics as the output of any third-party source, and you may not resell or redistribute the raw datasets in a manner that competes with or substitutes for the Service. Where you have any doubt about the rights attached to a dataset, the `rights` metadata and the source attribution returned with each observation govern. We retain all right, title, and interest in the Service, the Financial Data API software, the normalized data model, and the derived analytics, except for the limited license granted above. ## 5. No investment advice The Service provides data and analytics for informational purposes only. Nothing in the Service constitutes investment, financial, legal, tax, or accounting advice, or a recommendation to buy, sell, or hold any security or instrument. You are solely responsible for any decisions you make using the data. ## 6. Fees and billing Free-tier access is provided at no charge subject to the published limits. Paid plans are billed in advance for the applicable period at the prices in the then-current plan you select. Unless stated otherwise, fees are exclusive of taxes, which you are responsible for. During early availability, billing may be handled by invoice; payment is due within the period stated on the invoice. If a payment is overdue, we may suspend or downgrade your access after reasonable notice. Except where required by law, fees are non-refundable; we may, at our discretion, prorate or credit amounts for service we failed to provide. We may change plan prices with reasonable advance notice; changes take effect at your next renewal. ## 7. Service levels and availability The Service is provided on an "as available" basis. We do not currently offer a contractual uptime or support service-level agreement. We may perform maintenance, impose or adjust rate limits, and throttle or suspend usage to protect the integrity and availability of the Service. ## 8. Warranty disclaimer THE SERVICE AND ALL DATA ARE PROVIDED "AS IS" AND "AS AVAILABLE", WITHOUT WARRANTIES OF ANY KIND, WHETHER EXPRESS, IMPLIED, OR STATUTORY, INCLUDING WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, NON-INFRINGEMENT, AND ANY WARRANTY THAT THE DATA IS ACCURATE, COMPLETE, CURRENT, OR UNINTERRUPTED. Data originates from third parties and may contain errors, omissions, revisions, or delays. ## 9. Limitation of liability TO THE MAXIMUM EXTENT PERMITTED BY LAW, NEITHER PARTY WILL BE LIABLE FOR ANY INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL, OR PUNITIVE DAMAGES, OR FOR LOST PROFITS, REVENUE, DATA, OR GOODWILL, ARISING OUT OF OR RELATING TO THE SERVICE. OUR TOTAL AGGREGATE LIABILITY ARISING OUT OF OR RELATING TO THE SERVICE WILL NOT EXCEED THE GREATER OF (A) THE FEES YOU PAID TO US FOR THE SERVICE IN THE THREE (3) MONTHS PRECEDING THE EVENT GIVING RISE TO THE CLAIM, OR (B) ONE HUNDRED U.S. DOLLARS (USD 100). ## 10. Indemnification You will defend, indemnify, and hold us harmless from claims, damages, and expenses arising from your use of the Service in breach of these Terms or the Acceptable Use Policy, or from your applications or end users. ## 11. Suspension and termination You may stop using the Service at any time. We may suspend or terminate access for breach of these Terms or the Acceptable Use Policy, for non-payment, for legal or security reasons, or if continued provision becomes impractical. On termination, your license to use the Service ends; sections that by their nature should survive (including 4, 5, 8, 9, 10, and 12) survive. ## 12. Changes, governing law, and miscellaneous We may update these Terms; material changes will be notified by a reasonable means and take effect on the stated date. Continued use after that date constitutes acceptance. These Terms are governed by the laws of the Republic of Singapore, and the parties submit to the exclusive jurisdiction of the courts of Singapore. If any provision is held unenforceable, the remainder stays in effect. These Terms, together with the Acceptable Use Policy and Privacy Policy, are the entire agreement between the parties regarding the Service. Contact: [support@financialdatapi.com](mailto:support@financialdatapi.com). # Pricing Source: https://docs.financialdatapi.com/pricing Macro and global-markets data as predictable, agent-native JSON. A genuinely useful free tier, two flat self-serve plans, and Enterprise for redistribution and bespoke needs. Financial Data API is priced for the transparent middle of the macro and markets data market: well above raw free feeds that give you numbers with no provenance, and far below opaque enterprise terminals. Point-in-time correctness and per-row provenance are included at every tier, because they are the reason to trust the data. Sign up, verify your email, and your key works immediately. Upgrade to a paid plan in the [dashboard](https://app.financialdatapi.com) — checkout and billing are handled securely by Stripe. Annual billing saves \~17%. ## Plans | | **Free** | **Advance** | **Scale** | | ------------------------------ | -------------------------------------- | ------------------------------------------------------------------- | ---------------------------------- | | **Price** | \$0 | \$59/mo (\$49/mo annual) | \$299/mo (\$249/mo annual) | | **Best for** | Evaluation, indie devs, agent builders | Research desks and production agents | Data-intensive workloads and teams | | **Dataset** | Full covered dataset | Full covered dataset | Full covered dataset | | **History** | Trailing 24 months | Full deep history (COT to 1986, backfilled calendar with consensus) | Full deep history | | **Point-in-time + provenance** | Included | Included | Included | | **Derived analytics** | — | Forecasts, surprise indices, COT percentiles, valuation multiples | Everything in Advance | | **MCP server (AI agents)** | — | Included | Included | | **Rate limit** | 60 req/min | 600 req/min | 2,400 req/min | | **Monthly calls** | 2,500 | 2M | 10M | | **API keys** | 1 | 5 | 10 | | **Use rights** | Evaluation and internal research only | Commercial internal use | Commercial internal use | | **Support** | Community | Standard | Priority, founder-answered | Higher volume, redistribution rights for the public-domain and official-source surface, bespoke datasets, and a direct relationship with the founder. [Contact us](/support). ## What we do not sell Financial Data API is the official, public-domain macro, derived-analytics, and SEC-fundamentals surface. Redistribution-blocked vendor market data is deliberately not part of the product, which is also what keeps your usage clean of licensing risk. Reliability today is best-effort, backed by a transparent public [status page](https://status.financialdatapi.com) and the unauthenticated `/health` and `/ready` endpoints. A contractual SLA is an Enterprise conversation, not a self-serve promise. Point-in-time correctness and per-row provenance are free on every tier, including Free. They are never gated, because they are the point. # Quickstart Source: https://docs.financialdatapi.com/quickstart Make your first Financial Data API request and page through results in a few minutes. This guide takes you from no account to a working request that pulls live macro data, with full provenance, in under five minutes. The base URL is `https://api.financialdatapi.com`, and endpoints use clean, versionless paths such as `/observations/latest`. ## Prerequisites * A Financial Data API key. Signup is self-serve and free; see [Create an API key](#1-create-an-api-key) below. * Either `curl` and a shell, or any HTTP client (Python `requests`, Node `fetch`, the official [TypeScript SDK](/sdks/typescript)). * Node.js 18+ if you plan to use the SDK. ## Get started Sign up at [app.financialdatapi.com](https://app.financialdatapi.com), verify your email, and create a key in the dashboard. It works immediately. The Free tier includes 2,500 requests a month with no card required. Export the key so the examples below pick it up: ```bash theme={"theme":"css-variables"} export FINANCIALDATA_API_KEY="your_key_here" ``` Keys are hashed server-side and never shown again after creation. Store yours securely the moment you create it. Pull the latest US CPI inflation reading. Either header form works; pick one and stay consistent. ```bash cURL theme={"theme":"css-variables"} curl "https://api.financialdatapi.com/observations/latest?country=USA&indicator=cpi_inflation_yoy" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` ```python Python theme={"theme":"css-variables"} import os, requests resp = requests.get( "https://api.financialdatapi.com/observations/latest", headers={"x-api-key": os.environ["FINANCIALDATA_API_KEY"]}, params={"country": "USA", "indicator": "cpi_inflation_yoy"}, ) resp.raise_for_status() print(resp.json()["data"]) ``` ```typescript TypeScript theme={"theme":"css-variables"} import { FinancialDataApiClient } from "@financialdatapi/client"; const client = new FinancialDataApiClient({ apiKey: process.env.FINANCIALDATA_API_KEY! }); const { data } = await client.getLatestObservations({ country: "USA", indicator: "cpi_inflation_yoy", }); console.log(data[0].actual, data[0].unit, data[0].period); ``` You will get back the standard response envelope: the value in `data`, request metadata in `meta`, and a `requestId` for tracing. The latest endpoint returns one row per indicator. To pull history, hit `/observations` and follow the cursor while `meta.pagination.has_more` is `true`. ```python Python theme={"theme":"css-variables"} import os, requests BASE = "https://api.financialdatapi.com/observations" HEADERS = {"x-api-key": os.environ["FINANCIALDATA_API_KEY"]} params = {"country": "USA", "indicator": "cpi_inflation_yoy", "limit": 500} cursor = None while True: page = {**params, **({"cursor": cursor} if cursor else {})} body = requests.get(BASE, headers=HEADERS, params=page).json() for obs in body["data"]: print(obs["periodEnd"], obs["actual"]) pagination = body["meta"]["pagination"] if not pagination["has_more"]: break cursor = pagination["next_cursor"] ``` ```typescript TypeScript theme={"theme":"css-variables"} import { FinancialDataApiClient } from "@financialdatapi/client"; const client = new FinancialDataApiClient({ apiKey: process.env.FINANCIALDATA_API_KEY! }); // The SDK auto-paginates: async iteration follows next_cursor for you. for await (const obs of client.paginate("/observations", { country: "USA", indicator: "cpi_inflation_yoy", })) { console.log(obs.periodEnd, obs.actual); } ``` See [Pagination](/concepts/pagination) for the full loop. Every observation carries `source`, `sourceUrl`, and an `observationId`. Pass the id to the provenance endpoint for the full auditable chain. ```bash theme={"theme":"css-variables"} curl "https://api.financialdatapi.com/provenance/observations/" \ -H "x-api-key: $FINANCIALDATA_API_KEY" ``` See [Provenance](/concepts/provenance) for what each field means. ## Where to go next Header forms, scopes, the keyless discovery endpoints, and rate-limit headers. Period, knowledge time, and `as_of`. The basis for lookahead-free backtests. Filter countries by canonical macro indicators with a compact DSL. A typed, zero-dependency client with auto-pagination and screener helpers. Need help? Email [support@financialdatapi.com](mailto:support@financialdatapi.com) and include the `requestId` from the affected response. See [Support](/support). # TypeScript SDK Source: https://docs.financialdatapi.com/sdks/typescript @financialdatapi/client: a typed, zero-dependency client over the Financial Data API envelope and errors. `@financialdatapi/client` is a thin, typed TypeScript and JavaScript client for the Financial Data API. It is read-only and has no runtime dependencies: it uses the global `fetch` (Node 18+ or browsers). It targets the same response envelope and the same stable error codes as the HTTP API, so what you learn from the REST surface carries over directly. The SDK adds three things over raw `fetch`: typed methods for each endpoint, a `FinancialDataApiError` thrown on non-2xx responses, and an async iterator that auto-follows cursor pagination. ## Install and build ```bash npm theme={"theme":"css-variables"} cd clients/typescript npm install npm run build # emits dist/index.js + dist/index.d.ts ``` ## Construct the client Pass your API key. The base URL defaults to `https://api.financialdatapi.com`, and the key is sent as `x-api-key` on every request. ```typescript theme={"theme":"css-variables"} import { FinancialDataApiClient } from "@financialdatapi/client"; const client = new FinancialDataApiClient({ apiKey: process.env.FINANCIALDATA_API_KEY, // baseUrl defaults to https://api.financialdatapi.com // fetch: customFetch, // optional: override the fetch implementation (e.g. for tests) }); ``` The constructor accepts `apiKey`, `baseUrl`, and `fetch`. On a runtime older than Node 18 with no global `fetch`, pass your own implementation via the `fetch` option or the client throws at construction. ## Make a call Every typed method returns the full envelope, so you read `data` and `meta` exactly as you would from the HTTP API. ```typescript Latest readings theme={"theme":"css-variables"} const { data, meta } = await client.getLatestObservations({ country: "USA" }); console.log(data); // latest public reading per canonical indicator console.log(meta.api_version); // "v1" ``` ```typescript Single series theme={"theme":"css-variables"} const series = await client.getObservations({ indicator_id: "cpi_inflation_yoy", country: "GBR", limit: 24, }); console.log(series.data); ``` ```typescript Coverage theme={"theme":"css-variables"} const coverage = await client.coverage(); console.log(coverage.data); // catalog totals, public indicator categories, covered countries ``` Typed methods include `listIndicators`, `listCountries`, `countryIndicators`, `resolveEntity`, `getObservations`, `getLatestObservations`, `getProvenance`, `screen`, `screenerFields`, `crossCountry`, `ratesAnalytics`, `economicCalendar`, `officialEvents`, `coverage`, and `sourceHealth`. The low-level `request(path, params)` escape hatch returns the same envelope for any endpoint not yet wrapped. ## Auto-paginate with the async iterator `paginate` is an async generator that walks every page of a list endpoint for you, following `meta.pagination.next_cursor` until it is exhausted. It yields one item at a time, so you never touch a cursor. ```typescript theme={"theme":"css-variables"} for await (const observation of client.paginate("/observations", { indicator_id: "cpi_inflation_yoy", country: "GBR", })) { // each observation across all pages, in order console.log(observation); } ``` Set `limit` (1 to 500) in the params to control page size. The iterator still returns every matching item regardless of page size; a larger `limit` just means fewer round trips. ## Build screener filters The screener takes a `filter` DSL of comma-separated `field:operator:value` clauses that are AND-ed together. `buildScreenerFilter` serializes structured clauses into that string so you do not assemble it by hand. The `screen` method accepts either form. ```typescript Structured theme={"theme":"css-variables"} import { FinancialDataApiClient, buildScreenerFilter } from "@financialdatapi/client"; const client = new FinancialDataApiClient({ apiKey: process.env.FINANCIALDATA_API_KEY }); const filter = buildScreenerFilter([ { field: "cpi_inflation_yoy", operator: "gt", value: 3 }, { field: "unemployment_rate", operator: "lt", value: 5 }, ]); // "cpi_inflation_yoy:gt:3,unemployment_rate:lt:5" const result = await client.screen(filter); ``` ```typescript Passed to screen() theme={"theme":"css-variables"} // screen() accepts structured clauses directly and serializes them for you const result = await client.screen([ { field: "cpi_inflation_yoy", operator: "gt", value: 3 }, { field: "unemployment_rate", operator: "lt", value: 5 }, ]); // equivalent DSL string const same = await client.screen("cpi_inflation_yoy:gt:3,unemployment_rate:lt:5"); ``` Operators are `gt`, `lt`, `gte`, `lte`, `eq`, and `in`. For `in`, pass an array; `buildScreenerFilter` joins it with the pipe separator the DSL expects. Discover the screenable canonical-indicator fields with `client.screenerFields()`. The screener screens public canonical-indicator values only. It never exposes any internal scoring. ## Handle errors Non-2xx responses throw a `FinancialDataApiError` carrying the stable `code`, the HTTP `status`, the `message`, the `requestId`, and any `details`. This is the same error contract as the REST API. ```typescript theme={"theme":"css-variables"} import { FinancialDataApiError } from "@financialdatapi/client"; try { await client.screen("oops"); } catch (error) { if (error instanceof FinancialDataApiError) { console.error(error.code, error.status, error.message, error.requestId); // e.g. "bad_request" 400 "..." "" } else { throw error; } } ``` The `code` is one of the stable values shared with the HTTP API: `bad_request`, `unauthorized`, `forbidden`, `not_found`, `rate_limited`, `internal_error`. Branch on `code`, not on the human-readable `message`. Unknown query parameters are rejected, not ignored. A typo in a param name throws `FinancialDataApiError` with code `bad_request` rather than silently returning unfiltered data. Catch it early in development. ## Related Native read-only tools for Claude Code, Claude Desktop, and Cursor. The keyless text indexes that describe the API to an agent. # Support Source: https://docs.financialdatapi.com/support How to get help with the Financial Data API and request an API key. Need a key, found something wrong, or want to talk to a human? Keys are self-serve; everything else reaches the team below. ## Get an API key Keys are self-serve. Sign up, verify your email, and your key is active immediately. No card is required, and the Free plan covers the full dataset with a trailing 24 month history window and 2,500 calls a month. app.financialdatapi.com You can create, rotate and revoke keys from the same dashboard, and upgrade a plan there when you need the full published history or higher limits. Keys are hashed server-side and are never returned after issue. Store yours securely when you create it. If it is lost or exposed, rotate it from the dashboard. ## Get help with the API For bugs, unexpected responses, or questions about behavior, email the same address. Before you write, the reference and the spec answer most questions. Endpoints, parameters, scopes, and the response envelope. The machine-readable contract. If it is not in the spec, it is not part of the public surface. ### Always include the request\_id Every Financial Data API response carries a `request_id` (mirrored as the top-level `requestId`, and inside `error` on failures). It identifies the exact request and lets us trace it server-side, so it is the single most useful thing to send. ```bash Read it from a header dump theme={"theme":"css-variables"} curl -i https://api.financialdatapi.com/observations/latest \ -H "x-api-key: $FINANCIALDATA_API_KEY" # The request_id is in the JSON body, under meta.request_id (and top-level requestId). ``` ```python Print it from a response theme={"theme":"css-variables"} import requests r = requests.get( "https://api.financialdatapi.com/observations/latest", params={"country": "USA", "indicator": "cpi_inflation_yoy"}, headers={"x-api-key": ""}, ) body = r.json() print("status:", r.status_code) print("request_id:", body.get("requestId")) ``` ```typescript Surface it from the SDK theme={"theme":"css-variables"} import { FinancialDataApiClient } from "@financialdatapi/client"; const client = new FinancialDataApiClient({ apiKey: process.env.FINANCIALDATA_API_KEY }); try { const res = await client.getLatestObservations({ country: "USA", indicator: "cpi_inflation_yoy", }); console.log("request_id:", res.meta.request_id); } catch (err) { // Financial Data API errors carry the request_id under error.request_id. console.error(err); } ``` When you report an issue, include: * The **`request_id`** from the affected response. * The **full request URL** (method, path, and query parameters). * The **HTTP status** and the **`error.code`** if the call failed. * A short note on what you expected versus what you got. You do not need to paste your API key, and you should not. The `request_id` is enough for us to find the request. ## Response times We aim to acknowledge access requests and support email within one business day. ## Status For live service health, check the unauthenticated health endpoints. `GET /health` reports liveness and `GET /ready` reports readiness; neither requires a key. [https://api.financialdatapi.com/health](https://api.financialdatapi.com/health)