Matching guide

Core·18 min·updated 2026-08-14

Matching is a modelling problem wearing a string-similarity costume. This guide explains what the score is made of, what it is calibrated against, and how to choose the band where a human looks.

The pipeline, in four stages

  1. Normalise. Case, punctuation, diacritics, and 1,900 legal-form variants across 192 jurisdictions — GmbH, Ges.m.b.H., gesellschaft mit beschränkter haftung collapse to one token, and the form itself becomes a separate feature rather than part of the name.
  2. Block. A learned key set proposes candidates. Blocking is why p50 is 38 ms rather than a table scan; it is also the only stage that can lose a true match outright, so recall at this stage is measured separately and sits at 99.87%.
  3. Score. Four scorers run over each candidate and produce a feature vector, not a single number.
  4. Calibrate. A per-jurisdiction isotonic model turns that vector into a probability that means what it says.

The four scorers

ScorerWhat it seesWeight at auto_accept
Register keyRegister number, VAT, LEI, EUID0.52
NameToken set, legal form, transliteration, former names0.21
GeographyAddress, postcode, commune, NUTS/LAU rollup0.16
Web identityDomain, RDAP registrant, certificate SANs0.11

The weights are illustrative of a typical accepted match, not fixed coefficients: a register-key hit dominates when present, and the other three carry the decision when it is absent. This is why edit distance plateaus around 78% on real CRM data — three of the four signals are not in the name at all.

Former names are first-class

A rename does not create a new entity. The name scorer sees every name the register has published for a company since 2009, each with the window it was current in, and a match against a former name is annotated rather than discounted.

Matching on a name that has not been current since 2019
{
  "match": {
    "entity_id": "ent_01JR8K3F5T2QW9",
    "confidence": 0.971,
    "decision": "auto_accept",
    "matched_on": "former_name",
    "matched_value": "Nordwind Spedition GmbH",
    "current_since": "2019-04-02"
  }
}

Calibration, and why it is per jurisdiction

A global threshold is a lie told to whichever jurisdiction is furthest from the mean. Germany publishes a register number with almost every filing; several US states publish a name and a status and little else. A raw score of 0.90 therefore means something different in each.

Since API version 2026-06-01, confidence is calibrated per jurisdiction against SPOT-Bench, so 0.90 means the same empirical precision everywhere. The deprecated score field, which was not calibrated, was removed in that version.

Confidence bandPrecisionShare of traffic
0.95 – 1.0099.4%81.2%
0.85 – 0.9594.1%9.7%
0.70 – 0.8578.3%5.4%
Below 0.7041.0%3.7%

Choosing your threshold

The right band depends on the cost of a wrong accept relative to the cost of a review. Three worked positions:

  • CRM deduplication. A wrong merge is expensive and hard to unpick. Auto-accept at 0.97, review 0.80–0.97, discard below. Roughly 6% of records reach a human.
  • GTM enrichment. A wrong enrichment costs an email. Auto-accept at 0.85, no review queue, discard below. Under 1% needs attention.
  • KYB pre-check. Never auto-accept on the score alone. Require a register-key hit — matched_on of register or vat — and route everything else to review.
Worth knowing

Do not use confidence as the deciding input in an automated decision with legal effect on a person. The Acceptable Use Policy says so, and so does Article 22.

Reading the evidence

Every candidate in alternatives carries the per-scorer contribution that produced its score. A review queue that shows the analyst why the machine hesitated is resolved roughly three times faster than one showing only a number.

An alternative, with its evidence
{
  "entity_id": "ent_01JQ9V2H7YB4KC",
  "name": "Nordwind Holding AG",
  "confidence": 0.612,
  "evidence": {
    "register_key": null,
    "name": 0.74,
    "geography": 0.91,
    "web": 0.38
  },
  "why_not": "no register key in common; address is the shared group seat"
}

Where we lose

  • Sole traders and unregistered businesses. No register key exists, so the name and geography scorers carry everything. Top-1 falls to 84.2%.
  • Freshly incorporated companies. A company registered this morning is not in a gazette yet. Median lag to first appearance is 4.2 hours, but the tail is days in a few jurisdictions.
  • Transliterated names in non-Latin scripts. Greek and Bulgarian names round-tripped through a CRM lose accents and gain ambiguity; top-1 is 91.8%.
  • Deliberately similar names. Two active companies with the same name in different communes are a real thing, and where geography is absent from the input we return both rather than guess.

The full measurement, including the harness, is in the SPOT-Bench methodology.

Try it against your own data

The Developer plan is free forever and needs no card. 2,500 credits is enough to answer the only question that matters: does it resolve your records.