# Sandbox

WatchEye provides separate **sandbox** accounts for testing integrations without consuming live credit or touching live screening data. Sandbox is the recommended environment for all development work and continuous-integration runs.

## What's different

- **Separate account.** Sandbox is a distinct account with its own UUID and its own API keys. The environment (`live` or `sandbox`) is fixed at the account level - you cannot switch an existing key between environments with a query parameter, header or environment variable.
- **No billing.** Calls made with a key on a sandbox account are not charged.
- **Test data only.** Screening operations return canned or test-provider data, not real PEP, sanction or business records. The response shape is identical to live so that your integration code does not need to branch on environment - only the data behind it changes.
- **Same endpoints, same URL.** Sandbox and live share `https://portal.watcheye.com.au/api/v1`. Which environment you are operating in is determined entirely by the account behind the API key you authenticate with.

## How to tell which environment you are pointed at

`GET /v1/account` returns an `environment` field of either `live` or `sandbox`. This is the authoritative answer.

## Getting a sandbox account

Sandbox accounts are provisioned by your Global Data account manager. Once your sandbox account exists, API keys on it are created and managed in the [API Keys (login required)](/documentation/account/api-keys) section of the sandbox portal in exactly the same way as keys on a live account.

## Recommended workflow

1. Build and exercise your integration against a key on your sandbox account. Every endpoint, every response shape, every error envelope, idempotency and rate-limit behaviour mirrors live.
2. Run your happy-path and failure-path test suites against sandbox - as often as you like, with no billing impact.
3. Switch to a key on your live account for production. The only change in your code should be the credentials.

## Sample sandbox test data

In sandbox mode the underlying data providers (DVS, ASIC, Companies House, etc.) are replaced with simulators that return deterministic results from a fixed set of test inputs. You can use any entity details you like to exercise the request and response plumbing, but to drive a particular outcome - a match, an explicit not-matched, a system error - you need to use one of the values listed below.

All of these values only produce results on keys belonging to a sandbox account. The same inputs sent to a live key reach the real upstream providers and return real (or no) data.

### Screening check inputs

Sample data for screening checks is matched against the **entity** record (or, for adhoc checks, against the input payload). To exercise a particular outcome, create an entity with the matching details and then launch the relevant screening check against it.

#### pep_sanction_check

Names that produce a match in the sandbox PEP / sanction dataset:

| Name | Birth date | Result |
|-|-|-|
| Ed Virgil Leuschke | 1993-03-23 | Sanctioned (AU DFAT) |
| Alford McGlynn | 1994-03-13 | Sanctioned (AU DFAT) |
| Justus Tanner Beatty | 1950-06-04 | PEP (QLD politician) |
| Julien Kovacek | 2002-08-14 | PEP (NSW senator) |

Business / organisation matches:

| Name | Sanction source |
|-|-|
| Southern Cross Commodities Pty Ltd | AU DFAT + US Trade CSL |
| Baltic Petrochem Logistics OU | EU + UK HMT |
| Jade Meridian Holdings Pte Ltd | US OFAC SDN + US Trade CSL |
| Andes Orbital Freight SAC | UK HMT |
| Sahel Mineral Ventures SARL | UN SC + AU DFAT |

Any other name returns an empty result set.

#### banned_disqualified_persons

The banned and disqualified persons check covers two registers: the ASIC banned and disqualified persons registers (the six `banned_type` values shown below) and the ATO disqualified SMSF trustees register (`ato_disqualified_trustee`). Each of the eight sandbox names below has one record on the ASIC side and one record on the ATO side, so an unfiltered call typically returns two matches per name. Set `config.banned_disqualified_persons.banned_types` to one or more `banned_type` values (including `ato_disqualified_trustee`) to scope the search to specific registers.

| Name | ASIC `banned_type` | Address |
|-|-|-|
| John Michael Smith | `afs_banned_disqualified` | Shepparton VIC |
| John Robert Smith | `banned_futures` | Sydney NSW |
| Jane Penny Sally Roberts | `banned_securities` | Camberwell VIC |
| Jane Roberts | `banned_securities` | Camberwell VIC |
| J S Roberts | `credit_banned_disqualified` | Melbourne VIC |
| P Zao | `disqualified_director` | Woolongong NSW |
| Simone N Zao | `disqualified_smsf` | (no address) |
| Adam Darren Halliday | `disqualified_director` | Illawong NSW |

