API documentation
Normalized financial data built from official filings. Every response uses the same schema, whatever the country or accounting taxonomy of origin.
Quickstart
1. Create your free API key (no card needed) from the dashboard. 2. Send your first request:
curl "https://api.nexusfilings.io/v1/companies/search?q=sample" \ -H "X-API-Key: YOUR_API_KEY"
3. With the id returned by the search, request the detail:
curl "https://api.nexusfilings.io/v1/companies/GB:SC000001/financials" \ -H "X-API-Key: YOUR_API_KEY"
Authentication
Every call (except the billing webhook) requires the X-API-Key header.
Base URL and environments
Production https://api.nexusfilings.io/v1
Development http://127.0.0.1:8420/v1 (local server, for your own testing only)
Endpoints
| Method | Endpoint | Usage units | Description |
|---|---|---|---|
| GET | /companies/search | 0 | Search by name and/or by exchange |
| GET | /companies/{id}/financials | 1 per company returned | Normalized detail. Free: 1 fiscal year per request (selectable with ?fiscal_year=); paid plans: their whole history in one request |
| POST | /companies/batch | 1 per company returned | Detail of several companies; ids without data cost 0 — not available on Free |
| POST | /screen | 1 per company in the results | Filter by metrics; 0 results cost 0 — not available on Free |
Search companies
Searches by name (q, at least 2 characters) across the demo catalog and the real listed companies of the UK, Denmark, Norway and SEC-registered US companies. Real matches include preloaded: true if data for that company is already stored. It doesn't use any usage units. Business plans also search the full UK registry (non-listed companies, via Companies House), with registry and company_status; in Denmark, Norway and the United States the search covers listed/registered companies only.
You can also search by exchange with exchange (e.g. ?exchange=Nasdaq, ?exchange=XLON for the London Stock Exchange Main Market, ?exchange=AIMX for AIM) — case-insensitive, exact match. At least one of q or exchange is required; passing both returns the union of both searches. Exchange search only covers listed/registered companies (it never applies to the full UK registry or the demo catalog).
{
"results": [
{ "id": "GB:SC000001", "name": "Sample Trading Ltd", "jurisdiction": "GB" }
]
}
Financial detail
The number of years returned depends on the plan (see limits): Free returns one fiscal year per request (the latest, or the one you request with ?fiscal_year=2024; the response includes available_years with the years you can ask for), and paid plans return their whole history in a single request. Every field carries its provenance: direct if it comes as-is from the filing, derived if Nexus calculated it, or unavailable if it could not be obtained or derived with confidence. Amounts are in the filing's own currency — never converted.
{
"company_id": "GB:SC000001",
"years_returned": 1,
"filings": [{
"income_statement": {
"revenue": { "value": 1250000, "source": "direct" },
"net_profit": { "value": 95500, "source": "direct" }
},
"ratios": {
"net_margin": { "value": 0.0764, "source": "derived" }
}
}]
}
First request for a company that is not preloaded — asynchronous response
Companies in the main catalog (large / listed) always answer instantly — they are preloaded. If you request a company (from the UK or Denmark) outside that catalog that nobody has asked for before, its first filing has to be downloaded and processed on the spot, which can take a few minutes (longer for large Danish companies). If no data can be found for the company (it doesn't exist or never filed accounts), the retry returns 404 company_data_unavailable, and if the source registry fails, 502 source_unavailable; the result is remembered for a few minutes so it isn't retried on every request. Instead of leaving the HTTP connection waiting all that time (many clients and load balancers cut the connection earlier anyway), the endpoint returns 202 Accepted immediately:
// HTTP 202 { "status": "processing", "company_id": "GB:07209813", "detail": "First request for this company: its real filings are being downloaded and processed...", "retry_after_seconds": 10 }
The API's detail fields are always in English; the error codes are stable and are what you should handle in code. Repeat the same GET after retry_after_seconds — while it is processing in the background it keeps returning 202; as soon as it finishes it returns 200 with the full filing, exactly the same shape as a normal request. Polling retries are not charged extra units, only the original request that triggered the processing. In addition, each plan has a monthly allowance of new companies to process (Free 5, Pro 50, Business 500): only the request that triggers a new processing counts, not retries or already-processed companies. If it runs out, the API responds 429 new_company_processing_limit_reached; if the shared daily capacity runs out, 503 processing_capacity_reached.
Batch
Charged by the number of companies returned, not per call: 1 usage unit per company that comes back with data. An ID that doesn't exist returns null in its place, costs nothing and doesn't abort the rest of the batch; the response includes units_charged. It also serves real UK and Danish companies that are already processed; a batch never triggers the processing of a new company, so the ones with a real-company format but no data yet come back as null and are listed in not_preloaded — request them one by one with GET /companies/{id}/financials.
// body { "ids": ["GB:SC000001", "DK:12345678"] }
Screening
Charged by the number of companies returned, not per call: 1 unit per company in the results, and 0 units if none match. It scans the demo data and the real listed UK and Danish companies that are already preloaded. Screening is limited per minute by plan (see limits): beyond it the API answers 429 screening_rate_limited, which costs nothing.
// body { "jurisdiction": "GB", "min_net_margin": 0.10 }
Response schema
Every filing, whatever the country, returns exactly these groups of fields:
income_statement revenue · gross_profit · operating_profit · net_profit
balance_sheet total_assets · total_liabilities · equity · cash_and_equivalents · net_debt
ratios gross_margin · net_margin · roe (always "derived")
Error codes
batch_too_large
More IDs were requested than the plan allows in a single call.
invalid_or_missing_api_key
The X-API-Key header is missing or the key doesn't exist.
*_not_available_on_plan
The endpoint (batch or screening) or the full registry is not included in your current plan.
company_not_found
No company exists with that ID.
burst_exceeded / monthly_quota_exceeded
You exceeded the rate limit (per second) or the monthly usage allowance. remaining_monthly comes in the body when applicable.
screening_rate_limited
You exceeded the plan's screenings per minute (see the limits table). It costs no usage units; retry after retry_after_seconds.
invalid_request
A parameter or the JSON body is missing or has the wrong type or format (for example q in a search, a non-numeric fiscal_year, or ids that is not a list of strings up to 64 characters each). The detail array lists each field and its message.
request_too_large
The request body is larger than 1 MiB.
password_too_long
Passwords are limited to 1,000 characters.
fiscal_year_not_available
The requested fiscal_year isn't available for that company or plan. The body includes available_years.
company_data_unavailable
No financial data could be found for the company (it doesn't exist or never filed accounts). The result is remembered for a few minutes.
new_company_processing_limit_reached
The plan's monthly allowance of new companies to process is used up. Already processed companies are unaffected.
source_unavailable
The source registry didn't respond or failed while processing the company. Retry later.
processing_capacity_reached
The shared daily capacity to process new companies is used up. Already processed companies remain available; retry after retry_after_seconds.
internal_server_error
Our error, not yours. If it persists, contact us with the request timestamp.
Limits and plans
| Free | Pro | Pro Team | Business | |
|---|---|---|---|---|
| Companies / month (usage units) | 250 | 5,000 | 10,000 | 50,000 |
| Burst (req/sec) | 2 | 5 | 8 | 20 |
| History | 1 year | 5 years | 5 years | full (up to the last 5 filed fiscal years) |
| Years per request | 1 | whole history | whole history | whole history |
| All registered companies, listed or not (full registry) | not available | not available | not available | included |
| Batch (max IDs) | not available | 20 | 40 | 100 |
| Screening | not available | included | included | included |
| Screenings per minute | not available | 20 | 30 | 60 |
| New companies processed / month | 5 | 50 | 100 | 500 |
| Users per workspace | 1 | 1 | up to 5 (3 included + 2 extra) | up to 10 (6 included + 4 extra) |
Pro, Pro Team and Business are billed monthly or annually — annual billing is 2 months free compared to paying monthly (16.7% off, e.g. Pro is $49/month or $490/year). Every limit above renews every month regardless of the billing interval you choose: an annual subscription doesn't accumulate 12 months of allowance into a single year, it gets the same monthly allowance renewed 12 times.
Pro Team and Business are shared workspaces: everyone in the team has their own API key, but they all draw from the same monthly allowance above — it isn't multiplied per user. Only the workspace owner manages billing and invites or removes members; extra seats beyond the included count are $25/month each, billed together with the plan and prorated immediately. Extra seats can only be purchased once every included seat is already filled — invite teammates first, then buy more capacity.
To cancel a paid subscription (or just review invoices and the payment method on file), go to the Subscription screen of the dashboard and press Manage subscription — it opens our payment provider's Customer Portal, where cancellation actually happens. We never cancel a subscription from inside Nexus Filings directly, so this button is the only way to do it.
Support and contact
| For | Write to |
|---|---|
Technical support and API issues (include the request timestamp and, if you have it, the company_id) | support@nexusfilings.io |
| Sales, Business and Enterprise plans | sales@nexusfilings.io |
| General questions, privacy and legal | contact@nexusfilings.io |
Pro plans get email support and Business plans get priority support, both through the developer support address. Nexus Filings is a product of Kimera Software SAS, Maldonado, Uruguay.
Python SDK
pip install nexus-filings
from nexus_filings_sdk import NexusFilingsClient client = NexusFilingsClient(api_key="YOUR_API_KEY") results = client.search("sample") filing = client.get_financials("GB:SC000001") print(filing["filings"][0]["income_statement"]["revenue"])
JavaScript / TypeScript SDK
npm install nexus-filings
import { NexusFilingsClient } from "nexus-filings"; const client = new NexusFilingsClient({ apiKey: "YOUR_API_KEY" }); const results = await client.search("sample"); const filing = await client.getFinancials("GB:SC000001");
OpenAPI and other languages
We publish the full specification in OpenAPI 3.0. Any language without an official SDK — Rust, PHP, Go, Ruby, .NET — can generate a typed client from it with openapi-generator, or import it straight into Postman/Insomnia to test without writing code.
openapi.yaml in the project repository. If your language doesn't have its own SDK yet, this is the recommended route.
MCP server (beta)
Connect an AI assistant (Claude Code, Cursor, …) to Nexus Filings through the Model Context Protocol. The assistant can search companies, fetch normalized financials, run batch requests and screen by net margin — using your account's plan and usage units, exactly like the REST API.
https://api.nexusfilings.io/mcp (Streamable HTTP, stateless)
Authentication. Two options. API key: send it in a header, Authorization: Bearer YOUR_API_KEY or X-API-Key: YOUR_API_KEY (Claude Code, Claude Desktop, Cursor). The key is never accepted in the URL (query string). OAuth sign-in: for apps that don't accept keys (ChatGPT, Claude on the web) add the endpoint above as a custom connector and choose to sign in — you authorize with your Nexus Filings email and password on a page hosted by the API, and the app never sees them. Both use the same plan and usage units. You can review and revoke connected apps in the dashboard (Connect to AI); changing your password revokes them all.
| Tool | Usage units | What it does |
|---|---|---|
search_companies | 0 | Search by (partial) name; returns ids like GB:07209813 |
get_financials | 1 per company | Normalized financials of one company (optional fiscal_year); compact values plus the formula of every derived field |
batch_financials | 1 per company returned | Several companies at once — Pro and Business |
screen_companies | 1 per company returned | Filter processed companies by net margin and jurisdiction — Pro and Business |
claude mcp add --transport http nexus-filings https://api.nexusfilings.io/mcp \ --header "Authorization: Bearer YOUR_API_KEY"
{
"mcpServers": {
"nexus-filings": {
"url": "https://api.nexusfilings.io/mcp",
"headers": { "Authorization": "Bearer YOUR_API_KEY" }
}
}
}
processing — ask again a minute later (retries cost nothing). OAuth sign-in follows OAuth 2.1 (PKCE S256, dynamic client registration, refresh-token rotation) and is in beta: we have tested it with the official MCP client, not yet with every third-party app.
Guides
01 — Search and fetch a company's financials
Almost every flow starts the same way: search by name to get the id, then request the detail with it.
matches = client.search("sample") company_id = matches[0]["id"] filing = client.get_financials(company_id)
02 — Compare the UK and Denmark with the same schema
The real value of the unified schema: two countries, two different accounting taxonomies (UK GAAP and DK GAAP), the same field name in the response.
uk = client.get_financials("GB:SC000001")["filings"][0] dk = client.get_financials("DK:12345678")["filings"][0] for f in (uk, dk): r = f["income_statement"]["revenue"] print(f["company"]["jurisdiction"], r["value"], f["currency"])
03 — Screen companies by net margin
Available on Pro and Business. It returns only the companies that meet the filter, and charges according to that number of results.
result = client.screen(jurisdiction="GB", min_net_margin=0.10) for company in result["results"]: print(company["name"], company["net_margin"])