Mobile Money Trigger Numbers

The sandbox test numbers for every mobile money outcome

In the sandbox, the payer’s mobile number (paymentDetails.payerMobileNumber) decides what happens to a payment. Any number not listed here succeeds.

You can send the number in local or international format: in Kenya, 0970000005 and +254970000005 give the same result. The same numbers work in every market, so set payerDetails.location to the country you’re testing.

The sandbox also ignores the operator, so every number works the same with any operator. To mirror a market, check the Approval flow column on its country page and use the matching section below. Flows where the customer dials a USSD code themselves can’t be tested in the sandbox yet.

Authorisation failures

The transaction ends in FAILED with authState.state: "failed" and emits transaction.failed. Terminal — to retry, start a new transaction.

NumberauthState.codeMeaning
0970000005payinInsufficientFundsThe payer’s wallet balance is too low.
0970000006customerRejectedThe payer declined the prompt on their handset.
0970000007timeoutThe payer did not respond before the operator gave up.
0970000008accountNotActiveThe wallet exists but is inactive or suspended.
0970000009payinPayerInvalidAccountNo wallet exists for this number on the chosen operator.
0970000010payinPayerLimitExceededThe payer’s daily limit would be exceeded.
0970000011monthlyLimitExceededThe payer’s monthly limit would be exceeded.
0970000014transactionNotFoundThe provider cannot locate the transaction.

System errors

These return authState.state: "error" rather than "failed" — the payment was not declined, something broke. Check canRetry and canPoll on the response before deciding what to do.

NumberauthState.codeMeaning
0970000012internalErrorA CrissCross-side error.
0970000013downstreamErrorThe operator returned an error.

Transient faults

These misbehave for the first 2 seconds after the transaction is created, then behave normally. Use them to prove your retry and polling code recovers rather than giving up.

NumberBehaviour
0970000015POST /v1/payment errors with downstreamError inside the window, then succeeds on a retry.
0970000016The transaction is created normally, but GET /v1/payment/{transactionId} errors with downstreamError inside the window before returning a normal state.
0970000017The first execution fails. If your account has a fallback processor configured for the same method, the fallback attempt succeeds.

Delayed confirmations

These stay in AUTH_REQUIRED for a fixed delay, then authorise — a payer who is slow to approve. Pair a delay longer than your session expiry to exercise the late-debit path: the confirmation lands after the transaction has expired, and the automatic refund fires.

NumberDelayAs a late debit
09700000185 minutesRefund fails — accountNotActive
097000001930 secondsToo close to the 30-second minimum session expiry to exercise late debit reliably
09700000201 minuteRefund fails — recipient limit reached
09700000261 minuteRefund succeeds — use this one to test the full path

0970000018 respects a SANDBOX_DELAYED_CONFIRMATION_MS override on the environment, so an operator-run demo may use a shorter window than the 5 minutes shown here.

Why some refunds fail

A refund is paid back to the number the payment came from, and it goes through the payout sandbox. There, a number ending in 12, 14, 16, 18, 20 or 22 fails (see Payout Trigger Endings).

That’s why the refunds for 0970000018 and 0970000020 fail. To test a late debit and a successful refund end to end, use 0970000026.

OTP

Use 0970000021 to test a payment that asks the payer for a one-time code. The response has authState.authMethodType: "fields" with one otp field.

Send the code with POST /v1/payment/authorize (API reference):

CodeResult
123456The payment completes shortly after.
Any other codeThe payment fails with invalidPin. The payer isn’t asked again, as in production.
No codeThe payment expires with the session.

If your account has a fallback processor, the fallback attempt fails straight away rather than asking for a second code.

Redirect

These numbers send the payer to a URL to approve the payment, as some wallets do. The response has authState.authMethodType: "redirect".

NumberWhat the payer seesResult
0970000025A test page with Approve and Decline buttonsWhatever the payer clicks
0970000023The same test page, with requiresTopLevel: trueWhatever the payer clicks
0970000022No page; they go straight to your redirectUrlCompletes after about 10 seconds
0970000024No page; they go straight to your redirectUrlFails after about 10 seconds
  • Test page numbers only resolve when the payer clicks. If they ignore the page, the payment expires with the session. Use 0970000023 to test wallets that must open outside an iframe.
  • No-page numbers need no clicks, so use them in automated tests. The result arrives through polling or your webhook.

After the payer decides, Hosted Checkout returns them to the checkout. With the Direct API, they go to the session’s redirectUrl with status=complete or status=failed. Always set redirectUrl, or the payer ends up on a placeholder page.

As with OTP, a fallback processor fails straight away rather than redirecting the payer a second time.

Success

Any number not listed here succeeds. The payment goes from PENDING to AUTH_REQUIRED and reaches COMPLETED about 10 seconds after you create it, with a processorReference.