All three `search_type` values (`narrow_search`, `medium_search`, `broad_search`) are supported by the sandbox dataset. Any other name returns an empty result set.

#### business_check

The Australian business check is driven by the entity's ABN or ACN. The following sample businesses produce results in sandbox:

| ABN | ACN | Name | Status | Notes |
|-|-|-|-|-|
| 32111111114 | 111111114 | Tech Innovators Ltd | Registered | Immediate result |
| 11123456780 | 123456780 | Green Energy Solutions | Deregistered | Historical extract |
| 54222222228 | 222222228 | Urban Development Corp | Registered | Relational extract |
| 33234567894 | 234567894 | Creative Media Agency | Registered | Delayed ~5s, exercises async polling |
| 94782610486 | 782610486 | Copper Finch Construction Pty Ltd | Registered | Risk: court case + insolvency notice |
| 84655375652 | 655375652 | Marble Kookaburra Interiors Pty Ltd | Registered | Risk: court case + adjudication (delayed) |

Any other ABN / ACN returns an empty extract.

#### uk_business_check

Driven by the entity's UK company number:

| Company number | Name | Status | Notes |
|-|-|-|-|
| 12345678 | TEST COMPANY LTD | active | Immediate |
| 87654321 | SAMPLE HOLDINGS PLC | active | Immediate |
| 11223344 | DORMANT SERVICES LTD | dormant | Immediate |
| 55667788 | DELAYED REPORT LTD | active | ~2s delay, exercises async polling |
| 99887766 | DISSOLVED EXAMPLE LTD | dissolved | Immediate |
| SC654321 | SCOTTISH ENTERPRISE SC | active | Scottish prefix |

Any other company number returns "company not found".

#### court_check

Sandbox only returns matches for one person and one company:

| Search input | Result |
|-|-|
| first name `Michael`, last name `Raymond` (optionally state `VIC`) | 2 civil + 1 criminal listing in VIC |
| business name `Samplemart` (optionally state `VIC`) | 1 civil + 1 criminal company listing in VIC |

Any other name returns zero records.

#### realestate_check

Driven by the entity's address. The sandbox real-estate dataset is keyed by G-NAF ID; matching addresses must resolve to one of the IDs below.

| G-NAF ID | Address | Listings |
|-|-|-|
| GAVIC421647320 | 20 Hardy St, Lilydale VIC 3140 | 3 records (sale 2018, rent 2016, sale 2012) |
| GANSW716615055 | 35 Yaralla St, Concord West NSW 2138 | 2 records (sale 2019, rent 2015) |
| GANSW704115400 | 17 Napier St, Binnaway NSW 2395 | 3 records (sales 2010, 2008, 2005) |
| GANSW704224437 | 375 Argent St, Broken Hill NSW 2880 | 2 records (sale 2018, rent 2016) |

For a negative case, use G-NAF ID `GAVIC419608268` - the address resolves but has zero listings, which exercises the "address found, no listings" branch.

#### adc_check

The ADC (Australian deaths) check returns matches for these names. Lookups use first name + middle name + last name + birth date.

| First | Middle | Last | Birth date | Result |
|-|-|-|-|-|
| John | (none) | Smith | 1998-03-21 | 1 match - NSW, died 2023-07-24 |
| John | (none) | Doe | 1971-01-23 | 2 matches - NSW (died 2003-08-22) and WA (died 2011-11-03) |
| John | Andrew | Doe | 1971-01-23 | 1 exact match - WA, died 2011-11-03 |
| Mary | (none) | Smith | 1965-02-17 | 1 match - NSW, date-of-death range late 2018 / early 2019 |

Any other input returns no matches.

#### adc_custodian_check

