Innovadata API Reference (Swagger) OpenAPI spec Get API key

Innovadata API

Query verified company data across 7 countries: Estonia, Latvia, Lithuania, Norway, Finland, Poland and Sweden. One simple REST API.

Filter by industry, location, size, financials, contact details and more, then pull the matching companies. Everything is JSON over HTTPS.

Start free: new accounts get 30 credits (€30 of data) on completing registration, enough for ≈ 750 Estonian company rows or hundreds of counterparty checks. On top of that, a 7-day trial gives unlimited API and MCP use. No card required; credits are valid for 7 days.

Base URL

BASE https://app.innovadata.eu

Each country exposes a slightly different filter set (Estonia has exact employee and turnover figures; Sweden has size bands instead, and no board members at all; Poland returns no person names; Swedish and Polish sole traders are held but not sold). The filters endpoint tells your app exactly which filters apply per country, so you never hardcode them.

Quick example
curl https://app.innovadata.eu/api/v1/data/companies?country=EE&page_size=3 \
  -H "Authorization: Bearer YOUR_API_KEY"

Authentication

Every request needs an API key, sent as a Bearer token:

HEADER Authorization: Bearer <your key>

Create a key in your dashboard → API keys → Create API key. The full key (ik_live_…) is shown once. Store it securely. Keep keys server-side; never embed them in a browser or mobile app.

Requests without a valid key return 401 Unauthorized.
Authenticated request
curl https://app.innovadata.eu/api/v1/data/countries \
  -H "Authorization: Bearer ik_live_xxx"

Quickstart

From zero to data in three calls:

1 · See which filters a country supports

Returns the filter list for the country and the exact query params to send.

2 · Check how many companies match

A free count (0 credits, rate-limited only) to size your query before pulling rows.

3 · Pull the companies

Page through the results. You're charged per returned row.

curl
# 1: filters for Estonia
curl ".../api/v1/data/filters?country=EE" -H "$AUTH"

# 2: count manufacturers with email
curl ".../api/v1/data/count?country=EE&has_email=true" -H "$AUTH"

# 3: pull 50 of them
curl ".../api/v1/data/companies?country=EE&has_email=true&page_size=50" \
  -H "$AUTH"

JavaScript & Python

Plain HTTPS + JSON — no SDK needed. The examples pull one page of Estonian companies with an email address and print the name, code and billing meta.

Parameter names. The original query parameters use internal (Estonian) column names. Since 2026-08-02 every one of them has an English alias — company_name, registration_code, industry_codes, legal_form, status, share_capital_min/max, registered_from/to. Both spellings work and will keep working; existing integrations need no changes. Prefer the English names in new code — the Estonian ones are marked deprecated in the OpenAPI spec.

Keep keys server-side. Calls from a browser would expose your ik_live_… key to every visitor.
JavaScript (Node 18+)
const res = await fetch(
  "https://app.innovadata.eu/api/v1/data/companies?" + new URLSearchParams({
    country: "EE", has_email: "true", page_size: "50",
  }),
  { headers: { Authorization: `Bearer ${process.env.INNOVADATA_API_KEY}` } },
);
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const { data, meta } = await res.json();
for (const c of data.items) console.log(c.registrikood, c.arinimi);
console.log(`charged ${meta.credits_charged} credits, ${meta.credit_balance} left`);
Python (requests)
import os, requests

r = requests.get(
    "https://app.innovadata.eu/api/v1/data/companies",
    params={"country": "EE", "has_email": True, "page_size": 50},
    headers={"Authorization": f"Bearer {os.environ['INNOVADATA_API_KEY']}"},
    timeout=30,
)
r.raise_for_status()
body = r.json()
for c in body["data"]["items"]:
    print(c["registrikood"], c["arinimi"])
print("charged", body["meta"]["credits_charged"], "credits")

Credits & metering

REST API, MCP and in-app Search all draw from one wallet balance. You pay per company row you pull; counts and metadata are free. New accounts get a 7-day free trial with unlimited, unmetered API + MCP use — when it ends you simply continue on pay-per-row credits, no cutoff. If per-row cost would exceed it, the optional Unlimited API & MCP plan (€1,500/month) waives metering for every country, and the per-country plan (€300/month per country) waives it for the countries you pick entirely; start it from your dashboard. The per-row prices below apply to all three.

1 credit = €1. Rows are priced per country: Estonia, Finland and Poland €0.04 per row, Latvia and Lithuania €0.08, Norway €0.10, Sweden €0.24 (the same prices as the main site; they can change, so treat the meta block in each response as authoritative).

  • Search reserves page_size × row price up front and refunds the unused portion based on rows actually returned.
  • Company detail costs one row's per-country price (e.g. €0.04 for an Estonian company).
  • Discovery and sizing are FREE: countries, filters, activities, locations and count cost nothing, so you can size a query before spending.
  • New accounts get 30 free credits on completing registration (valid 7 days). Admin/integration keys are unlimited.

