Documentation

Everything you need to pull Nordic small-cap fundamentals, news and insider trades into your code, your warehouse, or your AI assistant.

Quickstart

  1. 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.
  2. 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
  1. Explore the universe: GET /tickers lists 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
Treat the key like a password: store it in an environment variable or secret manager, never in source control. Revoke and reissue from the dashboard if it leaks — you can hold up to 5 active keys, so rotation is zero-downtime.

Tiers & limits

TierPriceCalls / dayWebhooks
ExplorerFree250
Quant499 kr/mo50,000✓ 5 destinations
FundContact usUnlimited✓ 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.

DatasetCoverageSource
Company factsAll countriesNational business registries
Financials🇩🇰 up to 13y history · 🇳🇴 annual accountsErhvervsstyrelsen XBRL · Brønnøysund
Filings🇩🇰 with document linksErhvervsstyrelsen
NewsAll countriesMFN press releases
Insider tradesAll countriesMAR 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 typeFires when
news.createdA new press release is indexed
insider_trade.createdA new MAR art. 19 announcement is classified
financials.createdA new annual report is parsed
filing.createdA 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));
}
Three classic mistakes: (1) verifying parsed-then-reserialized JSON instead of the raw bytes; (2) comparing with == instead of a constant-time compare; (3) forgetting the timestamp check, which is your replay protection.

Retries & idempotency

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.

ClientHow
Claude.ai / DesktopSettings → Connectors → Add custom connector → paste the URL (leave advanced fields empty)
Claude Codeclaude mcp add --transport http nordcap https://mcp.nordcap.dev/mcp
CursorAdd {"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

CodeMeaningWhat to do
401Missing or invalid X-API-KEYGet a key at /signup, check the header name
403Feature not on your tier (e.g. webhooks on Explorer)Upgrade to Quant
404Unknown ticker or resourceCheck GET /tickers for coverage
429Daily quota reachedWait for the midnight UTC reset, or upgrade
503Auth backend briefly unavailableRetry with backoff — data plane is unaffected for recently-seen keys

Questions, missing data, or a company we should add? Write us — we answer fast.