Verdicts & confidence
Every validation returns exactly one verdict, one 0–100 confidence score, and a provider-consensus report. The engine verifies answers against your input first, then uses independent provider agreement to adjust confidence.
The three verdicts
| Verdict | Meaning | What to do |
|---|---|---|
| valid | Confidence is at or above your valid threshold and no checked component was corrected, mismatched, or missing. | Accept the address as submitted. |
| correctable | The address was found, but something had to be fixed (a misspelled street, a wrong postcode letter, a missing city). The response carries the standardized address. | Apply address, or show it to the user as a suggested correction. This is a success, not a failure. |
| invalid | Below the correctable threshold, no provider returned anything, or a supplied house number could not be matched. | Ask the user to re-enter. reasons tells you what went wrong. |
How the verdict is decided
In order, for the consensus-selected candidate:
- No candidate at all: invalid, reason
no_results. - You supplied a house number and the best result's house number is
missingormismatch: invalid, reasonno_house_number_match. A confident street-level hit is deliberately not treated as a deliverable address. - Confidence at or above the valid threshold and nothing corrected, mismatched, or missing: valid, no reasons.
- Confidence at or above the correctable threshold: correctable, with reason
components_correctedwhen something was corrected. - Otherwise: invalid, reason
low_confidence, pluscomponents_incompletewhen a component was mismatched or missing.
Because step 3 requires clean components, a result can score above your threshold and still come back correctable. That is intentional: it flags that the stored address differs from what the user typed.
Reasons taxonomy
A closed set of five values. reasons is an array and is empty for a clean valid.
| Reason | Meaning |
|---|---|
no_results | No provider returned any candidate. |
low_confidence | The best candidate scored below the correctable threshold. |
no_house_number_match | You supplied a house number and no result matched it. |
components_incomplete | A component was mismatched or missing (accompanies low_confidence). |
components_corrected | At least one component was corrected to produce the standardized address. |
Component verdicts
The components object reports how each part of your input compared to the result. Only checked components appear.
| Value | Meaning |
|---|---|
match | The result agrees with your input. |
corrected | Close enough to be the same address, but the canonical value differs (typo, formatting, postcode letters). |
mismatch | The result contradicts your input. |
missing | You supplied the field but the result has no value for it. |
not-checked | Not comparable for this request. |
The confidence score
Confidence is a unified 0–100 integer, comparable across providers. It is built from weighted component agreement:
| Component | Weight |
|---|---|
houseNumber | 0.30 |
street | 0.25 |
postcode | 0.25 |
city | 0.15 |
country | 0.05 |
Each component contributes points by its verdict: match scores 1, corrected 0.7, missing 0.2, mismatch 0, and not-checked is excluded from the weighting entirely. When a provider reports its own confidence, the adapter normalizes it to 0–1 and it blends in at weight 0.25. A per-provider, per-country calibration prior can scale the result (currently 1.0 for every provider, so it has no effect today).
Free-form query input is scored with presence-in-query checks; structured components input gets exact per-field comparison. Structured input therefore produces the more precise score when you have separate form fields.
Provider consensus
Each provider gets one vote: its highest input-verification candidate. Results form the same address cluster when their identifying components agree and, when both include coordinates, they are within 25 metres. One provider cannot create a majority by returning duplicate candidates.
With two or more providers, consensus.score is the percentage supporting the selected cluster. The final confidence blends 80% of the selected candidate's input-verification score with 20% of that consensus score. Unanimous agreement can raise confidence; disagreement lowers it. The report preserves baseConfidence and confidenceDelta so the adjustment is auditable.
| Status | Meaning |
|---|---|
unavailable | No provider returned a candidate. |
single-provider | Only one independent provider answered; confidence is unchanged. |
agreement | Every participating provider supports the selected address. |
partial-agreement | At least two providers support the selected address and at least one differs. |
disagreement | No address has support from more than one provider. |
disagreements names every conflicting provider and lists the differing fields. Coordinate conflicts also include distanceMeters. These details are available without debug mode and are stored in the console request log and Quality analytics.
Matching rules worth knowing
- House numbers carry real postal semantics:
2/B,2-b,2 B, and2Bare the same. A letter range2A-2Dcontains2B. A numeric range2-8respects street-side parity, so it contains 4 but not 3. The same number with a different suffix scorescorrected. - Postcodes compare digits and letters separately: a Dutch
1234 ABagainst1234 ACiscorrected, not a mismatch. - Street and city use normalization (diacritics, casing), Levenshtein similarity, and token/abbreviation containment.
Thresholds
The valid threshold defaults to 85 and is configurable directly on each project between 50 and 99. The correctable threshold is derived: 25 points below the valid threshold, never lower than 40. At the default that means valid ≥ 85 and correctable ≥ 60.
Raising the threshold makes valid stricter and pushes borderline results into correctable. Lowering it does the opposite. Changing the threshold also changes the cache key, so new settings take effect on the next lookup rather than being masked by cached responses.
Providers behind the verdict
| Id | Data | Coverage |
|---|---|---|
bag | Dutch national register (BAG) via PDOK | Netherlands only. Authoritative, with typo-aware correction. |
opencage | OpenCage | Global. |
photon | OpenStreetMap via Photon | Global. |
nominatim | OpenStreetMap via Nominatim | Global. |
Provider credentials belong to the platform, so you never bring your own keys. Which providers are active is a platform setting; GET /healthz reports the current list, and projects can restrict and reorder the ones they use. Providers that do not cover the requested country are skipped and traced as no-coverage.