Verdicts & confidence
Every validation returns exactly one verdict and one 0–100 confidence score. Both are computed by comparing the provider's answer against what you actually sent, never by trusting a provider's own 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 best-scoring 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.
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 per account (console Settings) between 50 and 99, with optional per-project overrides. 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.