# Global Data Check

`POST /globaldata_check`

- Live: `POST https://gdapi.globaldata.net.au/api/v2/globaldata_check`
- Sandbox: `POST https://sandbox-gdapi.globaldata.net.au/api/v2/globaldata_check`

Validates a person's identity details against the **Global Data Universe** and returns one or more candidate match rows with per-field outcomes.

The endpoint searches by **last_name** and any combination of optional identifiers - `birth_date`, `address`, up to four `phone` numbers, and up to four `email` addresses. Every supplied field is then evaluated against each candidate and reported separately. `last_name` is the only required field.

## Match outcomes

For **first_name** and **middle_name** the response uses a graded ladder. The strongest applicable label is returned:

| Label | Meaning |
|:------|:--------|
| `match` | Exact equality after normalisation (case- and diacritic-insensitive). |
| `alias_match` | The two names share a known nickname / alias group (for example `Bob` / `Robert`, `Jenny` / `Jennifer`, `Tony` / `Antonio`). |
| `partial_match` | One side is exactly a single-letter initial that matches the leading letter of the other side (for example `P` vs `Peter`). Modelled on universe records that only have a first-letter initial captured. Longer-form abbreviations like `Pete` vs `Peter` are handled by `alias_match` instead. |
| `fuzzy_match` | The two names share a phonetic (metaphone) code and the same leading letter. |
| `no_match` | None of the above. |
| `no_record` | (Middle name only.) The caller supplied a middle name but the candidate has no middle name on file. |
| `not_used` | The caller supplied this field but it was dropped because it failed validation and `ignore_errors=true`. |

Fields that the caller did not supply are **omitted from each candidate row entirely**. The `address` rollup key appears whenever any address part was supplied; individual address component keys (`street_address`, `suburb`, `state`, `postcode`) appear only when the caller actually supplied that part. When no address was supplied at all, the rollup and all four component keys are omitted together.

Which match types are accepted is controlled per name field via `first_name_matching`, `middle_name_matching`, and `last_name_matching` (defaults to `["exact"]` for each).

