# Interpreting Results

Use this guide to interpret Verify results and decide when to accept a record, ask for a correction, or handle a failed request.

A `200` response means the request was processed. Address validation reports a `nextAction`. Email and phone validation report `valid` alongside individual checks. These results do not establish that a person owns the address, mailbox, or phone number.

## Address validation

### Address decisions

Validation bases `nextAction` on the first candidate's match quality:

| `nextAction` | Meaning | Suggested handling |
| --- | --- | --- |
| `ACCEPT` | The first candidate has Exact match quality | Accept the address and retain its ID |
| `ACCEPT_WITH_CHANGES` | The first candidate has Confident match quality | Show the returned address and ask the user to confirm changes |
| `DENY` | No candidate was found, or its quality was neither Exact nor Confident | Ask for a correction or send the record for review |

A denied result can still contain `id` and `formatted` from a lower-quality candidate. Their presence does not override `DENY`. These fields are omitted when no candidate provides them.

These response excerpts show the three decisions. They are illustrative, rather than a promise of the result for a particular query:

```json
{"nextAction":"ACCEPT","id":"GANSW705988020","formatted":"1 MARTIN PL, SYDNEY NSW 2000"}
```

```json
{"nextAction":"ACCEPT_WITH_CHANGES","id":"GANSW705988020","formatted":"1 MARTIN PL, SYDNEY NSW 2000"}
```

```json
{"nextAction":"DENY","id":"GANSW705988020","formatted":"1 MARTIN PL, SYDNEY NSW 2000"}
```

If no candidate is found, the excerpt is simply `{"nextAction":"DENY"}`.

## Mailpoint validation

Mailpoint matches against the Australia Post Postal Address File (PAF). It returns a Delivery Point Identifier (DPID) and postal attributes when a match is available.

| Field | How to use it |
| --- | --- |
| `properties.dpid` | Keep the DPID as a string. `00000000` is the no-match sentinel |
| `properties.formatted` | Review the matched postal address |
| `properties.barcode` | A 4-State barcode encoded as bar-state digits `0`–`3`, rather than an image |
| `matchScore` | Postal match score from 0 to 100. It is not a probability. `0` means no match |
| `matchType` | Returned postal match level, when available. A street or locality match does not confirm a specific delivery address |
| `pafVersion` and `pafExpiry` | PAF release and expiry date |
| `geometry` | Physical location, when available. A postal-only match can have no geometry |

A no-match response includes `matchScore: 0` and `properties.dpid: "00000000"`. It omits the barcode and formatted address. Do not treat the sentinel DPID as a successful match.

Mailpoint accepts a single `query` containing the postal address to validate.

