Know who to look at.
Know when to act.
Everything here does one of those two jobs. Resolve and Graph tell you which company you are looking at and what it is connected to. Watch, Sync and Grounding make sure every system you run finds out the day that changes.
Four scorers, one decision
Four independent scorers run over a blocked candidate set and are combined by a calibrated model. You get the winner, the runners-up, and the reason — so a low-confidence match becomes a review task instead of a silent error.
- Any input type. Free text, domain, email domain, VAT, LEI, DUNS, register number, EUID, brand name, former name, OCR line, postal address.
- Calibrated confidence. A 0.91 means it is right about 91% of the time. We refit the calibration monthly against SPOT-Bench and publish the residuals.
- Per-key thresholds. KYB wants 0.99 and a human on everything else. CRM dedup runs happily at 0.90. Both are one setting.
- Explainable. Every response carries per-scorer contributions and the fields that agreed or conflicted.
| Entity | Lexical | Embedding | Registry key | Geo | Score | Decision |
|---|---|---|---|---|---|---|
| Nordwind Logistik GmbH ent_01JR8K3F5T2QW9 · HRB 148902 | 0.91 | 0.96 | — | 0.98 | auto_accept | |
| Nordwind Kontraktlogistik GmbH ent_01JQ9V2H7YB4KC · HRB 204117 | 0.84 | 0.90 | — | 0.98 | review | |
| Nordwind Logistik Bremen (branch) ent_01JQ8B4X2VT7RC · HRB 148902-B1 | 0.79 | 0.83 | — | 0.41 | no_match | |
| Nordwerk Logistik GmbH ent_01JW2K6D9NF3PB · HRB 331507 | 0.74 | 0.71 | — | 0.22 | no_match |
The record behind the ID
The graph is what makes the ID worth having. Ownership chains, branch networks, brand portfolios and administrative geography are typed relations — so you can roll a portfolio up to its ultimate parent, or count every entity in a Swiss commune, in one call.
| Attribute group | Fields | Primary sources | Populated |
|---|---|---|---|
| Identity & status | 21 | National registers, BRIS | 100% |
| Identifiers | 14 | GLEIF, VIES, register, RDAP | 96% |
| Address & geography | 19 | Register, LAU/NUTS, national gazetteers | 99% |
| Classification | 11 | NACE 2.1, SIC, national codes | 93% |
| Financials | 38 | Bundesanzeiger, Companies House, Registro Imprese | 61% |
| Relations | 17 | Register filings, group accounts | 74% |
| Brands & marks | 23 | EUIPO TMview, WIPO GBD, USPTO | 91% |
| Web & digital | 26 | RDAP, CT logs, DNS, sitemaps | 81% |
| Events & history | 15 | Gazettes, announcement feeds | 97% |
Change events
Subscribe to an entity list or to a saved query — “any DE logistics company over €50M that files an insolvency notice”. Signed webhooks, at-least-once delivery, 7-day replay, and a dead-letter queue you can drain.
| Event type | Fires on | Volume / mo |
|---|---|---|
| entity.name_changed | Register name amendment | 61,400 |
| entity.status_changed | Liquidation, dissolution, reactivation | 248,900 |
| entity.insolvency_filed | Court insolvency notice | 9,120 |
| entity.officer_changed | Directors, managers, signatories | 412,700 |
| entity.capital_changed | Share capital increase or reduction | 38,500 |
| entity.address_changed | Registered seat relocation | 154,300 |
| entity.financials_filed | New annual accounts published | 643,000 |
| entity.merged | Merger, split, cross-border conversion | 14,600 |
| query.entered / query.exited | Entity enters or leaves a saved query | — |
31 event types in total.
{ "event_id": "evt_01JXR4T8M2C9KD", "type": "entity.officer_changed", "occurred_at": "2026-03-11T00:00:00Z", "observed_at": "2026-03-11T04:47:31Z", "entity_id": "ent_01JR8K3F5T2QW9", "subscription_id": "sub_01JH9F2Q7XB4NM", "change": { "field": "relations.officers", "before": { "count": 2 }, "after": { "count": 3 } }, "source": { "authority": "Amtsgericht Hamburg", "document": "src_01JXQ0W5R8T2LP", "gazette": "HRB 148902 / 2026-03-11" } }
Delivery p95 is 2.4 s from ingest; ingest median is 4.2 h from register publication.
Warehouse and CRM delivery
A Snowflake or BigQuery share that refreshes hourly. A dbt package with the join macros written. A Salesforce field map that writes the entity ID back onto the Account object. The pipeline is ours to run.
| Destination | Mechanism | Refresh | Writes back |
|---|---|---|---|
| Snowflake | Secure data share (EU / US) | hourly | — |
| BigQuery | Analytics Hub listing | hourly | — |
| Databricks | Delta Sharing | hourly | — |
| Postgres | Logical replication slot | streaming | — |
| Salesforce | Managed package, field map | 15 min | entity ID, name, status |
| HubSpot | App + property map | 15 min | entity ID, domain, NACE |
| dbt | spotit_core package | on run | — |
| Fivetran · Airbyte | Certified source connector | 6 h | — |
| Clay · n8n · Zapier · Retool | Native blocks | on demand | configurable |
The nine rows above are the connectors we build and support ourselves; the rest are community-maintained against the OpenAPI spec. Full list.
-- the spotit share is mounted as SPOTIT.CORE with resolved as ( select a.account_id, r.entity_id, r.confidence from analytics.crm_accounts a, table(SPOTIT.CORE.resolve(a.raw_name, a.country)) r where r.confidence >= 0.90 ) select e.entity_id, e.name as canonical_name, count(*) as crm_rows, array_agg(v.account_id) as collapse_into from resolved v join SPOTIT.CORE.entities e using (entity_id) group by 1, 2 having count(*) > 1 order by crm_rows desc;
| entities | 418.6M rows · one per canonical entity |
| identifiers | LEI, VAT, EUID, register number, domain |
| relations | 1.9B edges · parent, branch, brand, commune |
| events | Register filings from 2009, one row each |
| lineage | Field to source document, with observed_at |
Tools that return citations
An LLM will produce a company name, a registration number and a revenue figure with equal confidence, and only one of them will be checkable. spotit is the tool call that makes all three checkable — and it is wired into every framework in the table below.
- MCP server. Hosted at mcp.spotit.ai/sse, or run it locally with npx @spotit/mcp. Seven tools, scoped by API key.
- OpenAI-compatible tool schemas. Drop-in JSON for function calling, Anthropic tool use, Vertex, Bedrock and Azure AI Foundry.
- Framework adapters. LangChain, LlamaIndex, Mastra, Pydantic AI, Vercel AI SDK, CrewAI, Semantic Kernel.
- Test keys. A spk_test_ key reads the full graph, caps at 500 calls a day and is never billed, so an eval suite costs nothing to run.
- Citations included. Every tool result carries entity_id, source and observed_at, so your evaluator can grade groundedness without a second retrieval pass.
{ "mcpServers": { "spotit": { "url": "https://mcp.spotit.ai/sse", "headers": { "Authorization": "Bearer spk_test_..." } } } }
| spotit_resolve_entity | Messy input → entity ID + confidence |
| spotit_get_entity | Full record, optionally as_of a date |
| spotit_search | Structured filters: sector, geo, size, form |
| spotit_events | Register events for a set of entities |
| spotit_lineage | Source document behind any field |
| spotit_relations | Walk parents, subsidiaries, branches, brands |
| spotit_geo | Communes, districts, NUTS/LAU rollups |
Where the data comes from
Tier 1 is primary-register ingest with the full event history. Tiers 2 and 3 narrow to identity and identifiers, and the cards below say exactly which fields each one carries.
Ingested from the primary register, with the full event history behind every field.
Assembled from official sources that publish identity but not a full filing stream.
Identity only, from official aggregates and international registers.
| Jurisdiction | Legal entities | Primary register | Filed financials | Median freshness | Tier |
|---|---|---|---|---|---|
| United States | 41,209,774 | 50 SoS registries · SEC EDGAR | 9% | 27 h | Tier 2 |
| Germany | 6,412,880 | Handelsregister · Bundesanzeiger | 88% | 3.1 h | Tier 1 |
| United Kingdom | 5,704,119 | Companies House | 94% | 1.4 h | Tier 1 |
| France | 4,988,301 | INPI RNE · INSEE SIRENE | 71% | 6.8 h | Tier 1 |
| Italy | 3,146,902 | Registro Imprese | 79% | 9.4 h | Tier 1 |
| Poland | 2,905,441 | KRS · CEIDG | 57% | 11 h | Tier 2 |
| Netherlands | 2,381,660 | KVK Handelsregister | 64% | 5.0 h | Tier 1 |
| Switzerland | 762,455 | Zefix · SHAB | 22% | 2.2 h | Tier 1 |
What teams do with it
Six workflows, one underlying question: is this the same company as that one, and what is true about it today?
Screen the register directly
Define the universe with the filters that correlate with a deal — NACE code, revenue band, headcount trajectory, legal form, shareholder concentration, incorporation vintage, commune. Dedupe against your pipeline by entity ID, then put Watch on the survivors.
- 1Screen the register
- 2Dedupe against the pipeline
- 3Watch the survivors
Signals teams subscribe to: officer change, capital increase, first-time filing of consolidated accounts, new branch abroad, auditor change, insolvency of a customer or supplier in the same graph.
{ "jurisdiction": ["DE", "AT", "CH"], "nace": ["28.4", "28.9", "25.6"], "revenue_eur": { "gte": 10e6, "lte": 80e6 }, "headcount": { "gte": 50 }, "legal_form": ["GmbH", "GmbH & Co. KG"], "incorporated_before": "2005-01-01", "has_parent": false, "status": "active" }
The join key you never had
Batch-resolve the whole account table once. Rows sharing an entity ID are duplicates by definition — no fuzzy-match tuning, no merge-rules committee. Then keep it clean: Watch pushes name changes, status flips and seat relocations back through the managed package so nobody hand-edits an Account again.
- 1Batch resolve
- 2Collapse by ID
- 3Write the ID back
- 4Subscribe to changes
What the review queue contains: mostly holding companies that share a name with their operating subsidiary, and branches filed under a parent’s register number. Both are real ambiguities, which is why they are not auto-accepted.
| Rows submitted | 240,118 | — |
| Auto-accepted | 208,904 | 87.0% |
| Sent to review | 24,733 | 10.3% |
| No match | 6,481 | 2.7% |
| Distinct entities behind the matches | 189,477 | — |
| Duplicate rows (233,637 matched − 189,477 entities) | 44,160 | 18.4% |
| Dissolved / inactive accounts | 3,918 | 1.6% |
| Names now stale in CRM | 7,204 | 3.0% |
Retrieval keyed on identity
Index your documents against entity IDs and a query about “Nordwind Spedition” finds the 2024 contract filed under “Nordwind Logistik GmbH”. Agents that can call the register stop inventing registration numbers. And because every result carries a source and a timestamp, groundedness becomes a metric you can compute.
- 1Resolve at ingest
- 2Key chunks by ID
- 3Expose the tools
- 4Grade with citations
| Configuration | Exact-fact accuracy | Unsupported claims |
|---|---|---|
| Model alone, no tools | 41.8% | 38.2% |
| Web search tool | 67.4% | 14.9% |
| Name-matched RAG over filings | 72.1% | 11.6% |
| spotit tools, ID-keyed | 94.6% | 1.3% |
Also built on the same spine
Same spine, shorter story. Each links to a worked example in the docs.
Sales & GTM targeting
Size the addressable market from registers instead of a vendor estimate. Resolve the company field inside the form so routing sees a legal entity, and suppress accounts you already own by entity ID rather than by domain.
Market research
Segment by sector, legal form, geography and vintage, then replay the identical query with as_of at each year end. Formation and dissolution rates by commune, foreign-branch openings by parent jurisdiction, every count traceable to a gazette.
KYB & data validation
Existence, status, legal form, VAT and LEI checked against the register of record with the filing reference attached. spotit supplies registry facts, not sanctions screening — it gives your screening vendor clean LEI, VAT and EUID keys to work from.
Bring a messy CSV.
Leave with entity IDs.
Upload 1,000 rows on the free tier or 10,000 on Team. You get a match report with confidence bands, duplicates and stale names back before you write any code.