Documentation
Everything you need to pull Nordic small-cap fundamentals, news and insider trades into your code, your warehouse, or your AI assistant.
Quickstart
- Get a key. Sign in at nordcap.dev/signup (magic link, no password, no card). Generate a key — it starts with
nc_live_and is shown once. - Make your first call:
# Curasight A/S — clinical-stage radiopharma on Spotlight curl -H "X-API-KEY: nc_live_..." \ https://api.nordcap.dev/financials/income-statements?ticker=CURAS
- Explore the universe:
GET /tickerslists all 749 companies with market and country.
Authentication
Every request needs your key in the X-API-KEY header. That's it — no OAuth dance, no tokens to refresh.
curl -H "X-API-KEY: nc_live_..." https://api.nordcap.dev/tickers
Tiers & limits
| Tier | Price | Calls / day | Webhooks |
|---|---|---|---|
| Explorer | Free | 250 | — |
| Quant | 499 kr/mo | 50,000 | ✓ 5 destinations |
| Fund | Contact us | Unlimited | ✓ 5 destinations |
Hitting the daily quota returns 429. The counter resets at midnight UTC.
Data coverage
749 companies across Denmark, Sweden, Norway and Finland — First North, Spotlight, NGM and Euronext Growth. Deliberately not the main markets: large caps like Novo Nordisk are well served by US data vendors; we cover the companies they can't see.
| Dataset | Coverage | Source |
|---|---|---|
| Company facts | All countries | National business registries |
| Financials | 🇩🇰 up to 13y history · 🇳🇴 annual accounts | Erhvervsstyrelsen XBRL · Brønnøysund |
| Filings | 🇩🇰 with document links | Erhvervsstyrelsen |
| News | All countries | MFN press releases |
| Insider trades | All countries | MAR art. 19 announcements |
Swedish and Finnish financials are on the roadmap (Bolagsverket digital filings; PRH when digital adoption grows). Empty responses for those today are expected, not errors. No share prices — fundamentals only.
GET /tickers
The full coverage universe. No parameters.
{
"tickers": [
{"ticker": "CURAS", "name": "Curasight A/S", "country": "dk", "market": "Spotlight"},
...
]
}
GET /company/facts
?ticker=CURAS — registry facts: legal name, registration number (CVR/orgnr), industry, employees, address.
{
"company_facts": {
"ticker": "CURAS", "name": "Curasight A/S", "country": "dk",
"market": "Spotlight", "cvr": 35249389,
"legal_name": "Curasight A/S", "industry": "...", "employees": ...
}
}
GET /financials/income-statements
?ticker=CURAS&limit=4 — annual fundamentals parsed from official filings, newest first. Fields are normalized across countries; amounts are in the reporting currency (currency).
{
"income_statements": [
{
"ticker": "CURAS", "period_end": "2025-12-31", "period": "annual",
"currency": "DKK", "revenue": ..., "operating_profit": ...,
"net_income": ..., "total_assets": ..., "equity": ..., "cash": ...
}
]
}
Norwegian rows carry "source": "brreg" and may include pretax_income, liabilities and a consolidated flag (group vs. parent-only accounts).
GET /filings
?ticker=CURAS&limit=10 — official filings with direct document links (doc_url), newest first.
GET /news
?ticker=CURAS&limit=10 — company press releases across all Nordic venues, newest first. Each item: id, title, source, published_at, url.
GET /insider-trades
?ticker=FREETR&limit=20 — MAR article 19 managers'-transaction announcements, classified from the press-release stream. A buy or sale by management is one of the strongest small-cap signals there is.
Webhooks Quant + Fund
Don't poll — register an HTTPS endpoint and we POST the moment new data lands. Wake an agent on a fresh insider trade, stream press releases into your warehouse, alert on a new annual report.
| Event type | Fires when |
|---|---|
| news.created | A new press release is indexed |
| insider_trade.created | A new MAR art. 19 announcement is classified |
| financials.created | A new annual report is parsed |
| filing.created | A new official filing is indexed |
Limits: 5 active destinations per account, one event type per destination. Endpoints must be public HTTPS.
Create a destination
curl -X POST https://api.nordcap.dev/webhooks/destinations \
-H "X-API-KEY: nc_live_..." -H "Content-Type: application/json" \
-d '{"url": "https://your-app.com/hook", "event_type": "insider_trade.created"}'
The response includes a signing secret (whsec_...) — shown only once, store it safely. Manage destinations with GET /webhooks/destinations and DELETE /webhooks/destinations/{id}. Fire a canned test event (with livemode: false) any time:
curl -X POST https://api.nordcap.dev/webhooks/destinations/{id}/test \ -H "X-API-KEY: nc_live_..."
Payload format
Every delivery is a JSON envelope; data.object has the same shape as the matching REST endpoint, so existing parsers work unchanged.
{
"id": "04b97437-62cd-4ccb-b7eb-54765dbaa72d", // dedupe on this
"type": "insider_trade.created",
"api_version": "2026-06-12",
"livemode": true,
"created": 1781293014,
"data": {
"object": {
"id": "...", "ticker": "FREETR",
"title": "Freetrailer Group A/S — indberetning af ledende medarbejderes transaktioner",
"published_at": "...", "url": "..."
}
}
}
Headers on every delivery: Content-Type: application/json, User-Agent: nordcap-webhook/1.0, and NC-Signature.
Verify the signature
Your endpoint is public — the signature is how you know a request really came from us. NC-Signature: t=<unix-ts>,v1=<hex> where v1 is an HMAC-SHA256 of {timestamp}.{raw_body} keyed with your destination's secret.
# Python import hashlib, hmac, time def verify(raw_body: bytes, header: str, secret: str) -> bool: parts = dict(p.split("=", 1) for p in header.split(",")) ts = int(parts["t"]) if abs(time.time() - ts) > 300: # reject replays older than 5 min return False expected = hmac.new(secret.encode(), f"{ts}.".encode() + raw_body, hashlib.sha256).hexdigest() return hmac.compare_digest(expected, parts["v1"])
// Node
const crypto = require("crypto");
function verify(rawBody, header, secret) {
const parts = Object.fromEntries(header.split(",").map(p => p.split("=")));
if (Math.abs(Date.now() / 1000 - +parts.t) > 300) return false;
const expected = crypto.createHmac("sha256", secret)
.update(`${parts.t}.`).update(rawBody).digest("hex");
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}
== instead of a constant-time compare; (3) forgetting the timestamp check, which is your replay protection.Retries & idempotency
- Reply fast. Any 2xx within 10 seconds counts as delivered. Queue heavy work for later.
- We retry failures after ~1 minute, then ~10 minutes. After three failed attempts the delivery is dead (new events still flow).
- 50 consecutive failures auto-disable the destination so we don't hammer a broken endpoint.
- Dedupe on the envelope
id— the same event can arrive more than once, and order isn't guaranteed. A unique-constraint insert on processed ids is the classic pattern.
MCP — connect your AI assistant
nordcap ships as a native MCP server at https://mcp.nordcap.dev/mcp. Once connected, your assistant can search companies, read financials and check insider trades in plain conversation.
| Client | How |
|---|---|
| Claude.ai / Desktop | Settings → Connectors → Add custom connector → paste the URL (leave advanced fields empty) |
| Claude Code | claude mcp add --transport http nordcap https://mcp.nordcap.dev/mcp |
| Cursor | Add {"nordcap": {"url": "https://mcp.nordcap.dev/mcp"}} under mcpServers in mcp.json |
Seven tools: list_tickers, search_companies, get_company_facts, get_income_statements, get_filings, get_news, get_insider_trades. Then just ask: "Any insider buying in Freetrailer lately?"
Anonymous MCP use is free up to 100 data calls/day per IP. Clients that can send headers (Claude Code, agent frameworks) can attach X-API-KEY to lift the cap to their tier's quota.
Agent Skill
For Claude Code (and any agent that reads Agent Skills): a ready-made skill that teaches the agent the whole nordcap system — endpoints, the NORDCAP_API_KEY convention, webhook signature verification, and the coverage rules so it never misreads an empty response.
# install for your user (macOS / Linux / Git Bash)
mkdir -p ~/.claude/skills/nordcap && \
curl -sL https://nordcap.dev/skill/SKILL.md -o ~/.claude/skills/nordcap/SKILL.md
# Windows PowerShell
New-Item -ItemType Directory -Force "$HOME\.claude\skills\nordcap" | Out-Null
Invoke-WebRequest https://nordcap.dev/skill/SKILL.md -OutFile "$HOME\.claude\skills\nordcap\SKILL.md"
Or download the zip and unpack it into .claude/skills/ in a project to share it with your team. Set NORDCAP_API_KEY in your environment and the agent handles the rest.
Bonus: The Council
A second skill that turns your assistant into a six-seat investment committee — the Bookkeeper, the Storm Rider, the Undertaker, the Insider Whisperer, the Catalyst Cartographer and the Chair — who debate any Nordic small-cap over live nordcap data, cross-examine each other, and close with a verdict card. Every claim must cite a real number from the data; disagreements are mandatory. Say "convene the council on CURAS" and take a seat.
mkdir -p ~/.claude/skills/nordcap-council && \ curl -sL https://nordcap.dev/skill/council/SKILL.md -o ~/.claude/skills/nordcap-council/SKILL.md
Download the zip. An AI simulation for research and fun — not investment advice, and it will tell you so itself.
Errors
| Code | Meaning | What to do |
|---|---|---|
| 401 | Missing or invalid X-API-KEY | Get a key at /signup, check the header name |
| 403 | Feature not on your tier (e.g. webhooks on Explorer) | Upgrade to Quant |
| 404 | Unknown ticker or resource | Check GET /tickers for coverage |
| 429 | Daily quota reached | Wait for the midnight UTC reset, or upgrade |
| 503 | Auth backend briefly unavailable | Retry with backoff — data plane is unaffected for recently-seen keys |
Questions, missing data, or a company we should add? Write us — we answer fast.