Skip to content

Sandbox mode

The same API, completely separate data, and outcomes you choose.

Sandbox is not a separate product or a mock server. It is the same API, the same routes and the same validation, with data kept completely apart from live. What changes is where the money comes from: no operator is contacted, and the outcome is decided by the test number, card or account you use.

How the environment is chosen

By the key. There is no parameter, no header and no flag.

PrefixEnvironment
pk_test., sk_test., rk_test.Sandbox
pk., sk., rk.Live

A sandbox key cannot read live data, and the reverse is equally true: sandbox and live are completely separate. That is also why a payment you created in sandbox will never appear in your live Konsole, and why there is nothing to filter.

What is real

Real in sandboxMeaning
ValidationThe same rules, the same 422 messages
LimitsAmount floors and ceilings are enforced identically
Events and webhooksReal events, real signatures, real retries
IdempotencyThe same behaviour on a repeated key
Rate limitsThe same ceilings, counted apart from live: a sandbox load test does not spend your live minute
BalanceA separate sandbox balance, credited by sandbox payments
Platform fees2% is charged on successful payments and transfers, producing fee.charged

The last one surprises people: a sandbox payment of 5,000 XAF credits less than 5,000 to your sandbox balance, exactly as a live one would.

What is simulated

SimulatedHow
The operatorThe test number decides the outcome, nothing is dialled
The card networkThe test card decides the outcome
3D SecureThe hosted checkout asks for a code sent by email, then the test card decides the outcome
The bankThe last two digits of the account decide the outcome
CryptoA deposit address per outcome is generated; sending one of them as wallet_address decides the outcome
TimingA fixed delay rather than a real network

The delays are short and fixed, which is what makes an automated test suite possible.

OperationDelay before the terminal status
Payment3 seconds
Refund2 seconds
Transfer2 seconds

Outcomes are deterministic

This is the part worth internalising: nothing in the sandbox is random, with one narrow exception.

ObjectWhat decides the outcome
Payment, mobile moneyThe suffix of the payer number
Payment, cardThe exact card number
Payment, bankThe last two digits of the account
Payment, cryptoWhich crypto.deposit.scenarios address you send as wallet_address (none: success)
RefundThe original payment's card or phone
TransferThe beneficiary's test number or account

The exception: a refund on a payment with no payment method attached falls back to a 70% chance of success. In practice this only happens on payments created without a payer, which is not a flow you ship.

Transfers are deterministic too

A sandbox transfer to a mobile money beneficiary requires a recognised test number and refuses anything else with a 422 that lists the valid ones. There is no probability involved.

The sandbox balance

Payouts need money. Sandbox payments credit a sandbox balance, and transfers debit it, so the order of your test matters: create and complete a payment before testing a payout, or the transfer fails for insufficient funds exactly as it would in production.

A failed transfer returns the amount to the balance. The 2% platform fee is not returned, which mirrors live behaviour.

Crypto is off unless asked for

The crypto channel is disabled in sandbox by default, and it is switched on for the whole sandbox platform, not per account. When it is enabled, a deposit address and a payment URI are generated per scenario, valid for 30 minutes, and the address itself is deterministic, so you can reproduce the same scenario twice.

Nobody sends funds in sandbox, so the answer to POST /payments/{id} on a crypto channel also carries a simulator_url. It is a signed link, valid for 30 minutes, to a page with four buttons, SUCCESS, FAILURE, TIMEOUT and CANCELED. Pressing one queues that outcome, and the payment then moves on as it would after a real deposit, webhooks included. The field never exists in live.

3D Secure asks for a code by email

A 3D Secure test card from the scenarios answers 202 with action: "confirm_3ds". On the hosted checkout, the payer is then asked for a six digit code, which Wajub emails to the customer's address and to the account owner, so the challenge can be completed even when the test customer has a placeholder email. The code is valid for 10 minutes and allows 3 attempts. Once it is accepted, the card number decides whether the payment succeeds or fails.

What did you think of this content?