Getting started
- Create a free account at app.firmtrove.nl and verify your email address.
- Under My account → Connections, create an access key. The key is shown once, stored hashed and can be revoked immediately. At most five active keys per account.
- Send the key as
Authorization: Bearer ft_live_…. Keys belong in a secrets manager, never in a URL or client code.
Connect your AI agent
Put your key in an environment variable and refer to it. Mind the single quotes for Claude Code: that way Claude stores the reference, not the key itself. Then check with claude mcp get firmtrove that the status is Connected.
Claude Code
export FIRMTROVE_KEY=ft_live_…
claude mcp add --transport http firmtrove https://app.firmtrove.nl/mcp \
--header 'Authorization: Bearer ${FIRMTROVE_KEY}'
Then just ask your question. Claude picks the right FirmTrove tool itself.

Codex
export FIRMTROVE_KEY=ft_live_…
codex mcp add firmtrove --url https://app.firmtrove.nl/mcp \
--bearer-token-env-var FIRMTROVE_KEYcodex mcp list shows the connection. The key itself stays in your environment.

Cursor
Put this in .cursor/mcp.json:
{ "mcpServers": { "firmtrove": {
"url": "https://app.firmtrove.nl/mcp",
"headers": { "Authorization": "Bearer ${env:FIRMTROVE_KEY}" }
} } }
The six tools
firmtrove_search_companies: search by name, sector, province, postcode, founding year and whether a website, phone or business email is availablefirmtrove_get_company: one company with every field you may seefirmtrove_market_size: counts per sector and provincefirmtrove_find_similar: similar companies with a reasonfirmtrove_export: a CSV within your export limitfirmtrove_dataset_info: state and labels of the database
REST
Base URL https://app.firmtrove.nl. All responses are JSON. Limits and labels equal the browser.
| Call | Parameters | Response |
|---|---|---|
GET /api/companies | q (at least 3 characters; searches name and city), sector, province, signal (tender, grant, timely), postcode (PC4 prefix or exact PC6 of the selected source-observed business location), foundedFrom, foundedTo (inclusive source-stated years), email=business_available, website=available, phone=available, page, limit (max 50), cursor from the previous bounded result | {total, items[], page, limit, hasMore, nextCursor}; total is null for postcode, founding-year and availability filters |
GET /api/companies/:id | id such as firmtrove:126726 | the record with an optional business-location postcode, source-stated founding year, other fields, signals and withheld |
GET /api/companies/:id/similar | {items[]} with reasons | |
GET /api/facets | search filters except postcode, founding year or website, phone or email availability | {total, sectors[], provinces[]} |
POST /api/exports | {companyIds[], idempotencyKey} (max 5,000 IDs for Pro, 100 for Free; the same key returns the same export) | {id, count, remaining, downloadUrl} |
GET /api/exports/:id | CSV (UTF-8, attribution on line 1) | |
GET /api/suppressions | {people[], items[]}: people who had themselves removed, as the sha256 of the lower-case email address or of the phone number as digits with country code (31612345678); delete or suppress them on your side too |
MCP
Endpoint POST https://app.firmtrove.nl/mcp, JSON-RPC 2.0, protocolversie 2025-03-26, the same Bearer key. Methods: initialize, ping, tools/list, tools/call. There is no streaming transport; GET returns 405.
| Tool | Arguments | Returns |
|---|---|---|
firmtrove_search_companies | q, sector, province, postcode, foundedFrom, foundedTo, email, website, phone, cursor | search result as in REST |
firmtrove_get_company | id | one record |
firmtrove_market_size | sector, province | counts per category |
firmtrove_find_similar | id | similar records |
firmtrove_export | companyIds, idempotencyKey | export receipt with downloadUrl |
firmtrove_removed_people | none | the same list as people in GET /api/suppressions |
firmtrove_dataset_info | none | available, shareRisk, exportRiskLevels, asOf |
Contacting someone
Put this sentence in your first message to someone from FirmTrove (section 10 of the terms):
I found your details through FirmTrove (firmtrove.com). Prefer not to be listed? You can remove yourself in one click at firmtrove.com/en/am-i-listed.
A real call
With the API key of a free account.
curl -s -X POST https://app.firmtrove.nl/mcp \
-H "Authorization: Bearer ft_live_…" -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"firmtrove_dataset_info","arguments":{}}}'
curl -s -H "Authorization: Bearer ft_live_…" "https://app.firmtrove.nl/api/companies?q=software&province=Utrecht"
{"total":87,"items":[{"id":"firmtrove:126726","name":"Bulxoft Software","city":"Lexmond",
"website":"https://bulxoft.com","province":"Utrecht","shareRisk":"attribution",
"withheld":[{"field":"sector","reason":"source_redistribution_not_approved"}, …]}, …],"page":1,"limit":12}
KVK API costs next to the FirmTrove API
The FirmTrove API is not the KVK API. The KVK API serves data from the Dutch business register and costs €6.40 a month, plus €0.02 per basic profile requested; searching is free. The FirmTrove API searches 4,306,825 company records, 2,957,640 of them with a KVK number. Free gives 100 export rows a month, Pro costs €29 a month excluding VAT and starts at 5,000 rows per calendar month, adding 2,500 each consecutive paid month up to 25,000. Pro Year costs €290 excluding VAT upfront and has 25,000 rows per calendar month from day one. If you need the official register profile per KVK number, the KVK API is the right source.
Limits and errors
The postcode is a source-observed business location and may differ from the registered office address. City, province and postcode may come from independently supported fields and do not together establish a verified registered address. The founding year is the value stated by the source and does not prove a legal incorporation or registry date. The business-email filter finds only the exact address available through standard API, MCP and CSV delivery; personal mailboxes and their separate export choice are outside this filter.
- CSV, REST and MCP share your monthly allowance. Browser views use no rows. Every row of a new CSV export counts; delivered REST and MCP IDs count once per UTC calendar month. Exports allow at most 5,000 rows for Pro and 100 for Free, within your remaining allowance. Each search shows at most 10,000 results. Postcode, founding-year and availability filters return a lower bound and a cursor, not an exact total.
401 login_requiredmissing or revoked key ·400 search_too_short·400 postcode_filter_invalid·400 founding_year_filter_invalid·400 search_depthrefine your filters ·400 availability_count_unsupported·400 availability_cursor_required·400 export_too_large·429 quota_exhausted·429 machine_record_quota·409 idempotency_conflictsame key, different selection ·410 export_withdrawna company in the export was removed later- Account limits are 30 searches and 60 detail requests per minute; IP limits are four times those amounts. Browser, REST and MCP share these limits. Exceeding the limits first throttles requests. The third renewed violation locks the account until manual review; it does not unlock automatically. For HTTP 429, follow Retry-After.
Fields
| Field | Meaning | Where the date comes from |
|---|---|---|
name, city, province, website, size | record identity | newest source sighting of the record |
postcode | source-observed business location; may differ from the registered office address | observation date of the selected source |
foundedYear | founding year according to the source; not proof of legal incorporation or registration | observation date of the selected source |
sector | source category | newest sighting with a category |
description, phone | verbatim quote from the own website | own observation date and expiry |
email | business mailbox in standard delivery; personal mailboxes have a separate export choice | verification date |
signals[] | kind tender, grant or timely with value | own observation date and expiry |
shareRisk | share risk of the record: none or attribution | |
withheld[] | fields not delivered, with reason |
Your shared monthly allowance
Pro: €29 a month excluding VAT. Start with 5,000 rows, adding 2,500 each consecutive paid month, up to 25,000 per calendar month. Pro Year: €290 excluding VAT paid upfront, with 25,000 per calendar month from day one.
Free has 100 rows per calendar month. CSV, REST and MCP share one allowance per account, including team members and multiple keys. Every exported CSV row counts, including a new export of the same company. REST and MCP count each delivered company ID once per calendar month, across keys and calls. That ID counts again in the next month. Downloading an existing export again uses no extra rows. Searching, filtering and viewing company records in the browser uses no allowance; rate limits apply. Per account, the limits are 30 searches and 60 detail requests per minute; IP limits are four times those amounts. Browser, REST and MCP share these rate limits. Exceeding the limits first throttles requests. The third renewed violation locks the account until manual review; it does not unlock automatically. Pro exports allow at most 5,000 rows and Free exports at most 100, within the remaining allowance. The allowance resets at 00:00 UTC on the first day of each calendar month and unused rows expire. Existing paid accounts retain 25,000 rows per calendar month.