Skip to content

Test Scenarios by Payment Method

Each scenario below is the same four steps with a different destination. Work through the happy path first, then the four failures — those are the ones that decide whether your integration survives contact with production.

All of them need sandbox credentials and your sandbox wallet's account number: see Sandbox Credentials & Test Numbers.

1. The happy path: C2B M-Pesa collection

The same flow as the Quickstart, laid out as a repeatable scenario.

  1. Authenticate — GET /auth/token/ with your sandbox client ID and secret. See Authentication.
  2. Initiate — POST /payments/initiate/ with transaction_type: "C2B", payment_method: "mpesa", account_number: "254700000000" and your sandbox wallet as merchant_id. See Initiate Payment.
  3. Poll status — POST /payments/status-query/ with your merchant_reference until status is final. See Transaction Status Query.
  4. Confirm in statement — GET /transactions/?account_number=<sandbox_merchant_id> and confirm the transaction appears. See Transactions Statement.

The result arrives a few seconds after step 2, so expect the first poll to still show the payment in flight. That is not a failure — it is what a real STK prompt looks like while the customer is still deciding.

Repeat this shape for B2C payouts, B2B transfers and the bank, card, airtel and tkash methods. The outcome table works the same way for all of them.

2. Customer cancels — 254700000001

Same request, different destination. The initiate call still succeeds: the customer has not decided yet at that point.

Then the result arrives with ResultCode 1032 and the payment goes to failed.

What this tests: that you do not treat a successful initiate response as a completed payment. If your code releases goods at step 2, this scenario ships them for free.

3. Insufficient funds — 254700000002

As above, with ResultCode 1.

What this tests: that your failure handling distinguishes "the customer could not pay" from "something broke". These are the same HTTP status to you and very different things to your support team.

4. Timeout — 254700000003

The initiate call succeeds. Then nothing arrives, ever. No callback, no status change.

Walk this one through deliberately:

  1. Initiate to 254700000003.
  2. Wait past whatever timeout your own code uses.
  3. Call POST /payments/status-query/. It answers — the payment is still processing.
  4. Decide what your system does now.

What this tests: the case that produces most support tickets in production. Your integration needs an answer to "we never heard back" that is neither "assume it failed" (the customer may have paid) nor "wait forever" (the order never resolves). Status query is that answer.

5. Ambiguous payout — 254700000004

Use transaction_type: "B2C" and destination 254700000004. This time the initiate call itself fails.

The payout is recorded as reconciliation_required. Hivemind Payments does not retry it against another provider, because we do not know whether the first one already moved the money — retrying is how a recipient gets paid twice. A human settles it.

What this tests: that your code does not automatically re-send a failed payout. If it does, this is the scenario where that becomes a duplicate payment in production. Surface it as "pending investigation" and stop.

6. Late result — 254700000005

Initiate, then wait. The successful result arrives about two minutes later.

What this tests: that a slow result does not get overwritten by a premature decision. If your polling loop gives up after 30 seconds and marks the payment failed, your records now disagree with ours about a payment that succeeded — and the customer has been charged.

Testing webhook delivery alongside polling

Set result_url on your initiate calls to a webhook.site URL or an ngrok tunnel, and watch the callbacks arrive while you poll. Every scenario above except the timeout delivers one.

Receiving a sandbox result on your webhook and returning a 2xx is also one of the go-live requirements — so this step is not optional housekeeping, it is part of the path to production. See Verifying & Testing Webhooks.