The custodian variant of the ADC check returns a simple deceased / not-deceased flag. Same backend data as `adc_check`, so the names above also match here. The search type adjusts based on what you supply: birth date + multi-word first name forces an exact-name match; birth date + single-word first name allows a partial-name match (useful for matching records that include a middle name); death date only matches name + date of death.

| First | Last | Birth date | Death date | Result |
|-|-|-|-|-|
| John | Smith | 1998-03-21 | (omitted) | Deceased |
| John | Smith | 1998-03-21 | 2023-07-24 | Deceased (date of death matches) |
| John | Smith | 1998-03-21 | 1999-01-01 | Not deceased (date of death does not match) |
| John | Doe | 1971-01-23 | (omitted) | Deceased |
| John Andrew | Doe | 1971-01-23 | 2011-11-03 | Deceased (exact name + date of death match) |
| Mary | Smith | 1965-02-17 | (omitted) | Deceased |

Any other name returns "not deceased".

#### adverse_media

Adverse media requires the entity's country to match the seeded record:

People:

| First | Middle | Last | Birth date | Country |
|-|-|-|-|-|
| John | James | Doe | 1990-01-01 | AU |
| Jane | Karen | Smith | 1995-02-18 | AU |
| Liam | Raphael | O'Connor | 1980-02-01 | AU |
| Olivia | Rose | Smith | 1973-06-06 | GB |

Businesses:

| Name | Country |
|-|-|
| Acme Systems | AU |
| Sample Software Services | NZ |

Any other input returns `has_adverse_media: false`.

#### email_check

The email-check sandbox is driven entirely by the email suffix - the local part can be anything:

| Email suffix | Result |
|-|-|
| `.asn.au` | Simulated upstream failure (no result) |
| `.com.au` | Deliverable (after a ~20s simulated delay) |
| `.org.au` | Undeliverable - mailbox not found (after ~20s) |
| `.net.au` | Undetermined - greylisted (after ~20s) |
| `.edu.au` | Spamtrap (after ~20s) |
| `.org` | Undeliverable - mailbox not found |
| `.net` | Undetermined - greylisted |
| `.edu` | Spamtrap |
| anything else | Deliverable |

Example: `test@example.org` returns Undeliverable; `slow@example.com.au` returns Deliverable after a ~20 second delay (useful for exercising your timeout handling).

#### phone_check

The phone-check sandbox uses a small seeded dataset. Phone numbers must be Australian and can be submitted in E.164 (`+61...`) or local (`0...`) form. Sample numbers that return data:

| Phone number | Notes |
|-|-|
| `0427519643` | Person 1 - Mr John Andrew Smith |
| `0436991031` | Person 2 - Mr Robert Patrick Brown |
| `0755687356` | Person 3 - Ms Mary Sally Jones |

