# How to read an address-existence answer

Premise, street and postcode matches prove different things, and absence from a partial register proves nothing at all. A field-by-field reading of exists.

Date: 2026-09-05

"Does this address exist?" sounds like a yes-or-no question. It is not, and the products that answer it as one are quietly making things up. Whether a given building can be found depends on which register you asked, how much of the country that register covers, and how far into it the address could be followed. This guide is about reading that answer honestly: the three match levels, the three states of `exists`, and what each of them is worth in a decision.

## Two fields, read together

Spaw answers existence with a pair.

`match_level` says how far the address was followed into the register: `premise` (the building itself), `street` (the street, not that number on it), `postcode` (the postcode area only), `none` (nothing matched), or `null` (no register was consulted at all).

`exists` turns that into a verdict, and it is deliberately hard to make it say no:

- **`true`** only on a `premise` match. The building itself was found.
- **`false`** only when the register that answered claims, in its own publisher's words, to list every address in its country — and does not carry this one.
- **`null`** in every other case: no register covers the country, the register that does covers only part of it, or the address is a box with no street behind it.

Two more fields tell you who answered and how far to trust the answer: `register` names the dataset, and `register_coverage` reports `complete` or `partial` as its publisher describes it. Read `exists` against `register_coverage` every time.

## The four answers, measured

These are real answers from the Swiss building-address directory, a register whose publisher describes its coverage as complete, run through the lookup on 5 September 2026.

| Address | match_level | exists | risk |
| --- | --- | --- | --- |
| Bahnhofstrasse 1, 8001 Zürich | premise | true | 0 |
| Bahnhofstrasse 9999, 8001 Zürich | street | false | 20 |
| Nonexistentstrasse 999, 8001 Zürich | postcode | false | 20 |
| Bahnhofstrasse 1, 9999 Zürich | none | false | 20 |

Read the second row carefully, because it is the interesting one. The street is real and was found; the house number on it is not. The answer keeps both facts — `match_level: street` and `exists: false` — instead of collapsing them, so you can tell "wrong number on a real street" (usually a typo, worth asking about) from "street nobody has heard of" (usually a fabrication, or a very new development).

The last row is the reverse: a real street and number with a postcode that does not belong to it. A complete register that carries neither the premise nor the street in that area answers `false`, and `match_level: none` tells you the search never got anywhere at all.

## Why absence from a partial register proves nothing

Change the register and every `false` above becomes `null`.

Some national registers are contributed to voluntarily. The United States National Address Database is assembled from what states and local authorities choose to submit, and the French Base Adresse Nationale from what communes choose to publish; both describe their own coverage as partial. In a register like that, "not found" carries no information about the address at all. It might not exist. It might sit in a county that never sent its data.

So Spaw does not say `false` there. It says `null`, which means *not evaluated* — and the difference is enforced right through to the score: the `not_in_register` signal fires only when `exists` is `false`, so an address missing from a partial register contributes exactly zero points. There is no quiet penalty for living somewhere whose local authority did not take part.

This is the single most important line in this guide, so it is worth writing plainly: **absence from a partial register is not evidence that an address does not exist.** Any product that scores it as if it were is charging you for a bug.

## Null is not no

The same discipline runs through every flag in the response, and it is worth mapping it into your own schema properly. `null` is not `false`. It means the dataset that would have answered is not installed for that country, or was not applicable to that address.

- `exists: null` — no register answered. Say nothing about the building.
- `is_po_box: null` — the box naming for that country is not carried, so "not a box" was never established.
- `is_mail_drop: null` — neither the operator lists nor a company register covered it.
- `deliverability_checked: false` — the licensed delivery check did not run, so `is_deliverable`, `is_cmra`, `is_vacant` and `is_residential` are all `null`, and none of them is a "no".

If your database column is a boolean, you have already lost this distinction. Make the column nullable, or store the string.

## Existence and validity are different questions

They arrive in different fields, and conflating them is the most common integration mistake.

**Validity** is whether the address stands as written for its own country: are the required lines there, does the postcode match the country's pattern, and — where a national directory is installed — does that postcode exist? A failure here answers `valid: false` with a typed reason such as `missing_locality`, `invalid_postal_code` or `postcode_not_found`, and it is free of charge. Something is wrong with the text, and a person can usually fix it.

**Existence** is whether the building is in the register. An address can be perfectly valid and still answer `exists: false`, which is why that case is a 20-point risk signal on a *valid* address rather than an invalid verdict. Nothing about the writing is wrong; the place just is not in the book.

Keep them in separate branches of your code. "Fix your address" and "we could not confirm this address" are different messages to send someone, and only one of them is their fault.

## What to do with each answer

- **`exists: true`** — the strongest confirmation open data offers. It is still not deliverability: a real building can be vacant, and whether post arrives is a licensed answer that this lookup does not make.
- **`exists: false` with `match_level: street`** — treat as a probable typo. Show the person the street you found and ask for the number again.
- **`exists: false` with `match_level: postcode` or `none`** — worth a human look before shipping anything expensive. Combine it with the rest of the response rather than rejecting on it alone; new-build addresses appear in registers late, and register updates lag the ground.
- **`exists: null`** — carry on as if you had not asked. Use the parts of the answer that did run: the format, the delivery-point kind, the postcode status.
- **Never store a `null` as a `false`,** and never show a customer "this address does not exist" on the strength of a partial register.

## Where the register facts come from

Every answer names its own sources. `register` gives the dataset, `register_coverage` the publisher's own description of it, and the `sources` block lists the version of each dataset installed when the answer was given — so an answer from last month can be checked against the file that produced it rather than against today's. The [free postal address checker](/tools/address-checker) prints the whole block, including the coverage table for the datasets this server currently holds.

## What to do next

- Try the four cases above on the [free postal address checker](/tools/address-checker) and watch `match_level` change while `exists` stays honest.
- Read the [address verification guide](/docs/address-verification) for every field, every reason and every weight.
- See what the postcode half of the answer can and cannot settle in [a UK postcode is not an address](/guides/a-uk-postcode-is-not-an-address).
- Understand how the 20 points fit into the rest in [how Spaw computes the risk score](/guides/how-spaw-computes-the-risk-score).

Reference: https://spaw.co/guides/how-to-read-an-address-existence-answer
