> ## Documentation Index
> Fetch the complete documentation index at: https://docs.verifyyou.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Testing

> General gotchas and how to use the sandbox API

## What to expect when testing

If you're running the full flow yourself in a browser (not just hitting the API), there are a few things to know up front.

### Heads up if you're testing on desktop

If you open the verification URL on a laptop or desktop, you'll be handed off to your phone via a QR code; the liveness capture only runs on mobile. Scan the QR, finish the flow on your phone, and the desktop tab will advance and redirect back on its own. See the [Quick start](/v2/quickstart) for the full breakdown.

### Test phone numbers are required

In sandbox mode, you must use a test phone numbers via the [sandbox API](/v2/testing#generate-a-test-phone-number).
You can generate a number and its verification code first via `POST /v2/sandbox/phone-number`,
then enter both when the flow prompts you.

<Tip>
  Want to skip the phone-OTP step entirely during testing? Pass the test phone number as `phone` on `verification.create`; the flow lands straight on the liveness check. See [Skip phone verification](/v2/quickstart#skip-phone-verification-with-phone).
</Tip>

### Account state persists beyond your browser

VerifyYou tracks accounts at the user level, not the browser level.
Your verified phone number acts as a persistent identifier that follows the account
across devices and sessions, clearing cookies, switching devices, or opening an
incognito window won't give you a fresh start.

When you're testing, you'll probably run into this pretty quickly, and from the API
side it can feel like a bug. You'll call `verification.create`, push the same user
(or someone close) through the flow a second time, and not get the fresh slate you
expected. That's by design: every verification you create is tied to a user at
creation time, and that tie follows them through the whole lifecycle on our end.
Incognito, cleared cookies, a different browser, a new device: none of that gives
you a fresh start, because the state lives on our servers, not in your browser.
One verified account per user per company is the rule.

To keep testing, you've got two options: delete the account (see below) and re-run
the same user, or kick off a new `verification.create` with a different test phone
number so you're binding a different user.

If something looks genuinely broken (not just "I got blocked again"),
report it to us; we want to know.

If you actually need a clean slate (which is often when testing), visit [/del](https://vyjoin.com/del) on the
VerifyYou web app to delete your account, then try again.

### Landing in human review

On your second attempt through the flow, you'll should land in human review. The
reason is simple: your face is already on file from the first run, so the second
attempt collides with an existing verified account, and that collision is what
sends you to human review.

Human review is a safety net, not a catch-all; in production it should see very
little traffic. You won't see a big scary error when you land here; things just
sort themselves out in the background.

<Info>
  The human review step can be annoying during development. We're working on
  a sandbox dashboard where you can self-approve pending verifications for
  testing. No ETA yet, but reach out if it's slowing you down.
</Info>

***

## Sandbox API

The sandbox endpoints let you test the full verification flow without real phone numbers or SMS. No API key is needed; unauthenticated access works out of the box.

<Note>
  Public access to these endpoints is heavily rate limited. Please use an [API key](/v2/authentication) when possible.
</Note>

## Generate a test phone number

Call `POST /v2/sandbox/phone-number` to get a random test phone number and its verification code in one shot.

<CodeGroup>
  ```javascript Node.js theme={null}
  const response = await fetch("https://api.connect.verifyyou.com/v2/sandbox/phone-number", {
    method: "POST",
  });

  const data = await response.json();
  const phone = data.phone_number;       // "+999011234567"
  const code = data.verification_code;   // "234567"
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      "https://api.connect.verifyyou.com/v2/sandbox/phone-number",
  )

  data = response.json()
  phone = data["phone_number"]       # "+999011234567"
  code = data["verification_code"]   # "234567"
  ```

  ```typescript TypeScript theme={null}
  interface SandboxPhoneResponse {
    phone_number: string;
    verification_code: string;
  }

  const response = await fetch("https://api.connect.verifyyou.com/v2/sandbox/phone-number", {
    method: "POST",
  });

  const data: SandboxPhoneResponse = await response.json();
  const phone = data.phone_number;       // "+999011234567"
  const code = data.verification_code;   // "234567"
  ```

  ```csharp C# theme={null}
  using var client = new HttpClient();

  var response = await client.PostAsync(
      "https://api.connect.verifyyou.com/v2/sandbox/phone-number",
      null
  );

  var json = await response.Content.ReadAsStringAsync();
  // { "phone_number": "+999011234567", "verification_code": "234567" }
  ```

  ```java Java theme={null}
  var request = HttpRequest.newBuilder()
      .uri(URI.create("https://api.connect.verifyyou.com/v2/sandbox/phone-number"))
      .POST(HttpRequest.BodyPublishers.noBody())
      .build();

  var response = client.send(request, HttpResponse.BodyHandlers.ofString());
  // { "phone_number": "+999011234567", "verification_code": "234567" }
  ```

  ```php PHP theme={null}
  $response = file_get_contents("https://api.connect.verifyyou.com/v2/sandbox/phone-number", false,
      stream_context_create(["http" => ["method" => "POST"]])
  );

  $data = json_decode($response, true);
  $phone = $data["phone_number"];       // "+999011234567"
  $code = $data["verification_code"];   // "234567"
  ```

  ```go Go theme={null}
  req, _ := http.NewRequest("POST",
      "https://api.connect.verifyyou.com/v2/sandbox/phone-number",
      nil,
  )

  resp, _ := http.DefaultClient.Do(req)
  defer resp.Body.Close()

  var data struct {
      PhoneNumber      string `json:"phone_number"`
      VerificationCode string `json:"verification_code"`
  }
  json.NewDecoder(resp.Body).Decode(&data)
  // data.PhoneNumber: "+999011234567"
  // data.VerificationCode: "234567"
  ```
</CodeGroup>

```json Response theme={null}
{
  "phone_number": "+999011234567",
  "verification_code": "234567"
}
```

You can request US-formatted numbers by passing `type` and `area_code`:

<CodeGroup>
  ```javascript Node.js theme={null}
  const response = await fetch("https://api.connect.verifyyou.com/v2/sandbox/phone-number", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ type: "us", area_code: "415" }),
  });
  ```

  ```python Python theme={null}
  response = requests.post(
      "https://api.connect.verifyyou.com/v2/sandbox/phone-number",
      json={"type": "us", "area_code": "415"},
  )
  ```

  ```typescript TypeScript theme={null}
  interface SandboxPhoneRequest {
    type?: "us" | "global";
    area_code?: string;
  }

  const payload: SandboxPhoneRequest = { type: "us", area_code: "415" };

  const response = await fetch("https://api.connect.verifyyou.com/v2/sandbox/phone-number", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(payload),
  });

  const data: SandboxPhoneResponse = await response.json();
  ```

  ```csharp C# theme={null}
  var response = await client.PostAsync(
      "https://api.connect.verifyyou.com/v2/sandbox/phone-number",
      new StringContent(
          """{"type": "us", "area_code": "415"}""",
          System.Text.Encoding.UTF8,
          "application/json"
      )
  );
  ```

  ```java Java theme={null}
  var request = HttpRequest.newBuilder()
      .uri(URI.create("https://api.connect.verifyyou.com/v2/sandbox/phone-number"))
      .header("Content-Type", "application/json")
      .POST(HttpRequest.BodyPublishers.ofString(
          "{\"type\": \"us\", \"area_code\": \"415\"}"
      ))
      .build();

  var response = client.send(request, HttpResponse.BodyHandlers.ofString());
  ```

  ```php PHP theme={null}
  $response = file_get_contents("https://api.connect.verifyyou.com/v2/sandbox/phone-number", false,
      stream_context_create(["http" => [
          "method" => "POST",
          "header" => "Content-Type: application/json",
          "content" => json_encode(["type" => "us", "area_code" => "415"]),
      ]])
  );
  ```

  ```go Go theme={null}
  body, _ := json.Marshal(map[string]string{
      "type":      "us",
      "area_code": "415",
  })

  req, _ := http.NewRequest("POST",
      "https://api.connect.verifyyou.com/v2/sandbox/phone-number",
      bytes.NewBuffer(body),
  )
  req.Header.Set("Content-Type", "application/json")

  resp, _ := http.DefaultClient.Do(req)
  defer resp.Body.Close()
  ```
</CodeGroup>

```json Response theme={null}
{
  "phone_number": "+14155550142",
  "verification_code": "550142"
}
```

***

## Look up a verification code

Already have a test phone number? Call `POST /v2/sandbox/verification-code` to get its code.

<CodeGroup>
  ```javascript Node.js theme={null}
  const response = await fetch("https://api.connect.verifyyou.com/v2/sandbox/verification-code", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ phone_number: "+14155550142" }),
  });

  const code = (await response.json()).verification_code;  // "550142"
  ```

  ```python Python theme={null}
  response = requests.post(
      "https://api.connect.verifyyou.com/v2/sandbox/verification-code",
      json={"phone_number": "+14155550142"},
  )

  code = response.json()["verification_code"]  # "550142"
  ```

  ```typescript TypeScript theme={null}
  interface VerificationCodeRequest {
    phone_number: string;
  }

  interface VerificationCodeResponse {
    verification_code: string;
  }

  const response = await fetch("https://api.connect.verifyyou.com/v2/sandbox/verification-code", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ phone_number: "+14155550142" } satisfies VerificationCodeRequest),
  });

  const data: VerificationCodeResponse = await response.json();
  const code = data.verification_code;  // "550142"
  ```

  ```csharp C# theme={null}
  var response = await client.PostAsync(
      "https://api.connect.verifyyou.com/v2/sandbox/verification-code",
      new StringContent(
          """{"phone_number": "+14155550142"}""",
          System.Text.Encoding.UTF8,
          "application/json"
      )
  );

  var json = await response.Content.ReadAsStringAsync();
  // { "verification_code": "550142" }
  ```

  ```java Java theme={null}
  var request = HttpRequest.newBuilder()
      .uri(URI.create("https://api.connect.verifyyou.com/v2/sandbox/verification-code"))
      .header("Content-Type", "application/json")
      .POST(HttpRequest.BodyPublishers.ofString(
          "{\"phone_number\": \"+14155550142\"}"
      ))
      .build();

  var response = client.send(request, HttpResponse.BodyHandlers.ofString());
  // { "verification_code": "550142" }
  ```

  ```php PHP theme={null}
  $response = file_get_contents("https://api.connect.verifyyou.com/v2/sandbox/verification-code", false,
      stream_context_create(["http" => [
          "method" => "POST",
          "header" => "Content-Type: application/json",
          "content" => json_encode(["phone_number" => "+14155550142"]),
      ]])
  );

  $code = json_decode($response, true)["verification_code"];  // "550142"
  ```

  ```go Go theme={null}
  body, _ := json.Marshal(map[string]string{
      "phone_number": "+14155550142",
  })

  req, _ := http.NewRequest("POST",
      "https://api.connect.verifyyou.com/v2/sandbox/verification-code",
      bytes.NewBuffer(body),
  )
  req.Header.Set("Content-Type", "application/json")

  resp, _ := http.DefaultClient.Do(req)
  defer resp.Body.Close()

  var data struct {
      VerificationCode string `json:"verification_code"`
  }
  json.NewDecoder(resp.Body).Decode(&data)
  // data.VerificationCode: "550142"
  ```
</CodeGroup>

```json Response theme={null}
{
  "verification_code": "550142"
}
```

<Info>
  The verification code is always the last 6 digits of the phone number. Only test phone numbers are accepted; real numbers will return a `400` error.
</Info>

***

## Test phone number ranges

Test numbers use reserved ranges that never send real SMS and never trigger real verifications:

| Range                             | Format                           | Example         |
| --------------------------------- | -------------------------------- | --------------- |
| **Global** (ITU E.164 test range) | `+99901` followed by 7-12 digits | `+999011234567` |
| **US** (NANP 555 block)           | `+1{area_code}555-01xx`          | `+14155550142`  |

***

## Full test flow

Here's how to run the complete verification cycle end-to-end. The loop is:
**generate a test phone number → create a verification → complete the human
step in a browser → check status → delete the account and repeat** if you want
another clean run.

<Warning>
  The liveness + uniqueness scan has to be completed in a browser by a real
  human in front of a camera. It's intentionally not API-automatable; don't
  try to wire it into an automated test suite. The script below handles the
  backend steps; the human step happens in the hosted flow.
</Warning>

**1. Backend steps (scriptable):**

```python Python theme={null}
import requests

# 1. Generate a test phone number
sandbox = requests.post(
    "https://api.connect.verifyyou.com/v2/sandbox/phone-number",
).json()
print(sandbox)
# {"phone_number": "+999011234567", "verification_code": "234567"}

# 2. Create a verification
verification = requests.post(
    "https://api.connect.verifyyou.com/v2/verification/create",
    json={"redirect": "https://yourapp.com/verified"},
).json()
print(verification)
# {"verification_url": "https://verifyyou.com/i/A3KF9X", "external_id": "d4f8e2a1-..."}
```

**2. Human step (browser, manual):** open `verification_url` in a browser,
enter the sandbox phone number and its verification code, then complete the
liveness capture in front of a camera.

**3. Check the status (scriptable):**

```python Python theme={null}
# After the human has finished the flow in the browser
status = requests.post(
    "https://api.connect.verifyyou.com/v2/verification/status",
    json={"external_id": verification["external_id"]},
).json()
print(status)
# {"verification_complete": true, "external_id": "d4f8e2a1-..."}
```

**4. Restart the loop (for repeat testing, spoof attempts, etc.):**

Once you've verified, your face is on file; the next run through the flow
will collide with your existing account and land in human review (see
[Landing in human review](#landing-in-human-review)). To get a clean slate,
visit [/del](https://vyjoin.com/del) on the VerifyYou web app to delete your
account, then start again from step 1.