Top up or check your balance in the dashboard (top-ups from €20). Each metered response includes a meta block with credits charged and your remaining balance.

meta in every metered response
{
  "meta": {
    "rows_returned": 50,
    "credits_charged": 2.0,
    "credits_reserved": 2.0,
    "credit_balance": 78.0
  }
}

Errors & limits

Standard HTTP status codes. Error bodies are { "detail": "…" }.

CodeMeaning
200OK
401Missing or invalid API key
402Payment required: insufficient wallet credits (top up in the dashboard)
404Not found (e.g. unknown company)
422Invalid or unknown parameter (e.g. unsupported country, or a misspelt filter name: nothing is run or charged)
429Rate limit exceeded

Standard keys are rate-limited per key; admin/integration keys are unlimited.

402 example
{
  "detail": "insufficient credits: have 10, need 50"
}

MCP for AI agents

POST /mcp

Innovadata is also a remote MCP server (Model Context Protocol, Streamable HTTP). Connect it to Claude Code, Claude Desktop or any MCP-capable agent and it gets tools to count, search and look up companies across all 7 countries directly. Authenticate with your ik_live_… key as a Bearer token.

Metered from your wallet, like everything else. The MCP server and the full REST API are priced per row from the same credit balance (counts and metadata are free). New accounts get a 7-day free trial with unlimited, unmetered use; after it you continue on pay-per-row credits. The optional Unlimited API & MCP plan (€1,500/month) waives metering; the per-country plan (€300/month per country) waives it for chosen countries only. Start either from your dashboard. Create an API key, then connect below.

Tools exposed: list_countries, list_filters, list_activities, list_locations, count_companies, search_companies, get_company (single-company verification lookup by registration code), get_company_history and, for Sweden, get_company_workplaces. Counts and metadata are free; search, detail, history and workplaces are metered per row.

Claude Code
claude mcp add innovadata https://app.innovadata.eu/mcp \
  --transport http \
  --header "Authorization: Bearer ik_live_…"
Claude API (MCP connector)
{
  "mcp_servers": [{
    "type": "url",
    "url": "https://app.innovadata.eu/mcp",
    "name": "innovadata",
    "authorization_token": "ik_live_…"
  }],
  "tools": [{ "type": "mcp_toolset",
              "mcp_server_name": "innovadata" }]
}

List countries FREE

GET /api/v1/data/countries

Returns the countries you can query.

Response
{
  "countries": [
    {"code":"EE","name":"Estonia"},
    {"code":"LV","name":"Latvia"},
    … LT, NO, FI, PL, SE
  ]
}

Filters per country FREE

GET /api/v1/data/filters?country=EE

The heart of the API: returns the filter set for a country, exactly like the website's filter panel. Each filter tells you the param to send to search, its type, and (for tree filters) an options_url.

FieldMeaning
paramquery param to send (or param_min/max, param_from/to)
typetext · select · tree · number_range · date_range · boolean
options_urlwhere to fetch choices (tree filters)

Differences are real: EE uses ehak_kood + EMTAK + employees/turnover; LT uses lt_locations; NO/SE use free-text location; FI/NO/PL/SE add vat_active; NO/PL/LT add share capital; PL adds the KRS filing filters annual_report_filed and annual_report_audited.

Response (excerpt, EE)
{
  "country":"EE", "industry_system":"EMTAK",
  "filters":[
   {"param":"emtak_codes","type":"tree",
    "options_url":"/api/v1/data/activities?country=EE"},
   {"param":"ehak_kood","type":"tree",
    "options_url":"/api/v1/data/locations?country=EE"},
   {"param_min":"last_quarter_employees_min",
    "param_max":"last_quarter_employees_max","type":"number_range"},
   {"param":"has_email","type":"boolean"}
  ]
}

Activity codes FREE

GET /api/v1/data/activities?country=EE&lang=en

The activity-classification tree for a country (EMTAK for EE, NACE/PKD/EVRK/SNI for the others). Use the leaf code values as emtak_codes when searching.

Response (excerpt)
[
  {"code":"C","label":"Manufacturing",
   "children":[
     {"code":"10","label":"Food products"}
   ]}
]

Locations FREE

GET /api/v1/data/locations?country=EE

Location tree for EE, LV, LT, FI, PL. NO and SE have no tree; they use the free-text location filter, so this endpoint returns 400 for them.

How to filter by a node: EE/LV/FI/PL nodes carry a codes array (the node plus all its descendants) — send that array as ehak_kood. A bare parent kood matches only rows tagged with exactly that code (Tallinn 0784 alone ≈ 338 rows; its full codes ≈ 158 000). LT nodes carry a locations array of name variants instead — send it as lt_locations.

Full trees are large (EE ~800 KB). query= searches nodes by name and returns them flat (max 100); max_depth= prunes the tree (1 = top level only).

Request
curl ".../api/v1/data/locations?country=EE&query=tallinn" -H "$AUTH"
Response (excerpt)
[
  {"kood":"0784","label":"Tallinn",
   "codes":["0784","0176","0298",…]}
]

