Topograph

For engineers and product teams

See how our API really works

Topograph gives you company data and official documents through one standard API. Here we show how it works, where the limits are, and what happens when a register is slow or down.

Verification always uses official sources. Prefill uses the fastest suitable source, and tells you if the result is authoritative.

Get an API keyRead the docs
DocsQuickstartAPI referenceOpenAPI specMCP serverChangelog
curl -X POST https://api.topograph.co/v2/company \
-H "x-api-key: $TOPOGRAPH_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"countryCode": "FR",
"id": "123456789",
"mode": "prefill"
}'
200 OKPrefill · 1.2 s
{
"company": {
"legalName": "ACME SAS",
"status": {
"active": true
}
}
}
Each field shows its sourceINPI (RNE)authoritative: truelive_from_registry

API keys

Your first request in minutes

Create a sandbox key and start building today. When you're ready for production, our team helps you choose the countries, modes and volumes that fit.

01

Sign up

At app.topograph.co. The sandbox needs no credit card.

02

Create a key

In Settings. You get an sk_dev_ key for the sandbox.

03

Make a request

Paste the line below into a terminal.

Your first request · bash
curl "https://api.sandbox.topograph.co/v2/search?country=FR&query=Topograph" \
-H "x-api-key: sk_dev_..."

Separate environments

Testing uses api.sandbox.topograph.co. Production uses api.topograph.co. To go live, you change the key and the URL.

sk_dev_…api.sandbox.topograph.co
sk_live_…api.topograph.co

Limits in the headers

By default, you can run 40 requests at the same time. Each response shows how many you have left in X-Concurrency-Remaining. A 429 tells you how long to wait.

HTTP/1.1 200 OK
X-Concurrency-Remaining: 37

Workspaces

Separate usage by client, product or team, with a usage report for each. Useful if you resell our data.

A budget cap

Set a spending limit and billing alerts, so a large import can't create a big bill overnight.

In the docsQuickstart →Concurrency and backfills →Workspaces →Billing notifications →

Sandbox

Test safely in the sandbox

The sandbox is a separate environment with its own API key, webhooks, request history, members, and roles. It covers every country we support with test data. It never contacts a register and never charges you. Pick a case and run it.

Country

The sandbox covers every market we support. This demo lists 46 markets.

Mode

Test identifier

Each error code in the live API has a test identifier. Here are six.

Request
curl -X POST https://api.sandbox.topograph.co/v2/company \
-H "x-api-key: sk_dev_..." \
-H "Content-Type: application/json" \
-d '{
"countryCode": "FR",
"id": "418166096",
"mode": "prefill"
}'
Sending…api.sandbox.topograph.co
Test data in the local format for France, marked as test data. Same structure as production.

Responses are shortened here. The full responses are in the development environment guide.

Real local formats

Test with the identifier formats, legal forms, roles and document types of each country.

Repeatable results

Test success, outages, slow responses, webhooks and edge cases. You get the same result every time.

Same API

Endpoints, requests, responses and webhooks are the same as in production. When you are ready, change the key and the URL. One exception: the ownership graph needs real registers, so it is not in the sandbox.

Test data, clearly marked

Sandbox results are test data, not register data. Sandbox requests do not appear in your production history or billing.

In the docsDevelopment environment →All test identifiers →Webhooks →

Asynchronous by design

Fast results first, the rest when ready

Some registers answer in milliseconds, others in minutes, sometimes in the same request. We don't make you wait for the slowest one. We send what is ready, send the rest when it arrives, and handle retries for you.

Streaming search

With stream=true, /v2/search sends results as Server-Sent Events. Results from our index come in less than a second. Results from the registers follow when they arrive. Search is free, with fair use.

text/event-stream
curl -N "https://api.topograph.co/v2/search?country=DE&query=Acme&stream=true" \
-H "x-api-key: $TOPOGRAPH_API_KEY"
Waiting for the first event…
Waiting

Each datapoint arrives on its own

Each datapoint and document has its own status in dataStatus. Fast ones come in the response. Slow ones come later by webhook, one by one. You can fill the form with what you have, without waiting for the slowest register.

ResponseBy webhook
companyProfile0.9 s · responsein_progress
legalRepresentatives1.4 s · responsein_progress
shareholders2 min · webhookin_progress
tradeRegisterExtract6 min · webhookin_progress
0.1 s1 s10 s1 min10 min

Example timings, log scale: one Verification request in Germany.

We handle retries

Registers time out, limit traffic and go down for maintenance. We retry and switch between sources inside the request, so most problems never reach your code. Verification keeps trying for up to one hour.

If it still fails, the datapoint tells you if you can retry, and when.

A failed datapointjson
"shareholders": {
"status": "failed",
"error": {
"code": "source_unavailable",
"retryable": true,
"retryAfterSeconds": 900
}
}

You can retry five codes. All other codes are final.

service_unavailablesource_unavailableprocessing_failedrequest_cancelledprocessing_interrupted

Three ways to get results

POST /v2/company answers at once, with a request ID and any data already available. Get the rest the way that suits you.