For **dob** the outcomes are `match`, `match_year` (year matches but day/month don't), `match_day_month_reversal` (year matches, day and month swapped), `no_record` (candidate has no DOB on file), `no_match`, or `not_used`.

For **phone** and **email**, each supplied slot is evaluated independently against the candidate's full set of phones / emails. If you supply `phone` and `phone3` (for example), the response carries a separate `phone` outcome and a separate `phone3` outcome, each `match` / `no_match` based on whether that specific value matches any of the candidate's phones on file. Slots that the caller did not supply are omitted from the response. The same per-slot evaluation applies to `email`, `email2`, `email3`, and `email4`.

Australian phone numbers are accepted in either `0NSN` form (10 digits starting with `0`) or the equivalent E.164 form (`+61` followed by 9 digits). The leading `+` on the E.164 form is optional - `61400123456` is accepted as well as `+61400123456`, which avoids spurious rejections of numbers that have round-tripped through Excel / CSV imports that silently strip the `+`. All three shapes are normalised to the `0NSN` form internally before comparison.

## Address matching

When an address is supplied, the response includes both an `address` rollup field and the four individual address component fields (`street_address`, `suburb`, `state`, `postcode`). The rollup is a single-glance summary of how well the supplied address matched the candidate; the component fields tell you exactly which parts agreed.

The rollup is derived from the components as follows:

| `address` rollup | Meaning |
|:-----------------|:--------|
| `match` | Every supplied address component matches the candidate (parts the caller did not supply are not considered). |
| `match_street` | Same street number on the same street name (street-type variations like `ST` vs `RD` are allowed) but at least one of the other supplied parts (suburb / state / postcode) does not match. |
| `match_locality` | The street did not match, but the state matches and at least one of the suburb or postcode also matches. State must be supplied for `match_locality` to fire. |
| `no_match` | None of the above; the supplied address did not align with the candidate at any of the levels above. |

The component fields each return `match` / `no_match` independently and are returned alongside the rollup so you can see which specific parts contributed to it. For example, `address: match_street` plus `street_address: match` and `postcode: no_match` tells you the candidate lives on the same street but in a different postcode area.

When the caller supplies only a subset of address parts (e.g. just `postcode`, or `suburb` + `postcode`), only those parts are evaluated and reported - the unsupplied address keys are omitted from the row entirely. The rollup `match` therefore means "every supplied part matched", not "all four parts matched".

Whichever input form was used (`gnaf_id`, `full_address`, or any combination of address parts), the supplied components are evaluated directly. With `gnaf_id` / `full_address` the address is resolved to canonical components first; with the parts form the supplied values are used as-is.

A given person may have several addresses on file (current and historical). `match_results` always returns **one row per person** - we do not duplicate the same person once per address. When evaluating, we score every address the person has against the supplied address and report the outcome for the **best-matching** one. Ties on rollup outcome are broken by preferring the most recently active address. For example, if a person has both an old `match_locality` address and a current `match` address against your input, you will see `address: match` in the response.

## Best-candidate selection

Candidates are ranked in three steps, applied in order:

1. **Strong-discriminator hits rank first.** A candidate that produces an exact match against any of `phone`, `email`, full `dob`, or the full `address` (the rollup at `match`) outranks any candidate that does not, regardless of how well the other candidate scores on names alone. `dob: match_day_month_reversal` also counts as a strong-discriminator hit, **but only when the candidate also has `first_name` of `match` / `alias_match` AND `last_name` of `match`** - without name corroboration, a reversed DOB is treated as a numeric coincidence and does not gate the candidate into the strong-discriminator group.
2. **Exact last-name wins within the strong-discriminator group.** Among candidates in the same group from step 1, candidates with `last_name: match` rank above candidates with `last_name: fuzzy_match` - a fuzzy last-name candidate never displaces an exact last-name candidate for the top slot.
3. **Weighted score breaks remaining ties.** Per-field weights are summed and the highest sum wins:

| Field | match | partial outcomes |
|:------|------:|:-----------------|
| `first_name` | 20 | `alias_match` 16, `partial_match` 10, `fuzzy_match` 6 |
| `middle_name` | 1 | `alias_match` 1, `partial_match` 1 |
| `last_name` | 12 | `fuzzy_match` 8 |
| `dob` | 10 | `match_day_month_reversal` 7, `match_year` 4 |
| `address` | 8 | `match_street` 5, `match_locality` 3 |
| each `phone` slot (`phone` / `phone2` / `phone3` / `phone4`) | 4 | - |
| each `email` slot (`email` / `email2` / `email3` / `email4`) | 2 | - |

Each candidate row reports the per-field outcomes directly. Callers wanting to drive a routing rule should branch on the specific outcomes that matter for their use case (for example, `last_name: match` plus `dob: match` plus any phone match for high-confidence auto-approval) rather than on a single aggregate score.

## Single vs multiple candidates

`match_results` is always an array, with one row per distinct **person** in the universe (never one row per person-and-address). By default the array contains the single best candidate (length 0 or 1). Set `return_multiple_candidates: true` to receive multiple candidates ordered best-first, with the same row schema.

When `return_multiple_candidates: true` is set, the response is capped at the **top 5 candidates by score**. If your search matches more than 5 records, only the strongest 5 are returned. Narrow your request (add a DOB, a phone, or an address) to lift the strongest candidates above the cap.

Two universe records that produce **identical per-field outcomes** against the request collapse into a single row in `match_results`. The count of rows therefore reflects the number of distinct outcome maps, not the number of underlying universe records considered. Adding more identifiers to the request makes candidates differ in their per-field outcomes and surface as separate rows.

## `ignore_errors`

Useful when the data you are checking is not perfectly clean - for example, when the source system you are pulling from contains the occasional malformed phone number, invalid email, or junk date of birth.

By default, any individual field that fails validation will cause the whole request to be rejected with a `400` error, leaving you to either retry the call with the bad fields omitted or fix the data on your side first.

Setting `ignore_errors: true` removes that round-trip: the endpoint silently drops any individual field whose value fails validation (a malformed `birth_date`, an invalid phone number, an unresolvable address, etc.) and runs the match against whatever valid input remains. The dropped fields are reported back in the response as `not_used` so you can see exactly which inputs were ignored. Only field-level value problems are soft-ignored - the request still has to be structurally well-formed (correct types, `last_name` present).

## `include_deceased`

Records marked as deceased are excluded from the candidate pool by default. Setting `include_deceased: true` adds them back in.

Note that the response does **not** include any indicator of whether a returned candidate was deceased - matched candidates are returned in the same shape regardless. Most use cases (KYC, identity verification, contact validation) should leave this off; only enable it when you have a specific need to match against deceased records and your downstream workflow handles them appropriately.

## Sandbox environment

When simulating queries in the sandbox environment, the following records can be searched for:

| First Name | Middle Name | Last Name | Birth Date | Address | Phone | Email |
|:-----------|:------------|:----------|:-----------|:--------|:------|:------|
| JOHN | ANDREW | SMITH | 1998-03-21 | 20 HARDY ST, LILYDALE 3140 VIC | 0399999999, 0491222111 | jsmith1998@example.com |
| ROBERT | PATRICK | BROWN | 1971-03-18 | 8 WALTHAM ST, RICHMOND 3121 VIC | 0399998888 | |
| MARY | SALLY | JONES | 1989-08-12 | 35 YARALLA ST, CONCORD WEST 2138 NSW | 0299995000, 0491222444 | mary_jones89@example.com |
| MARION |  | FILEWOOD | 1955-09-07 | 375 ARGENT ST, BROKEN HILL 2880 NSW | 0412024869, 0880885999 | m47b7@rev-zone.net |
| AARON | ALBERT | FILEWOOD | 1949-03-11 | 375 ARGENT ST, BROKEN HILL 2880 NSW | 0880885999 | |
| RUTH |  | WOLFE | 2000-05-20 | 375 ARGENT ST, BROKEN HILL 2880 NSW | 0455963579 | |
| MATTHEW |  | SMITH | 1999-10-21 | (no address on file) | (no phone on file) | (no email on file) |
| JOAN |  | EVANS | 1996-07-06 | (no address on file) | (no phone on file) | (no email on file) |
| ROBERT |  | BROWN | (no DOB on file) | 6 WATERVIEW CL, PORT MACQUARIE 2444 NSW | 0491222333 | |
| R |  | BROWN | (no DOB on file) | 22 BRABYN ST, WINDSOR 2756 NSW | (no phone on file) | RP_BROWN71@EXAMPLE.COM |

Useful demonstrations against the sandbox data:

- **alias_match** - search `first_name = "Bob"`, `last_name = "Brown"`, `birth_date = "1971-03-18"` with `first_name_matching = ["exact","alias"]` matches Robert Brown with `first_name: alias_match`.
- **partial_match** - search `first_name = "Robert"`, `last_name = "Brown"` with `first_name_matching = ["exact","partial"]` may match the `R BROWN` record with `first_name: partial_match`.
- **fuzzy_match** - search `first_name = "Mathew"`, `last_name = "Smith"`, `birth_date = "1999-10-21"` with `first_name_matching = ["exact","fuzzy"]` matches Matthew Smith with `first_name: fuzzy_match`.
- **address as identifier** - search `last_name = "Smith"` plus the full address `20 HARDY ST, LILYDALE 3140 VIC` (no other identifier) matches John Smith.
- **last-name-only** - search `last_name = "Evans"` with `return_multiple_candidates = true` returns every Evans in the universe, including Joan Evans.
- **no_record DOB** - search `first_name = "Robert"`, `last_name = "Brown"`, `phone = "0491222333"`, `birth_date = "1985-06-04"` matches the second Robert Brown record by phone, with `dob: no_record` because that record has no DOB on file.

## Request body

The details of the person to validate.

| Field | Type | Description |
|-------|------|-------------|
| `first_name` | string or null | The first name of the individual. Optional - omit, leave blank, or pass `null` if unknown. Example: `John` |
| `middle_name` | string or null | The middle name of the individual. Example: `James` |
| `last_name` | string | **Required.** The last name of the individual. Required. Example: `Doe` |
| `birth_date` | string (date) or null | The date of birth of the individual in `YYYY-MM-DD` format. Example: `1990-01-01` |
| `gnaf_id` | string or null | A GNAF address identifier (e.g. `GAVIC421647320`). Both no-separator (`GAVIC421647320`, `GANSW710277749`) and underscore-separated (`GANT_717247498`, `GASA_414917272`) forms are accepted; the underscore is part of the source identifier and should be preserved rather than stripped. Mutually exclusive with `full_address` and the address-parts fields. Example: `GAVIC421647320` |
| `full_address` | string or null | The address as a single free-text string. Mutually exclusive with `gnaf_id` and the address-parts fields. Example: `4/123 Fake Street, Fakeville VIC 3987` |
| `street_address` | string or null | The street line of the address. Any combination of `street_address` / `suburb` / `state` / `postcode` is accepted - the parts do not all have to be supplied together. `gnaf_id` / `full_address` must not be supplied alongside any address part. The response only evaluates and reports per-field outcomes for the parts the caller actually supplied. Example: `4/123 Fake Street` |
| `suburb` | string or null | The suburb of the address. May be supplied on its own or in combination with any other address parts. Example: `Fakeville` |
| `state` | string or null | The Australian state of the address. May be supplied on its own or in combination with any other address parts. Enum: `NSW`, `VIC`, `QLD`, `SA`, `WA`, `TAS`, `NT`, `ACT` Example: `VIC` |
| `postcode` | string or null | The postcode of the address. May be supplied on its own or in combination with any other address parts. Example: `3987` |
| `phone` | string or null | A phone number for the individual. Accepts either `0NSN` (10 digits starting with `0`) or the equivalent E.164 form (`+61` followed by 9 digits). The leading `+` is optional - `61400123456` is treated the same as `+61400123456`. Example: `0400123456` |
| `phone2` | string or null | An additional phone number. Same format as `phone`. |
| `phone3` | string or null | An additional phone number. Same format as `phone`. |
| `phone4` | string or null | An additional phone number. Same format as `phone`. |
| `email` | string or null | An email address for the individual. Example: `john@example.com` |
| `email2` | string or null | An additional email address. |
| `email3` | string or null | An additional email address. |
| `email4` | string or null | An additional email address. |
| `return_multiple_candidates` | boolean | When `true`, return up to the top 5 candidates ordered best-first. When `false` (the default), return only the single best candidate. Default: `false` Example: `false` |
| `ignore_errors` | boolean | When `true`, supplied fields that fail validation (bad DOB, invalid phone/email, unresolvable address) are dropped from the search and reported as `not_used` in the response, rather than producing a 400. Default: `false` Example: `false` |
| `include_deceased` | boolean | When `true`, deceased records are included in the candidate pool. Defaults to `false`. Default: `false` Example: `false` |
| `first_name_matching` | array of strings | Allow-list of accepted match types for `first_name`. Defaults to `["exact"]`. Add `alias`, `partial`, or `fuzzy` to also accept the corresponding outcome on the response ladder. Enum: `exact`, `alias`, `partial`, `fuzzy` |
| `middle_name_matching` | array of strings | Allow-list of accepted match types for `middle_name`. Defaults to `["exact"]`. Middle name does not filter candidates - a missing or mismatched middle name will still return a candidate; this list only controls which positive outcomes are recognised. Enum: `exact`, `alias`, `partial`, `fuzzy` |
| `last_name_matching` | array of strings | Allow-list of accepted match types for `last_name`. Defaults to `["exact"]`. Adding `fuzzy` widens the SQL candidate search to include records whose last-name metaphone matches and whose last name starts with the same letter. Enum: `exact`, `fuzzy` |

**Sample request**

```json
{
    "first_name": "John",
    "middle_name": "James",
    "last_name": "Doe",
    "birth_date": "1990-01-01",
    "gnaf_id": "GAVIC421647320",
    "full_address": "4/123 Fake Street, Fakeville VIC 3987",
    "street_address": "4/123 Fake Street",
    "suburb": "Fakeville",
    "state": "VIC",
    "postcode": "3987",
    "phone": "0400123456",
    "phone2": "string",
    "phone3": "string",
    "phone4": "string",
    "email": "john@example.com",
    "email2": "string",
    "email3": "string",
    "email4": "string",
    "return_multiple_candidates": false,
    "ignore_errors": false,
    "include_deceased": false,
    "first_name_matching": [
        "exact",
        "alias"
    ],
    "middle_name_matching": [
        "exact"
    ],
    "last_name_matching": [
        "exact"
    ]
}
```

## Responses

### 200 Result of the validation check.

Content type: `application/json`

| Field | Type | Description |
|-------|------|-------------|
| `message` | string | **Required.** A message indicating the result of the request. This will be `Ok` if the request was successful. Example: `Ok` |
| `api_reference` | string (uuid) | **Required.** A unique identifier for this request. This can be used to track the request in the logs. Example: `fe4291ca-d831-4760-96df-c9cb03b3cd95` |
| `match_results` | array of objects | **Required.** Candidate rows returned by the search, **one row per matched person** (never one row per person-and-address). Always an array. When `return_multiple_candidates` is `false` (the default) the array contains zero or one row (the single best candidate); when `true` it contains up to 5 candidates ordered best-first. When the request supplied an address and the candidate has several addresses on file, the address-component outcomes (`address` rollup plus any supplied `street_address` / `suburb` / `state` / `postcode` parts) reflect the **best-matching** address from the candidate's address history, with the most recently active address used to break ties. Each row only includes the fields that were actually evaluated. Fields that the caller did not supply are omitted from the row entirely (they are not returned as `null` or `not_provided`). The `address` rollup appears whenever any address part was supplied; the individual `street_address` / `suburb` / `state` / `postcode` keys appear only when the caller supplied that part. When no address was supplied at all, the rollup and all four component keys are omitted together. |
| `match_results[].first_name` | string | First name match outcome (uses the graded ladder). Omitted when not supplied in the request. Enum: `match`, `alias_match`, `partial_match`, `fuzzy_match`, `no_match`, `not_used` Example: `match` |
| `match_results[].middle_name` | string | Middle name match outcome. `no_record` means a middle name was supplied but the candidate has none on file. Omitted when not supplied in the request. Enum: `match`, `alias_match`, `partial_match`, `fuzzy_match`, `no_record`, `no_match`, `not_used` Example: `match` |
| `match_results[].last_name` | string | Last name match outcome. Enum: `match`, `fuzzy_match`, `no_match`, `not_used` Example: `match` |
| `match_results[].dob` | string | Birth date match outcome. `match_year` and `match_day_month_reversal` are returned for partial date matches; `no_record` means the candidate has no DOB on file. Omitted when not supplied in the request. Enum: `match`, `match_year`, `match_day_month_reversal`, `no_record`, `no_match`, `not_used` Example: `match` |
| `match_results[].address` | string | Roll-up address outcome derived from the four address components. `match_street` requires the same street number on the same street name (street-type variations allowed); `match_locality` requires state to match (if supplied) and at least one of suburb or postcode to match. Omitted when no address was supplied in the request. Enum: `match`, `match_street`, `match_locality`, `no_match`, `not_used` Example: `match` |
| `match_results[].street_address` | string | Street-line component of the address comparison. Omitted when no address was supplied. Enum: `match`, `no_match`, `not_used` Example: `match` |
| `match_results[].suburb` | string | Suburb component of the address comparison. Omitted when no address was supplied. Enum: `match`, `no_match`, `not_used` Example: `match` |
| `match_results[].state` | string | State component of the address comparison. Omitted when no address was supplied. Enum: `match`, `no_match`, `not_used` Example: `match` |
| `match_results[].postcode` | string | Postcode component of the address comparison. Omitted when no address was supplied. Enum: `match`, `no_match`, `not_used` Example: `match` |
| `match_results[].phone` | string | Match outcome for the supplied `phone` value: `match` if any of the candidate's phones on file equals it, otherwise `no_match`. Omitted when `phone` was not supplied in the request. Enum: `match`, `no_match`, `not_used` Example: `match` |
| `match_results[].phone2` | string | Match outcome for the supplied `phone2` value, evaluated independently of the other phone slots. Omitted when `phone2` was not supplied. Enum: `match`, `no_match`, `not_used` Example: `match` |
| `match_results[].phone3` | string | Match outcome for the supplied `phone3` value, evaluated independently of the other phone slots. Omitted when `phone3` was not supplied. Enum: `match`, `no_match`, `not_used` Example: `match` |
| `match_results[].phone4` | string | Match outcome for the supplied `phone4` value, evaluated independently of the other phone slots. Omitted when `phone4` was not supplied. Enum: `match`, `no_match`, `not_used` Example: `match` |
| `match_results[].email` | string | Match outcome for the supplied `email` value: `match` if any of the candidate's emails on file equals it (case-insensitive), otherwise `no_match`. Omitted when `email` was not supplied in the request. Enum: `match`, `no_match`, `not_used` Example: `no_match` |
| `match_results[].email2` | string | Match outcome for the supplied `email2` value, evaluated independently of the other email slots. Omitted when `email2` was not supplied. Enum: `match`, `no_match`, `not_used` Example: `match` |
| `match_results[].email3` | string | Match outcome for the supplied `email3` value, evaluated independently of the other email slots. Omitted when `email3` was not supplied. Enum: `match`, `no_match`, `not_used` Example: `match` |
| `match_results[].email4` | string | Match outcome for the supplied `email4` value, evaluated independently of the other email slots. Omitted when `email4` was not supplied. Enum: `match`, `no_match`, `not_used` Example: `match` |

**Sample response**

```json
{
    "message": "Ok",
    "api_reference": "fe4291ca-d831-4760-96df-c9cb03b3cd95",
    "match_results": [
        {
            "first_name": "match",
            "middle_name": "match",
            "last_name": "match",
            "dob": "match",
            "address": "match",
            "street_address": "match",
            "suburb": "match",
            "state": "match",
            "postcode": "match",
            "phone": "match",
            "phone2": "match",
            "phone3": "match",
            "phone4": "match",
            "email": "no_match",
            "email2": "match",
            "email3": "match",
            "email4": "match"
        }
    ]
}
```

### 500 Unexpected error.

Content type: `application/json`

| Field | Type | Description |
|-------|------|-------------|
| `message` | string | A message indicating the error. Example: `An error occurred while processing your request.` |

**Sample response**

```json
{
    "message": "An error occurred while processing your request."
}
```

Standard error responses: 400, 402, 403 (see [Common error responses](/docs/reference/general/common-error-responses.md))