These same people are also useful for global-data ID checks and other lookups backed by the same sandbox dataset - see the [globaldata](/docs/guides/watcheye_api/sandbox#globaldata) section below.

### ID check inputs

ID checks against DVS providers all follow the same convention: number ranges drive the broad result, individual magic numbers drive specific not-matched reasons, and out-of-range numbers return a random result on each request.

#### DVS document number ranges

For every DVS document type listed below, the document / card / certificate number is checked against a numeric range first:

| Number range | Outcome |
|-|-|
| `1...` (starts with 1) | MATCH |
| `2...` (starts with 2) | INVALID, with a random error reason |
| `3...` (starts with 3) | NOT_MATCHED, with a random error reason |

The per-document tables below list the specific ranges (for example `10000000`-`19999999` for driver licences) and the magic numbers within them that produce deterministic not-matched reasons.

> **Important:** if you submit a document number that falls outside any documented range and does not match a magic number, the sandbox returns a **random** result on each request. To get a deterministic failure use one of the specific magic numbers in the tables below; to get a deterministic match use any number in the `1...` range.

#### Last-name overrides

The following surname prefixes override the number-based outcome for any DVS check. They are matched case-insensitively against the surname field for the document type (`last_name`, `full_name`, or - for marriage certificates - either `last_name1` or `last_name2`).

| Last-name prefix | Outcome |
|-|-|
| starts with `error...` | Simulated upstream system error |
| starts with `locked...` | "Document Temporarily Locked" |

The prefix overrides take precedence over the document-number ranges, so `last_name = Errorsmith` returns a system error regardless of which document number you send.

#### drivers_licence

The `state` must be `VIC` for the sandbox to engage. Use the licence number as both `licence_number` and `card_number`.

| Card number | Outcome |
|-|-|
| `10000000` - `19999999` | MATCH |
| `20000000` - `29999999` | INVALID (random reason) |
| `30000000` - `39999999` | NOT_MATCHED (random reason) |
| `77777770` | MATCH but "card number has not been checked" |
| `88888880` | NOT_MATCHED - given name does not match |
| `88888881` | NOT_MATCHED - middle name does not match |
| `88888882` | NOT_MATCHED - surname does not match |
| `88888883` | NOT_MATCHED - date of birth does not match |
| `88888884` | NOT_MATCHED - licence number does not match |
| `88888885` | NOT_MATCHED - card number not matched |
| `99999990` | INVALID - document invalid |

#### passport

| Passport number | Outcome |
|-|-|
| `M1000000` - `M1999999` | MATCH |
| `M2000000` - `M2999999` | INVALID (random reason) |
| `M3000000` - `M3999999` | NOT_MATCHED (random reason) |
| `M9999990` | INVALID - document invalid |
| `M9999991` | INVALID - document number does not match |
| `M9999992` | NOT_MATCHED - gender does not match |
| `M9999993` | NOT_MATCHED - date of birth does not match |
| `M9999994` | NOT_MATCHED - family name does not match |
| `M9999995` | NOT_MATCHED - given name(s) does not match |

#### visa

The `passport_number` is the foreign passport number.

| Passport number | Outcome |
|-|-|
| `M1000000` - `M1999999` | MATCH |
| `M2000000` - `M2999999` | INVALID (random reason) |
| `M3000000` - `M3999999` | NOT_MATCHED (random reason) |
| `M9999990` | NOT_MATCHED - travel document could not be found |
| `M9999991` | NOT_MATCHED - date of birth does not match |
| `M9999992` | NOT_MATCHED - family name does not match |
| `M9999993` | NOT_MATCHED - given and family name do not match |

#### medicare

| Medicare number | Outcome |
|-|-|
| `2000000020` - `2999999939` | MATCH |
| `3000000030` - `3999999949` | INVALID (random reason) |
| `4000000040` - `4999999959` | NOT_MATCHED (random reason) |
| `6000000060` | NOT_MATCHED - name does not match |
| `6000000061` | NOT_MATCHED - date of birth does not match |
| `6000000062` | NOT_MATCHED - IRN / card number does not match |
| `6000000063` | NOT_MATCHED - expiry date does not match |
| `6000000064` | NOT_MATCHED - Medicare card number does not match |

#### asic_msic

| Card number | Outcome |
|-|-|
| `IC1000000` - `IC1999999` | MATCH |
| `IC2000000` - `IC2999999` | INVALID (random reason) |
| `IC3000000` - `IC3999999` | NOT_MATCHED (random reason) |
| `IC9999990` | INVALID - document invalid |
| `IC8888880` | NOT_MATCHED - name on card does not match |
| `IC8888881` | NOT_MATCHED - date of birth does not match |
| `IC8888882` | NOT_MATCHED - card number does not match |
| `IC8888883` | NOT_MATCHED - expiry date does not match |

#### citizenship_certificate and registration_by_descent

Both use the same `stock_number` ranges.

| Stock number | Outcome |
|-|-|
| `10000000000` - `19999999999` | MATCH |
| `20000000000` - `29999999999` | INVALID (random reason) |
| `30000000000` - `39999999999` | NOT_MATCHED (random reason) |
| `99999999990` | NOT_MATCHED - name or date of birth does not match |
| `99999999991` | NOT_MATCHED - document not found |

#### immicard

| ImmiCard number | Outcome |
|-|-|
| `ABC100000` - `ABC199999` | MATCH |
| `ABC200000` - `ABC299999` | INVALID (random reason) |
| `ABC300000` - `ABC399999` | NOT_MATCHED (random reason) |
| `ABC888880` | NOT_MATCHED - travel document could not be found |
| `ABC888881` | NOT_MATCHED - date of birth does not match |
| `ABC888882` | NOT_MATCHED - family name does not match |

#### centrelink

CRN matching uses the leading digit for the range and the trailing letter for magic-number outcomes.

| CRN | Outcome |
|-|-|
| `100000000A` - `199999999Z` | MATCH |
| `200000000A` - `299999999Z` | INVALID (random reason) |
| `300000000A` - `399999999Z` | NOT_MATCHED (random reason) |
| `999999999A` | NOT_MATCHED - name does not match |
| `999999999B` | NOT_MATCHED - date of birth does not match |
| `999999999C` | NOT_MATCHED - CRN is invalid |
| `999999999D` | NOT_MATCHED - expiry date does not match |
| `999999999E` | NOT_MATCHED - card type does not match |
| `999999999F` | NOT_MATCHED - input card type not matched |
| `999999999G` | NOT_MATCHED - input name mismatch |

#### aec

The AEC sandbox is driven by the leading house number of `street_address` and by `suburb` instead of a document number; the rest of the address can be anything.

| Input | Outcome |
|-|-|
| `street_address` numeric prefix 101 - 200 | MATCH |
| `street_address` numeric prefix 201 - 300 | INVALID (random reason) |
| `street_address` numeric prefix 301 - 400 | NOT_MATCHED (random reason) |
| `suburb` = `Sampleville` | NOT_MATCHED - address not known or invalid |
| `suburb` = `Testville` | NOT_MATCHED - name and/or date of birth not found at address |

#### birth_certificate, marriage_certificate, death_certificate, name_change_certificate

The four BDM (Births, Deaths and Marriages) certificate checks share a common scheme but the certificate-number ranges depend on the issuing `state` and on which certificate it is.

Range plan by state:

| State | Certificate number length | MATCH range | INVALID range | NOT_MATCHED range |
|-|-|-|-|-|
| ACT, NSW, NT, SA, VIC | 7 digits | `1000000` - `1999999` | `2000000` - `2999999` | `3000000` - `3999999` |
| QLD | 10 digits | `1000000000` - `1999999999` | `2000000000` - `2999999999` | `3000000000` - `3999999999` |
| TAS, WA | 11 digits | `10000000000` - `19999999999` | `20000000000` - `29999999999` | `30000000000` - `39999999999` |

Deterministic NOT_MATCHED magic numbers (return a fixed reason per state):

- **Birth, marriage and name-change certificates:**
  - ACT, NSW, NT, SA, VIC: `9999990` - `9999994` (7 digits)
  - QLD: `9999999990` - `9999999994` (10 digits)
  - TAS, WA: `99999999990` - `99999999995` (11 digits)
- **Death certificates:**
  - ACT, NSW, NT, SA: `9999990` - `9999994` (7 digits)
  - **VIC: `99999990` - `99999993` (8 digits)** - intentional outlier, follows the live VIC death-certificate format
  - QLD: `9999999990` - `9999999994` (10 digits)
  - TAS: `99999999990` - `99999999991` (11 digits)
  - WA: `99999999990` - `99999999995` (11 digits)

For VIC death certificates specifically: `99999990` = document not found; `99999991` = certificate number does not match; `99999992` = registration number does not match; `99999993` = given name does not match.

For marriage certificates the document records both parties but the request still carries a single `certificate_number`; the magic numbers apply to that one field regardless of which spouse's name is involved.

#### asic_id_check

The non-DVS ASIC ID check returns matches for these people:

| Name | Birth date | State / suburb |
|-|-|-|
| John Michael Doe | 1980-05-15 | NSW / Sydney |
| Jane Alice Smith | 1987-03-22 | QLD / Brisbane |
| Lucas Benjamin Carter | 1992-08-09 | WA / Perth (delayed, exercises async polling) |
| Maria Scott | 1971-11-02 | VIC / Melbourne |
| Patrick O'Connor | 1965-07-19 | QLD / Brisbane |
| Mary-Jane Parker | 1983-02-28 | SA / Adelaide |

Any other name returns no match.

#### globaldata

The Global Data identity check searches the same seeded sandbox dataset as the phone check, so any of the seeded people work as inputs. The sandbox outcome is keyed on `last_name`; supply the other fields the check requires (see [ID Checks](/docs/guides/watcheye_api/id-checks#globaldata)).

| First | Middle | Last | Birth date | Result |
|-|-|-|-|-|
| John | Andrew | Smith | 1998-03-21 | High-confidence match (person 1) |
| Robert | Patrick | Brown | 1971-03-18 | Match (duplicates exist, useful for fuzzy-ranking tests) |
| Mary | Sally | Jones | 1989-08-12 | Match |
| Frederick | Brian | Oag | 1983-10-12 | Match (rare-surname test) |
| Pauline | Sandra | Payne | 1969-09-06 | Single match |
| Matthew | (none) | Smith | 1999-10-21 | Match |
| John | (none) | James | 1962-06-11 | Match |

`last_name` of `Notarealsurname` (or any other unseeded surname) returns an empty match set.

#### nz_drivers_licence

The NZ Drivers Licence check verifies against a simulated NZTA database. Licence numbers must pass the check-digit validation regardless of the scenario being exercised.

| Scenario | Inputs | Result |
|-|-|-|
| Verified match | Dana Mitchell, born 1965-09-13, licence `DB512036` version `001` | Pass - `match_status` `Match`, `document_verified` `true` |
| No match | Any other valid inputs | Fail - `match_status` `NoMatch` |
| No match with explanation | Licence `DB111112` (any name) | Fail - `NoMatch` with `additional_information` of `driversLicenceVersion does not match driversLicenceNo` |
| Source outage | Licence `DB000000` (any name) | Fail - `NoMatch`, document not verified |
| Validation error | Licence version `999` | `400` validation error response |

#### nz_passport

The NZ Passport check verifies against a simulated DIA Passport database. Passport numbers must be in the valid NZ format regardless of the scenario being exercised.

| Scenario | Inputs | Result |
|-|-|-|
| Verified match | Southland Stags, born 1980-12-12, passport `LZ115041` expiring 2017-10-10 | Pass - `match_status` `Match`, `document_verified` `true` |
| No match | Any other valid inputs | Fail - `match_status` `NoMatch` |
| No match with explanation | Passport `ZZ111111` (any name) | Fail - `NoMatch` with `additional_information` of `passportExpiry does not match passportNo` |
| Source outage | Passport `ZZ000000` (any name) | Fail - `NoMatch`, document not verified |
| Validation error | Expiry date `1900-01-01` | `400` validation error response |

#### payroll_super

The non-DVS payroll & superannuation check returns matches for these people. Address, email, phone and employer-ABN inputs are also matched against the seeded record - matching values come back as `MATCHED`, anything else as `UNMATCHED`.

| First | Middle | Last | Birth date | Super | Payroll |
|-|-|-|-|-|-|
| John | James | Doe | 1990-01-01 | MATCHED | MATCHED |
| Jane | Karen | Smith | 1995-02-18 | UNMATCHED | MATCHED |
| Fiona | (none) | Cheng | 1982-06-28 | MATCHED | UNMATCHED |

Reference values for the matched paths (any field that does not match the value below comes back as `UNMATCHED`):

```
John James Doe (1990-01-01)
  4/123 Fake Street, Fakeville VIC 3987 AU
  john@example.com / 0400123456 / employer_abn 12345678901

Jane Karen Smith (1995-02-18)
  456 Wrong Avenue, Sampleville NSW 2785 AU
  jane@example.com / 0412345678 / employer_abn 98765432109

Fiona Cheng (1982-06-28)
  3 Right Avenue, Hiddenville WA 6824 AU
  fiona@example.com / 0400987654 / employer_abn 91237856482
```

To force a `500` upstream-failure response, submit `first_name` = `Service` and `last_name` = `Unavailable`.

ID Pass verifications are exercised with document images rather than field values: see [IDPass Test Documents (login required)](/docs/guides/watcheye_api/idpass-test-documents) for the sample licences and passports and the result each one returns.