A returned DPID alone does not establish eligibility for postal discounts. See the [Australia Post Data Guide](https://auspost.com.au/content/dam/auspost_corp/media/documents/australia-post-data-guide.pdf) for mailing requirements.

## Phone validation

Parsing either fails, leaving `meta.checks_performed: ["parse"]`, or succeeds and is followed by `validate`, `format`, and `location`.

### Parsing and input formats

Use an explicit country code for international numbers. Numbers without a country code are interpreted as Australian numbers.

Spaces, brackets, dashes, and dots between digits are accepted. The parser also recognises a national trunk prefix, a `+` country code, and an international dialling prefix such as Australia's `0011`.

The following masked examples illustrate input formats and the corresponding `format.e164: "+12025xxxxxx"`. The `x` characters hide digits and must be replaced before testing:

```text
+1 202 5xx xxxx
+1 (202) 5xx-xxxx
0011 1 202 5xx xxxx
```

`input.phone` echoes the supplied value. The request accepts 1–40 characters. An empty, missing, or over-40-character field returns `400`.

A non-empty value such as `abc` returns `200` with `valid: false`, an empty `format`, and only the `parse` check. The `number_details` object remains present with `type: "unknown"`, false `possible` and `valid` values, and `timezones: []`.

### Possible and valid numbers

| `number_details.possible` | `valid` | Meaning |
| --- | --- | --- |
| `true` | `true` | The number has a plausible length and matches a valid numbering range |
| `true` | `false` | The length is plausible, but the number does not match a valid range |
| `false` | `false` | The length is not plausible for that country's numbering plan |

A number can parse and still be invalid. The reference illustrates this with a masked Australian number, `1800 xxx xxxx`. Its formats are returned because the underlying number parsed successfully.

`valid: true` does not confirm that the number is connected, reachable, or owned by the user. `reachable` currently always returns `not_checked`.

### Formats

| Field | Use |
| --- | --- |
| `format.e164` | Canonical form for storage and comparison, such as `+12025xxxxxx` |
| `format.international` | Readable international form, such as `+1 202-5xx-xxxx` |
| `format.national` | Readable national form, such as `(202) 5xx-xxxx` |
| `format.rfc3966` | A `tel:` URI for links, such as `tel:+1-202-5xx-xxxx` |

Formats are returned whenever parsing succeeds, including for invalid numbers. Missing values are omitted rather than returned as `null`.

### Number details

- `country_code`, `region_code`, and `country_name` identify the number's country or region when available
- `location` describes the geographic area associated with the number's prefix. It is not the phone's live location
- Australian mobile and non-geographic numbers can omit `location`. Check that the field exists before using it
- `timezones` contains IANA timezone names associated with the numbering range. It can contain several zones or be empty

| `number_details.type` | Meaning |
| --- | --- |
| `fixed_line` | Landline |
| `mobile` | Mobile number |
| `fixed_line_or_mobile` | A range that can contain either fixed lines or mobiles, common in the US |
| `toll_free` | Toll-free number |
| `premium_rate` | Premium-rate number |
| `shared_cost` | Shared-cost number |
| `voip` | Voice over IP number |
| `personal_number` | Personal numbering service |
| `pager` | Pager number |
| `uan` | Universal access number |
| `voicemail` | Voicemail service |
| `unknown` | Type could not be determined, including unparsed input |

## Email validation

`meta.checks_performed` contains `syntax`, followed by `dns` only when syntax passes. `valid` is true only when `syntax.valid` and `domain.has_mx` are both true. Mailbox and domain categories do not change that verdict.

### Syntax and normalisation

Example mailbox names are masked with `xxx`. The API trims surrounding whitespace and lowercases the domain. It preserves the local part, which can be case-sensitive under [RFC 5321](https://www.rfc-editor.org/rfc/rfc5321). `input.email` echoes the supplied value and `syntax.normalized` shows the value checked.

For example, `"  Xxx@EXAMPLE.COM  "` becomes `"Xxx@example.com"`.

The request accepts 1–320 characters. A non-empty value can fit that request limit and still return `valid: false` because it fails syntax checks:

- The normalised address must be at most 254 characters, with a local part of at most 64 characters
- Both sides of `@` must be present. The domain must contain a dot and a supported alphabetic suffix
- The local part must not begin or end with a dot, contain consecutive dots, or contain unsupported characters
- Domain labels must not be empty or begin or end with a hyphen
- Internal whitespace, quoted local parts, address literals, and non-ASCII mailbox characters are not accepted by this syntax check

An empty, missing, or over-320-character `email` is a `400` request error. A non-empty malformed address within the request limit returns `200` with `syntax.valid: false`. No DNS lookup runs and the `domain` object is omitted. `mailbox.group` is still returned.

### Domain and mailbox categories

| Field | Meaning |
| --- | --- |
| `mailbox.group` | The local part matches a recognised role address, such as `sales` or `info`. Matching ignores case |
| `domain.consumer_email_provider` | The domain is a known consumer email provider |
| `domain.disposable` | The domain is known to provide disposable email |

Choose your own handling for these categories. A disposable or role address can still have `valid: true`. A false category flag does not prove that an address belongs to an individual or a particular organisation.

### DNS and mail servers

| `domain.exists` | `domain.has_mx` | Meaning |
| --- | --- | --- |
| `true` | `true` | At least one usable mail exchanger was found |
| `true` | `false` | The domain publishes no usable MX record, including a null MX |
| `false` | `false` | The domain was not found in DNS |

`domain.mx_records` lists mail exchangers by ascending `priority`. A lower value is preferred. An empty list accompanies `has_mx: false`.

A null MX, defined by [RFC 7505](https://www.rfc-editor.org/rfc/rfc7505), is an `MX` record with priority `0` and target `.`. It explicitly states that the domain accepts no email. `example.com` publishes one, so the Quickstart example returns `valid: false` even though its syntax is valid.

A DNS timeout or lookup failure returns `500`. Handle this as a request failure rather than concluding that the domain has no mail server.

The API does not contact a mailbox to confirm it exists or accepts mail. `valid: true` confirms syntax and usable MX records only.

## Other address operations

### Suggestions and locations

- Autocomplete returns `results` containing `id`, `formatted`, `type`, and a rank starting at `1`. Use the chosen ID to retrieve address details
- Geocoding and reverse geocoding return a `FeatureCollection`. Each feature has point geometry, an optional address ID, and `properties.formatted` when available
- Reverse geocoding can include `matchDistance`, in metres from the supplied point to the returned address point. A nearby result is not proof that the user intended that address
- An empty `results` or `features` array indicates no match. Ask for a more complete address or check the supplied coordinates

Geometry uses GDA94 (EPSG:4283). Point coordinates use `[longitude, latitude]` order. These operations do not expose a request CRS selector.

### Address details

Use address info with an ID returned by validation, geocoding, or autocomplete. It returns a single `Feature` with address `properties`. The address label is named `formatted`.

- Check for geometry before using it. Some records have no physical location
- An unknown ID returns `200` with empty `properties`
- An invalid ID format returns `400`. Correct the request rather than treating it as an unknown address

## Request metadata and failures

Email and phone responses include `meta.checks_performed`, `meta.billable_units`, `meta.request_id`, and `meta.processing_ms`. Use the check list to see which stages ran. Quote the request ID when contacting support. Processing time is measured in milliseconds and varies by request.

Successful Verify responses include `input`, `attribution`, `requestTimeStamp`, and `requestDateTime`. `requestTimeStamp` uses Unix seconds and `requestDateTime` uses UTC. Error responses use the structure below.

### Verify errors

Verify service errors use a structured `errors` array:

| Field | Meaning |
| --- | --- |
| `error_count` | Number of entries in `errors` |
| `errors` | Objects containing a `type`, `description`, and an optional `field` |
| `input` | Submitted body, including invalid values or rejected fields. Malformed JSON can be echoed as a raw string |
| `attribution` | Data attribution notice |
| `timestamp` | Unix timestamp in seconds. Success responses use `requestTimeStamp` instead |
| `requestDateTime` | UTC date and time of the error |

For example, address validation with an empty body returns `400`:

```json
{
  "error_count": 1,
  "errors": [
    {
      "type": "validation",
      "description": "Field required",
      "field": "query"
    }
  ],
  "input": {},
  "attribution": "NOTICE All rights reserved. Use of this data is subject to the Geoscape Hub Terms and Conditions (https://geoscape.com.au/legal/geoscape-developer-terms/)",
  "timestamp": 1792540800.0,
  "requestDateTime": "2026-10-21T00:00:00+00:00"
}
```

Use `errors[].type` and `errors[].field` for application handling. The description can vary. `field` is omitted when no request field can be identified, such as a JSON syntax error. Nested paths use dot notation, for example `items.2.query`.

| Error type | Meaning | Handling |
| --- | --- | --- |
| `validation` | A request field or JSON body failed validation | Correct the identified field or JSON syntax |
| `authentication` | Authentication failed | Check the Consumer Key and application access |
| `authorization` | The request is not permitted | Check product access and the [operation's plan requirements](/apis/verify#access) |
| `not_found` | A route or requested resource was not found | Check the path and identifier |
| `rate_limit` | A request-rate limit was reached | Retry with bounded backoff |
| `request` | Another request error, such as an unsupported query parameter or HTTP method | Check the status and description and correct the request |
| `server` | Service or lookup failure | Retry transient failures with backoff and contact support if they persist |

Local request validation returns `400`. Service failures return `500` with `errors[].type: "server"` and `description: "API request failed, please contact support"`.

Read the HTTP status first. A processed no-match or invalid result is `200` and follows the validation result schema, rather than the error schema. Check the result fields to determine whether a match was found. Keep contact details out of error logs because `input` can echo them.

Gateway authentication or rate-limit failures may return a different error body. Handle their HTTP status even when the body differs. See [Error Handling](/guides/errors) and [Rate Limiting](/guides/rate-limiting).

## Next steps

- [Make your first Verify request](/guides/verify/quickstart)
- [Choose a Verify operation](/apis/verify)
- [Review error handling](/guides/errors)