200 response
Data that is ready during the request. Prefill usually ends here.
webhook
Each datapoint when it arrives, signed. If your server is down, we retry for up to 3 days.
GET /v2/company/{requestId}
Check the status any time. Always free.
PDF extract
Download it at any time, even before the request ends. It lists what is included, what is still coming, and what failed and why.
In the docsCompany search and streaming →Webhooks →Retryable errors →Polling a request →

Response times

Response times by country

One global average hides the countries that matter to you. We show P50 and P90 for each country and mode, measured on successful production requests where we have enough traffic. These numbers measure speed, not how recent the data is. Source details tell you where each result came from.

Prefill, per datapointP50P90
United Kingdom
Companies House · 0.6 s / 1.4 s
Netherlands
KVK · 0.7 s / 1.8 s
France
INPI (RNE) · 0.9 s / 2.1 s
Germany
Handelsregister · 1.8 s / 4.6 s
Spain
Registro Mercantil · 2.6 s / 7.2 s
0 s5 s10 s deadline

Example figures. Real figures for each datapoint and mode are on each country page.

  • PrefillEach datapoint has 10 seconds. If it takes longer, it returns onboarding_timeout. Other datapoints in the same request can still succeed.
  • VerificationComplete data matters more than speed here. Slow sources can take minutes. If a register is down, we retry for up to one hour before we mark the item as unavailable.
  • Each country is differentEach country page shows availability, sources and supported modes. Check it before you design a flow for a country.

Use the coverage pages or the /v2/pricing endpoint to check availability and price before you send a request.

In the docsVerification vs Prefill →Coverage and pricing →Pricing endpoint →

Change policy

Changes you can plan for

We update the changelog every week: new countries, new datapoints, faster registers. Below are our rules for what can change, and how much notice you get before anything breaks.

01

Additive changes ship any week

New fields, datapoints, countries, document types and error codes. Make sure your code ignores fields it does not know.

02

Breaking changes run in parallel

Old and new run side by side for at least 90 days, so you can migrate when it suits you.

03

You hear about it directly

Every breaking change is in the changelog, which has an RSS feed. We also email every account that used the endpoint in the last 30 days.

04

Deprecated doesn't mean removed

Deprecated endpoints and parameters keep working until the removal date. We announce that date at least 3 months before.

05

Beta is clearly marked

Fields marked beta can change without notice. Everything else follows the rules above.

06

Register changes are our problem

When a register changes its format, we update our side and keep the same schema. Our target is a fix within 24 business hours. Your code sees the same fields.

A new major version gets a new path. When /v3 comes, /v2 keeps working for at least 12 months.

In the docsChangelog →Full versioning policy →Migrating off /v2/onboarding →

Status

A clear view of service status

status.topograph.co shows our API and each register separately. When requests in one country fail, you can quickly see if the problem is ours or the register's, and tell your customer.

status.topograph.coLast 45 days

Our side

APIOperational
WebhooksOperational
SandboxOperational

The registers' side

HandelsregisterDegraded
INPI (RNE)Operational
KVKOperational
Companies HouseOperational

Example only. Real status and history are on status.topograph.co.

  • Our sideAPI, webhooks and sandbox, each with its own uptime.
  • The registers' sideEvery register we use, by country. We show register outages too. They are not ours, but they affect you.
  • Format changesWhen a register changes its format, we open an incident. Our target is a fix within 24 business hours.
  • HistoryPast incidents stay visible, with what happened and what we changed.
  • UpdatesSubscribe to hear about incidents from us, before your customers tell you.

Errors

Clear answers when something changes

Registers go down, change their format, or take minutes to answer. When a request fails, the response names the register and gives the reason, so you know if a retry will help. Your support team can say “the German register is down”, not “something went wrong”.

Whose sideWhat you getWhat to do
Yours to fix400invalid parameters401missing or wrong key402not enough credits429too many requestsFix the request. For a 429, Retry-After tells you how long to wait.
The register'ssource_unavailableregister unavailable, naming the registerPrefill fails at once, so your customer does not wait. Verification retries for up to one hour first.
Not available here404company not found404document unavailable404datapoint does not apply to this company406country or feature not supportedonboarding_timeoutfast_source_unavailableNothing to retry. Change the request, switch mode, or skip the field in that country.
Ours500something broke on our sideRetry. If it keeps happening, contact support.
Not an error200with status: in_progressThe register is slow. You get the result by webhook, or you can check the request ID for free.
A register outage, as you get itjson
{
"statusCode": 503,
"code": "source_unavailable",
"countryCode": "DE",
"register": "Handelsregister",1
"message": "The register did not respond. Retried for 60 minutes.",2
"requestId": "req_..."3
}
  1. 1Names the register, so your support team can tell your customer which one is down.
  2. 2Says what we already tried, so you know if a retry will help.
  3. 3Gives you a request ID to check, for free.

You never pay for a failed request.

In the docsReliability and errors guide →Polling a request →Pricing and caching →Every failure, and what's charged →

FAQ

Get started

Get a key and try it

In the sandbox, you can trigger every error on this page and see how your code reacts. When you are ready for real registers, change the key and the URL. The rest of your code stays the same.

Get an API keyRead the quickstart

Prefer to talk to someone technical? Book a call.