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

# Sandbox

> Build and test your Hyparrow integration with simulated data and no real money.

The Hyparrow **sandbox** is a complete, isolated copy of the API that simulates
every external provider. Use it to build and test your integration end-to-end —
KYC verifications, payments, transfers, bills and crypto — without moving real
money or hitting real providers.

## Base URL

All sandbox requests go to:

```
https://sandbox.hyparrow.cloud/api/v1
```

This is the same API surface as production (`https://api.hyparrow.cloud/api/v1`)
— only the host and your keys differ.

## Test API keys

The sandbox accepts **test keys only**. Create one from your dashboard's API
keys page while in **Sandbox** mode; it is minted with `pk_test_` / `sk_test_`
prefixes and lives in the sandbox database.

<Note>
  Don't see an **API keys** page? It lives in the **Developer** extension. Open
  **Extensions** in your dashboard sidebar and install **Developer** first — the
  API keys page (and the rest of the developer tools) will then appear.
</Note>

```bash theme={null}
curl https://sandbox.hyparrow.cloud/api/v1/kyc/balance \
  -H "X-API-Key: pk_test_..." \
  -H "X-API-Secret: sk_test_..."
```

<Card title="Strict environment isolation" icon="lock">
  A test key only works against the sandbox, and a live key only works against
  production. Using a live key on the sandbox (or vice versa) returns
  `403 Forbidden`. A test key can never move real money.
</Card>

Every sandbox merchant is provisioned with a **funded test wallet**
(₦5,000,000) so calls that bill against your balance (pay-as-you-go
verifications, transfers, bill payments) succeed out of the box.

## Magic test values

Sandbox responses are deterministic and driven by "magic" inputs, so you can
reliably exercise both success and failure paths.

### Identity verification (BVN, NIN, etc.)

The rule is applied to whichever identifier the endpoint takes — `bvn`, `nin`,
`vin`, `phone_number` or `rc_number`.

| Input                                                          | Result                                                                                                             |
| -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| All ones (e.g. `11111111111`)                                  | Failure: HTTP **404**, `"code": "RECORD_NOT_FOUND"`                                                                |
| Anything else well-formed, including all zeros (`00000000000`) | Success with data deterministically derived from the input (the same input always returns the same person/company) |
| A malformed identifier (e.g. `1234`)                           | HTTP **400**, `"code": "VALIDATION_ERROR"` — rejected before simulation, exactly as in production                  |

<Note>
  All ones is the **only** special-cased value. Every other identifier succeeds,
  so `00000000000` returns a record like any other input — there is no
  separately reserved "success" value.
</Note>

<Warning>
  These magic values exist **only in the sandbox**. Production has no test
  identifiers: sending `00000000000` or `11111111111` to `api.hyparrow.cloud` is
  a live lookup, the verification network has no such record, and you get a
  `404 RECORD_NOT_FOUND` (automatically refunded — see
  [Identity Verification](/kyc#billing-model)).
</Warning>

The sandbox failure response is byte-for-byte the shape production returns, so
the branch you write here is the branch that runs live:

```json 404 Response theme={null}
{
  "success": false,
  "code": "RECORD_NOT_FOUND",
  "error": "no record was found for the details provided",
  "data": {
    "message": "Record not found"
  }
}
```

A sandbox success nests the record at `data.data` exactly as production does —
see [Response envelope](/kyc#response-envelope) — but the **keys of the
intermediate envelope are not identical**:

```json Sandbox success theme={null}
{
  "success": true,
  "data": {
    "status": true,
    "message": "Verification successful (sandbox)",
    "data": { "firstName": "Adaeze", "lastName": "Okafor", "…": "…" }
  }
}
```

Production carries `success`, `statusCode`, `message` and `response_code` at
that level instead of `status` and `message`, and its inner record uses the
verification network's own field names (for BVN basic: `phoneNumber1`,
`phoneNumber2`, `image`). Read the record at `data.data` in both environments,
but do not branch on the intermediate envelope's keys, and confirm inner field
names against the production examples in
[Identity Verification](/kyc) before you go live.

### Payments (transfers, bills, card charges, VA funding)

By default a simulated payment **settles successfully**. The amount's last two
minor-unit digits force the other paths:

| Amount ends in       | Outcome   |
| -------------------- | --------- |
| `.01` (e.g. ₦100.01) | `failed`  |
| `.99` (e.g. ₦100.99) | `pending` |
| anything else        | `success` |

### Card payments

| Value                      | Behaviour                               |
| -------------------------- | --------------------------------------- |
| Card `5060990580000217499` | Always approved                         |
| Card `0000000000000000000` | Always declined                         |
| Card OTP `123456`          | Correct OTP (any other OTP is rejected) |
| Any other card             | Follows the amount rule above           |

## What's simulated

In the sandbox, every external provider is short-circuited — no real calls are
made and no real costs are incurred:

* **Identity / KYC** — BVN, NIN, phone, voter's card, CAC and account-number lookups
* **Payments** — virtual accounts, money transfer, card payments
* **Bills** — airtime, data, cable TV, electricity, PINs
* **Crypto** — wallet creation, balances, transfers

Billing still runs against your funded **test** wallet, so you can observe
quota, pay-as-you-go and insufficient-balance behaviour exactly as in
production — just with simulated money.

## Going live

When your integration works in the sandbox, switch your dashboard to **Live**
mode, generate a live (`pk_live_`) key, and point your requests at
`https://api.hyparrow.cloud/api/v1`. No code changes are required beyond the
base URL and credentials.
