Sandbox (zz)
A synthetic jurisdiction for exercising every Kausate capability and testing webhook receivers against deterministic, free mock data
Overview
The Kausate Sandbox is a synthetic jurisdiction — code zz — that lets
you build and test against Kausate during development without touching a real
registry. It implements every Kausate capability against deterministic,
in‑process mock data, and its monitoring fires a webhook on every check so
you can test your webhook receiver on demand instead of waiting for a
real‑world registry change.
- No credentials, no setup — nothing to configure, no IP allow‑listing.
- Free — every sandbox SKU is zero‑credit; sandbox calls never consume credits or money, regardless of your plan.
- Deterministic — the same
kausateIdreturns the same data every time, so your assertions are stable (the one exception is the living companies described below, which evolve on purpose). - Opt‑in — the sandbox is enabled per organization. Ask us to turn it on for your org; it won't appear in your capability listing until then.
The sandbox is not a real registry. The data is fabricated and carries no accuracy guarantees — use it only to develop and test your integration.
The dataset
All sandbox companies use a kausateId of the form co_zz_…. You can discover
them with autocomplete or live search just like any other jurisdiction:
curl -H "X-API-Key: $API_KEY" \
"$BASE_URL/v2/companies/search/autocomplete?query=Sandbox&jurisdictionCode=zz"The sandbox is pre‑indexed with ~10,000 companies across five bands:
| Band | Sandbox number | What it's for |
|---|---|---|
| Roster | 000001–000005 | A handful of curated, rich edge cases (see below) |
| Bulk | 000006–010005 | ~10,000 deterministic companies for browsing, search, and pagination |
| Living | 700001–700050 | Companies whose data evolves over time — use these to drive the change‑detection monitor |
| Error | 800001–800005 | Companies that always return a specific error code instead of data |
| Shape | 810001–810003 | Ordinary successes carrying the data shapes integrations break on |
The five roster companies cover the shapes you'll want to test against:
| Company | Edge case |
|---|---|
| Sandbox Industries GmbH | a simple company — two individual shareholders, financials, documents |
| Sandbox Holding AG | a holding company |
| Sandbox Subsidiary Ltd | owned 75% by the holding + 25% by an individual → a multi‑level shareholder graph and UBO chain |
| Jane Doe Trading | a sole proprietorship — no shareholder block |
| Sandbox Defunct GmbH | an inactive / under‑external‑control company |
Every company in these bands is generated deterministically and always returns
the same data, so you can hard‑code the kausateIds you discover in your tests
without pre‑creating anything. The bands are the whole dataset — a co_zz_… id
from outside them isn't a sandbox company and won't resolve.
To turn a sandbox number from the tables below into the kausateId your calls
need, look it up by number — the mapping is stable, so you only have to do this
once per fixture:
curl -H "X-API-Key: $API_KEY" -H "Kausate-Version: 2026-05-01" \
-X POST "$BASE_URL/v2/companies/search/sync" \
-d '{"jurisdictionCode": "zz", "advancedQuery": {"sandboxId": "800001"}}'Exercising the capabilities
Every capability works against a sandbox company exactly as it does for a real
jurisdiction. Grab a kausateId from autocomplete, then call any endpoint —
for example a synchronous company report:
curl -H "X-API-Key: $API_KEY" -H "Kausate-Version: 2026-05-01" \
-X POST "$BASE_URL/v2/companies/report/sync" \
-d '{"kausateId": "co_zz_…"}'The same id works for search/live, finance, shareholder-graph, ubo,
documents/list + documents, and prefill. Use the multi‑level subsidiary
(Sandbox Subsidiary Ltd) to see a non‑trivial shareholder graph and UBO
chain — then use the error band to exercise the
branches your code takes when a call doesn't succeed.
Testing your error handling
A sandbox where everything succeeds lets you ship an integration that breaks the
first time it meets a real registry. Kausate publishes a stable, dotted code
on every error (see Errors), and the error band
gives you one company per code so you can exercise each branch of your error
handling on demand.
| Sandbox number | Company | Always returns | HTTP | On which calls |
|---|---|---|---|---|
800001 | Sandbox Vanished GmbH | company.not_found | 404 | every company call |
800002 | Sandbox Never Registered GmbH | company.does_not_exist | 404 | every company call |
800003 | Sandbox Confidential SAS | company.data_not_diffusable | 422 | every company call |
800004 | Sandbox Unfiled GmbH | document.not_found | 404 | document retrieval only |
800005 | Sandbox Restricted GmbH | document.type_unsupported | 400 | document retrieval only |
"Every company call" means the report, financials, UBO, shareholder graph, document list, document retrieval and prefill — the company is discoverable in search and autocomplete, and then every capability you order on it returns that one code:
curl -H "X-API-Key: $API_KEY" -H "Kausate-Version: 2026-05-01" \
-X POST "$BASE_URL/v2/companies/report/sync" \
-d '{"kausateId": "co_zz_…"}' # the 800001 company// → HTTP 404
{
"detail": "Company not found",
"code": "company.not_found",
"request_id": "req_e14506d86e0e452080d5de23ae5418b5"
}The two document companies behave differently on purpose: their report and
their document list are ordinary successes, so you reach the error the way you
would in production — list the documents, take a kausateDocumentId from the
list, request it, and the retrieval fails.
These are real production error types, not sandbox‑only ones — the code, the
message and the HTTP status are exactly what the same failure produces against a
live registry. They are all permanent errors, so the sandbox never spends
minutes retrying before it answers: report, financials, UBO, documents and
prefill return in well under a second, and shareholder-graph in a few seconds.
Testing awkward-but-valid data
These companies succeed. What they return is deliberately hostile to the assumptions integrations quietly make — every field present, Latin script, sensible lengths — and each one is a shape a real European register will hand you sooner or later.
| Sandbox number | Company | The shape |
|---|---|---|
810001 | Sandbox Sparse | Nothing but a name. No status, legal form, address, activity, director, shareholder, document or financial statement. Every optional field your client dereferences is genuinely absent. |
810002 | Пример Ωμέγα 株式会社 مثال Ünïcøde GmbH | Non‑Latin script in the company name, the address and a director's name — Cyrillic, Greek, CJK, Arabic (right‑to‑left) and Latin diacritics. Catches encoding, collation and name‑splitting bugs. |
810003 | Sandbox Vereinigte Maschinenbau‑ … Nachschusspflicht | A legal name over 300 characters, with a matching address and a director's name. Catches column truncation, fixed‑width layouts and single‑line log formats. |
For a large result set, search for a name shared by many companies in the
bulk band — Acme, Globex, Initech, Umbrella, Hooli and Cyberdyne all
match hundreds of companies, so any of them fills whatever page size you ask
for. This works on both search endpoints:
# autocomplete — returns a full page of 50
curl -H "X-API-Key: $API_KEY" \
"$BASE_URL/v2/companies/search/autocomplete?query=Acme&jurisdictionCode=zz&limit=50"
# live search — returns a full page of 20 distinct companies
curl -H "X-API-Key: $API_KEY" -H "Kausate-Version: 2026-05-01" \
-X POST "$BASE_URL/v2/companies/search/sync" \
-d '{"jurisdictionCode": "zz", "companyName": "Acme"}'Monitoring → a webhook on every check
The sandbox ships two monitoring sources so you can test your webhook receiver deterministically. Discover them for any sandbox company:
curl -H "X-API-Key: $API_KEY" \
"$BASE_URL/v2/monitors/sources?kausateId=co_zz_…"| Source | Behavior |
|---|---|
zz_sandbox.always_changing | Fires one generic change event every tick, for any sandbox company. Use it when you just want a steady webhook stream to test signing headers, retries, and payload shape. |
zz_sandbox.simulated | For a living company (700001–700050), each tick changes one real field, so you receive a different, realistic event_code in turn — NAME_CHANGED, COMPANY_STATUS_CHANGED, REGISTERED_ADDRESS_CHANGED, LEGAL_FORM_CHANGED, ACTIVITIES_CHANGED, and director changes. |
Then create a monitor and point it at your endpoint (or a webhook.site URL
while developing). scheduleCron is optional and defaults to monthly; set it
explicitly to control how fast the sandbox delivers:
curl -H "X-API-Key: $API_KEY" -H "Kausate-Version: 2026-05-01" \
-X POST "$BASE_URL/v2/monitors" \
-d '{
"kausateId": "co_zz_…", // a living company for varied events
"sources": ["zz_sandbox.simulated"],
"scheduleCron": "*/15 * * * *", // every 15 min ≈ 96 events/day
"webhookUrl": "https://your-server.com/webhooks/kausate"
}'The first tick records a baseline; every tick after that delivers a
monitor.change_detected webhook with the changed field in before / after
and the matching event_code. This lets you exercise your receiver's payload
parsing, signature verification, and retry handling without waiting for a real
registry change. See Monitoring & Webhooks for the
full webhook payload shape and delivery semantics.
Sandbox sources fire on every tick, so the cron you choose is the event rate.
A one‑minute cron (* * * * *) delivers roughly 1,440 events per day and
keeps retrying against an unreachable endpoint — pick the slowest cadence that
still exercises your receiver, and delete the monitor when you're done
testing (DELETE /v2/monitors/{id}).
Last updated on