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

# Sandbox

> A complete, separate stack with simulated money — and deterministic ways to make things fail.

The sandbox is not a flag on production. It's a **fully separate stack** — its own API, database, and workers — running the same code against simulated fiat rails and real testnet blockchains. A `sk_test_` key can't reach production and a `sk_live_` key can't reach sandbox, so the wrong-environment class of accident can't happen.

|                                 | Sandbox                                               | Production                        |
| ------------------------------- | ----------------------------------------------------- | --------------------------------- |
| Base URL                        | `https://sandbox-api.platform.chipper.ai`             | `https://api.platform.chipper.ai` |
| Keys                            | `sk_test_…`                                           | `sk_live_…`                       |
| Fiat rails (mobile money, bank) | Simulated — instant, deterministic                    | Real aggregators                  |
| Crypto                          | Real **testnets** (Solana devnet, Ethereum testnets…) | Mainnets                          |
| Customer-facing ids             | carry `_test_` (`pl_test_…`)                          | `pl_…`                            |
| Webhooks, pagination, errors    | identical                                             | identical                         |

## Funding a balance

Payouts debit a balance, and nothing pays *into* a sandbox account on its own. Create money:

```bash theme={null}
POST /v1/simulations/fund-balance
{ "amount": 5000, "currency": "NGN", "externalReference": "fund-1" }
```

## Deterministic outcomes

Real rails fail in real ways — a wallet rejects, a bank times out, a customer never approves the prompt. Sandbox lets you trigger each one on purpose.

### Payouts — the amount's cents choose the outcome

| Amount ends in | Outcome                                                        |
| -------------- | -------------------------------------------------------------- |
| `.01`          | `rejected` — provider refuses immediately                      |
| `.02`          | `beneficiary_unavailable`                                      |
| `.03`          | `timeout_then_reconciled` — no response, later found completed |
| `.04`          | `retry_then_completed` — first attempt fails, retry succeeds   |
| `.05`          | `pending_then_completed`                                       |
| `.06`          | `connection_reset`                                             |
| `.07`          | `pending_then_failed`                                          |
| anything else  | `completed`                                                    |

So `150.00` completes, `150.07` goes pending and then fails — same code path your production integration will hit.

### Collections — the amount's cents choose the outcome

| Amount ends in | Outcome                                            |
| -------------- | -------------------------------------------------- |
| `.50`          | `delayed_completion`                               |
| `.51`          | `failed` — the payer declined                      |
| `.52`          | `customer_timeout` — the prompt was never answered |
| `.99`          | `transient_error_then_reconciled`                  |
| anything else  | `completed`                                        |

### Validation — the account number's suffix chooses the outcome

| Account number ends in | Result                                     |
| ---------------------- | ------------------------------------------ |
| `000000`               | `account_not_found`                        |
| `000001`               | `account_closed`                           |
| `000002`               | `validation_timeout`                       |
| anything else          | `valid`, with a deterministic account name |

### Simulated inflows

Money *arriving* has no natural trigger in sandbox, so there are endpoints for it:

* `POST /v1/simulations/virtual-account-deposit` — a customer transferred into a virtual account (choose `completed` or `failed`).
* `POST /v1/simulations/checkout-deposit` — a payer completed a bank-transfer checkout session.
* Crypto deposits: send real testnet tokens to the address, or use the checkout page's dev tools locally.

`GET /v1/simulations` returns this whole table as JSON, so your test suite can read the rules rather than hardcode them.

## What sandbox won't tell you

Sandbox proves your *integration* — envelopes, idempotency, webhook handling, state machines. It doesn't prove a specific rail's behaviour on a Tuesday afternoon in Lagos: real settlement times, real operator downtime, real limits. Treat the `estimatedSettlement` values in capabilities as the honest production guide.

## Moving to production

You can create a `sk_live_` key and use the production API from day one — change nothing but the key and base URL. The one thing gated is **sending payouts with real money**: production access is enabled per organization. Email [**api-support@chippercash.com**](mailto:api-support@chippercash.com) with your organization name and use case.
