# Testing in sandbox

Use the sandbox test numbers to simulate verification codes and predefined outcomes without
sending an SMS message or placing a call to a real phone. You can test your verification flow
and error handling, including automated tests, without a phone.

Note

Use the sandbox base URL `https://verification-sandbox.didww.com` with credentials from a
sandbox OTP application. See [Choose an environment](getting-started.html#otp-verification-environments).

---

## Sandbox accounts

- Your sandbox account is approved automatically after you complete your account details and
  billing address in the
  [DIDWW Sandbox User Panel](https://my-sandbox.didww.com/#/users/account/edit).
- Your sandbox account includes USD 1,000 in virtual credit for testing.
- The verification fee is `0`.
- The sandbox never sends an SMS message or places a call to a real phone.

Verification responses depend on the number and selected delivery method:

| Condition | API response |
| --- | --- |
| Number outside the test ranges | The start request returns `201 Created`, then the verification ends with `status` set to `failed` and `error_code` set to `dispatch_failed`. |
| Destination not supported by the selected delivery method | The start request returns `201 Created` with `status` immediately set to `failed` and `error_code` set to `destination_not_supported_for_channel`. |

---

## Test numbers

Each scenario has ten US numbers and ten UK numbers. Replace `X` with any digit from `0`
to `9` to select a number.

Use a different number in each parallel test. After a verification is approved for delivery,
an OTP application must wait 30 seconds before starting another verification for the same
number, regardless of the delivery method. The expired test scenario also starts this
cooldown. See [Repeated starts](api-reference/start-verification.html#otp-verification-api-start-cooldown).

Per-second rate limits and the application's daily and monthly volume limits also apply.
See [Limits](limits.html#otp-verification-limits).

Test numbers support both `sms` and `callout`. Before testing, check the application's
[authentication mode](authentication.html#otp-verification-authentication) and callback settings:

- With `public` authentication, a callback URL must be configured. Without one, every test
  number except `+1201555015X` and `+44207946015X` returns `status` set to `denied` and
  `error_code` set to `denied_missing_callback_url`.
- For scenarios that send a [request callback](callbacks.html#otp-verification-callbacks), requests
  using `public` or `basic` authentication call the configured callback URL. To approve a
  verification, return `{ "action": "allow" }` from your callback endpoint. Requests using
  `application` authentication skip the callback.
- The slow-start and denied-by-callback scenarios simulate the callback outcome without
  contacting your callback endpoint. With `public` authentication, a callback URL must still
  be configured for these scenarios.

| US number | UK number | Result |
| --- | --- | --- |
| `+1201555010X` | `+44207946010X` | The sandbox simulates successful delivery and returns `status` set to `pending`. Reporting the [test code](#otp-verification-testing-codes) changes `status` to `verified`. |
| `+1201555011X` | `+44207946011X` | The sandbox simulates successful delivery and returns `status` set to `pending`. Reporting the [zero code](#otp-verification-testing-codes) changes `status` to `verified`. |
| `+1201555012X` | `+44207946012X` | The start request takes about 10 seconds to return, simulating a slow request callback. The verification has `status` set to `pending` and uses the [test code](#otp-verification-testing-codes). No request callback is sent. Use this scenario to test client timeouts and loading states. |
| `+1201555013X` | `+44207946013X` | The verification is created with `status` and `error_code` both set to `expired`. Reporting a code leaves the verification's `status` set to `expired`. |
| `+1201555014X` | `+44207946014X` | The start request returns `201 Created`, then the verification ends with `status` set to `failed` and `error_code` set to `dispatch_failed`. |
| `+1201555015X` | `+44207946015X` | The start request returns `402 Payment Required` with the `balance_insufficient` error code. |
| `+1201555016X` | `+44207946016X` | The start request returns `201 Created` with `status` set to `failed` and `error_code` set to `destination_not_supported_for_channel`. Nothing is sent. |
| `+1201555017X` | `+44207946017X` | The start request returns `201 Created` with `status` set to `denied` and `error_code` set to `denied_by_callback`, simulating a callback that denies the verification. No request callback is sent, so no callback server is needed. |

The UK test numbers use the London landline format and may be rejected by forms that accept
only mobile numbers.

Test verifications appear in the OTP Verification logs and statistics of the DIDWW Sandbox
User Panel. **Try it out** also accepts test numbers.

### Codes for test numbers

After starting a verification with a test number that simulates successful delivery or a
slow start, you still need to [report a code](api-reference/report-verification.html#otp-verification-api-report) to
complete
it. The sandbox does not send an SMS message or place a call, so use the predefined code for
that test scenario.

For example, with the default **Code length** of `6`:

- Start a verification for `+12015550100`, then report `123456` to change its `status`
  from `pending` to `verified`.
- Start a verification for `+12015550110`, then report `000000` to get the same result.

The other test numbers in the same ranges use the same codes. The slow-start scenario uses
the code shown for `+12015550100`. These rules also apply to the corresponding UK numbers.

If you change **Code length** in the OTP application, the code you must report changes too:

| Code length | Code for `+12015550100` | Code for `+12015550110` |
| --- | --- | --- |
| 4 | `1234` | `0000` |
| 5 | `12345` | `00000` |
| 6 (default) | `123456` | `000000` |
| 7 | `1234567` | `0000000` |
| 8 | `12345678` | `00000000` |

These codes apply to both `sms` and `callout`. You can check the code length in the start
response's `sms.code_length` or `callout.code_length` field.

### Example

The following example uses HTTP Basic authentication. Set `OTP_APPLICATION_KEY` and
`OTP_APPLICATION_SECRET` to the key and secret of your sandbox OTP application. Its minimum
authentication mode must allow `basic` requests. If a callback URL is configured, its
endpoint must return `{ "action": "allow" }` for this test to proceed.

The example assumes that **Code length** is `6`. If your application uses a different
length, use the code listed in [Codes for test numbers](#otp-verification-testing-codes).

1. Start an SMS verification for a test number:

   ```
   curl https://verification-sandbox.didww.com/api/v1/verifications \
     -u "$OTP_APPLICATION_KEY:$OTP_APPLICATION_SECRET" \
     -H 'Content-Type: application/json' \
     -d '{ "data": { "destination": "+12015550100", "delivery_method": "sms" } }'
   ```
2. Set `VERIFICATION_ID` to the `data.id` value from the response, then report the fixed
   code:

   ```
   curl -X PATCH "https://verification-sandbox.didww.com/api/v1/verifications/$VERIFICATION_ID" \
     -u "$OTP_APPLICATION_KEY:$OTP_APPLICATION_SECRET" \
     -H 'Content-Type: application/json' \
     -d '{ "data": { "delivery_method": "sms", "code": "123456" } }'
   ```

The response has `data.status` set to `verified`.

---

## Reproduce other outcomes

The following tests reproduce verification outcomes and request errors that can also occur in
production. Unless a row says otherwise, use a test number that simulates successful
delivery (`+1201555010X` or `+44207946010X`). Start a fresh verification for each report test.

Run each scenario separately and restore any changed settings before starting the next one.
For scenarios that test your callback endpoint, use `public` or `basic` authentication
with a configured callback URL. Requests using `application` authentication skip the
callback. See [Callbacks](callbacks.html#otp-verification-callbacks).

| Outcome | How to trigger it | Result |
| --- | --- | --- |
| Wrong code | For a pending verification, report a non-empty code that does not match the fixed code, such as `000000` when the fixed code is `123456`. | `422 Unprocessable Content` with the `code_invalid` error code. The verification's `status` stays `pending`. |
| Too many attempts | For a new pending verification, report a non-empty incorrect code three times, then report a non-empty code once more. | The first three reports return `422 Unprocessable Content` with `code_invalid`. The fourth returns `200 OK` with `status` set to `failed` and `error_code` set to `too_many_attempts`, even if the submitted code is correct. |
| Superseded | Start a verification and leave it pending. After 30 seconds, but before it expires, start another verification for the same number in the same OTP application. Retrieve the first verification using its `id`. | The first verification has `status` set to `failed` and `error_code` set to `superseded`. |
| Cooldown | Start a verification approved for delivery, then request another verification for the same number in the same OTP application within 30 seconds. | The second request returns `429 Too Many Requests` with the `destination_in_cooldown` error code and a `Retry-After` header. |
| Volume limit | Use an OTP application with no volume usage for the current UTC day and an available monthly allowance. Set its **Daily limit** to `1` (see [Set volume limits](manage-applications.html#otp-verification-volume-limits)), then start verifications for two different test numbers that simulate successful delivery. | The first approved request uses the daily allowance. The second request returns `429 Too Many Requests` with the `volume_limit_reached` error code and a `Retry-After` header. |
| Country disabled | Add the United States to the [country blocklist](manage-applications.html#otp-verification-country-blocklist), then start a verification for `+12015550100`. | `201 Created` with `status` set to `denied` and `error_code` set to `destination_country_disabled`. The UK numbers keep working. The expired, balance-insufficient, and unsupported test numbers keep their own outcomes. |
| Application paused | [Pause](manage-applications.html#otp-verification-pause-application) the OTP application, then start a verification for a test number that simulates successful delivery. | `201 Created` with `status` set to `denied` and `error_code` set to `application_paused`. |
| Invalid number | Start a verification for a malformed number, such as `+1201`. | `422 Unprocessable Content` with the `destination_invalid` error code. |
| Denied by your callback | Have your request callback return `{ "action": "deny" }`, then start a verification. To simulate this outcome without a callback server, use `+12015550170`. | `201 Created` with `status` set to `denied` and `error_code` set to `denied_by_callback`. |
| Invalid callback response | Have your request callback return a non-`2xx` status, invalid JSON, or an unsupported `action`, then start a verification. | `201 Created` with `status` set to `denied` and `error_code` set to `denied_invalid_callback_response`. |

After each test that changes settings, restore the previous configuration:

- Restore the application's daily and monthly volume limits.
- Resume the application if you paused it for the test.
- Restore the country blocklist, which applies to every OTP application in the account.
- Restore the callback URL and the response returned by your callback endpoint.

For every code and status, see [Errors and status codes](api-reference/errors.html#otp-verification-api-errors).

---

## Moving to production

Important

The test numbers listed on this page provide fixed codes and simulated outcomes only
in sandbox. In production, verification requests follow the normal delivery rules.

Before going live:

1. Switch your integration to the production environment. For REST API requests, use
   `https://verification.didww.com` as the base URL.
2. Use the key and secret from a production OTP application.
3. Keep automated tests that use test numbers configured for the sandbox environment.
