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

# Testing in sandbox

> Test PrimePay API integrations without real money.

* Use `sk_test_` keys on the sandbox API. Nothing is real, and nothing reaches live accounts.
* Your server address isn't checked in sandbox.
* Transfers can go to your own sandbox accounts, PrimePay's test merchant accounts and test wallets.
* Payouts can only go to test phone numbers and test bank account numbers (any `bankCode`). They finish on their own a few seconds later, with the result the test number or account is set up for (paid, declined, invalid account, slow or pending).
* PrimePay Wallet payments (`primepay_wallet`) work with the test wallet numbers below. Nobody has to approve anything: the test number decides the result.
* Payment link `redirectUrl` also allows `http://localhost` in sandbox.

## Test Airtel Money and TNM Mpamba numbers

Use one of these as `customerPhone` with the `airtel` or `tnm` operator. Nobody types a PIN: the number decides the result.

| Airtel Money | TNM Mpamba | What happens |
| - | - | - |
| `+265991000001` | `+265881000001` | Paid about 3 seconds later. The payment becomes `success`. |
| `+265991000002` | `+265881000002` | Refused straight away: `402` with `"status": "failed"` and `failureCode` `INSUFFICIENT_FUNDS`. |
| `+265991000003` | `+265881000003` | Refused straight away: `402` with `failureCode` `INVALID_ACCOUNT`. |
| `+265991000004` | `+265881000004` | The operator doesn't answer. The payment stays `processing`, then becomes `success` about a minute later. |
| `+265991000005` | `+265881000005` | A slow answer (about 8 seconds), then `processing` for 10 minutes before `success`. |
| Any other Malawi number | Any other Malawi number | Paid about 3 seconds later. |

## Test payout and transfer destinations

Payouts and transfers in sandbox can only go to these. Anything else is refused with `sandbox_recipient_not_allowed`.

| Send to | What happens |
| - | - |
| Mobile money `+265991000001` or `+265881000001` | Paid about 3 seconds later. |
| Mobile money `+265991000002` or `+265881000002` | Fails about 3 seconds later with `failureCode` `DECLINED`. |
| Mobile money `+265991000003` or `+265881000003` | Fails with `INVALID_ACCOUNT`. |
| Mobile money `+265991000004` or `+265881000004` | Paid about a minute later. |
| Mobile money `+265991000005` or `+265881000005` | Paid 10 minutes later. |
| Bank account `0000000001` (any `bankCode`) | Paid about 3 seconds later. |
| Bank account `0000000002` | Fails with `ACCOUNT_REFUSED`. |
| Bank account `0000000003` | Paid 10 minutes later. |
| Merchant account `00000101` | Transfer accepted. |
| Merchant account `00000102` | A disabled account: the transfer is refused. |
| PrimePay wallet `+265991000100` | Transfer accepted. |
| PrimePay wallet `+265991000101` | A suspended wallet: the transfer is refused. |

## Test PrimePay Wallet numbers

Use one of these as `customerPhone` with the `primepay_wallet` operator. A test wallet never runs out of money.

| Number | What happens |
| - | - |
| `+265991000100` | The owner approves after about 3 seconds. The payment becomes `success`. |
| `+265991000101` | A suspended wallet. The request is refused straight away with `wallet_inactive`. |
| `+265991000102` | The owner declines. The payment becomes `failed` with `failureCode` `DECLINED`. |
| `+265991000103` | The owner approves but the balance is too low. `failed` with `WALLET_INSUFFICIENT_FUNDS`. |
| `+265991000104` | The owner never answers. The payment becomes `expired` after 5 minutes (`EXPIRED`). |
| Any other number | Refused with `wallet_not_found`. |

You get the same webhooks as live: `payment.succeeded`, or `payment.failed` for a declined, unpaid or expired payment.

A successful test wallet payment can be refunded. The refund becomes `success` a few seconds later.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.