Count companies FREE

GET /api/v1/data/count

Exact count of companies matching your filters. Call this first to size a query before spending credits. Accepts the same filters as search.

Request & response
curl ".../api/v1/data/count?country=EE&has_email=true" -H "$AUTH"
{ "country":"EE", "count":354244, "count_mode":"exact" }

Company detail METERED

GET /api/v1/data/companies/{registrikood}?country=EE

Full record for one company: contacts, activities and people. Costs one row at the country's price; refunded if the company isn't found (404). Poland: person names come masked to initials (the register redacts them) and sole-trader owners are left out.

Each figure in latest_metrics has its own period: turnover_period and employees_period ({year, quarter, month, as_of}; quarter 0 and month 0 = an annual figure, as_of = the period end where the source gives one). The top-level year/month belong to whichever figure is newer, so read the two periods before comparing them.

Each contact has a source: null = the country's business register; brreg_subunit = listed in the Norwegian register for one of the company's own sub-units; pl_regon / pl_krs / pl_ceidg = the Polish register it came from; own_site = read from the company's own website (role addresses such as info@ only); other values name an open dataset (for example uzt_lt, bis_lv, overture).

Sweden: se_register carries SCB's attributes — export_import, owner_category, sme_class, listing, turnover_class, activity_start_date, trade_names — each code with its label, and the source. Source attribution when you pass the data on: "Källa: SCB. Egen bearbetning av Innovadata OÜ."

ParamTypeNotes
registrikood pathstrregistration code
country requiredenumwhich country it belongs to
Request
curl ".../api/v1/data/companies/10000018?country=EE" \
  -H "$AUTH"
Response (excerpt)
{
  "data":{
    "registrikood":"10000018",
    "arinimi":"Acme OÜ",
    "contacts":[…], "emtak":[…], "people":[…]
  },
  "meta":{"credits_charged":1,"credit_balance":4997}
}

Company history METERED

GET /api/v1/data/companies/{registrikood}/history?country=EE

Time series of turnover and employee counts for one company, straight from the official registers, in chronological order — see growth or decline over time. Each row carries its own granularity (monthly / quarterly / annual / year_to_date / snapshot) and, where the source gives it, as_of = the period end; the top-level value is mixed when they differ. Costs one row at the country's price; free when the company has no history, and refunded on 404.

ParamTypeNotes
registrikood pathstrregistration code
country requiredenumwhich country it belongs to
CoverageGranularityFields
EEquarterly, 2025 →turnover, employees, state & labour taxes
LVannual, 2006 →turnover, employees (annual report figures)
LTmixedemployees monthly (2021–2023, 2025; 2024 pending backfill); taxes & turnover as annual totals (dense 2021 →, sparse 2015–2020). The current year's taxes are year_to_date (VMI publishes them cumulatively); a turnover row's as_of is the end of the company's financial year, which need not be 31 December. Each row carries its own granularity.
NOsingle snapshotemployees
FI · PL · SEthe registries publish no series (granularity: "none", not charged)
Request
curl ".../api/v1/data/companies/10000018/history?country=EE" \
  -H "$AUTH"
Response (excerpt)
{
  "data":{
    "registrikood":"10000018",
    "granularity":"quarterly",
    "periods":[
      {"period":"2025-Q1", "turnover":412805.6,
       "employees":12, "labour_taxes":48210.9},
      {"period":"2025-Q2", "turnover":455102.3,
       "employees":13, "labour_taxes":51877.4}
    ]
  },
  "meta":{"credits_charged":1,"credit_balance":4996}
}

Workplaces (Sweden) METERED

GET /api/v1/data/companies/{registrikood}/workplaces?country=SE

Every active workplace (branch, SCB arbetsställe) of a Swedish company, the main one first: name, postal and visiting address, municipality, size class, activity codes, phone, e-mail and the address coordinate in SWEREF99 TM. Each workplace has its own marketing block, honoured like the company's: addresses and coordinates are null under a postal block (marketing_optout), the phone under a telephone block (phone_optout) — of the workplace or of its company. Costs one row at the Swedish price; free when the company has no workplace on file, refunded on 404. MCP: get_company_workplaces. To find companies by branch location use se_workplace_kommun in search or count.

ParamTypeNotes
registrikood pathstrSwedish registration code (10 digits)
countryenumSE (the only country with workplaces)
Request
curl ".../api/v1/data/companies/5560000001/workplaces?country=SE" \
  -H "$AUTH"
Response (excerpt)
{
  "data":{
    "registrikood":"5560000001",
    "workplaces":[
      {"cfar_nr":42244590, "name":"Huvudkontor", "is_main":true,
       "visit_address":"Exempelgatan 1", "kommun_code":"0180",
       "employees_band_code":5, "marketing_optout":false}
    ],
    "source":"SCB Företagsregistret, arbetsställen. Källa: SCB. Egen bearbetning av Innovadata OÜ."
  },
  "meta":{"credits_charged":"one SE row", "credit_balance":…}
}