State Machine
Every RohoPay transaction follows this lifecycle:successful, failed) are permanent — a transaction never moves back to pending once it resolves.
Status Definitions
| Status | Description | Mobile Money | Card |
|---|---|---|---|
pending | Transaction created; awaiting user action | USSD prompt sent | 3DS not yet completed |
successful | Payment confirmed by provider webhook | User approved USSD | 3DS passed, card charged |
failed | Payment definitively rejected or timed out | User rejected USSD, expired | Card declined, 3DS failed |
Transaction Type States
- Collection (Mobile Money)
- Disbursement (Mobile Money)
- Card Payment
Best Practices
Never fulfill orders on pending status
Never fulfill orders on pending status
Only mark an order as paid after receiving a
successful status via webhook or confirmed by polling. Never fulfill on the initial pending response.Handle failed payments gracefully
Handle failed payments gracefully
Show the user a clear error and provide a retry option. Avoid retry loops — generate a new idempotency key for each retry attempt.
Implement a timeout on your side
Implement a timeout on your side
After 2 minutes of polling with no resolution, treat the transaction as “in progress” and inform the user. The status will eventually resolve — your webhook will fire when it does.
Reconcile with the dashboard
Reconcile with the dashboard
Periodically cross-check your local order states against the RohoPay transaction list. The dashboard’s Reconciliation feature can help identify mismatches.
Order Status vs. Transaction Status
RohoPay distinguishes between:- Transaction status (
pending/successful/failed) — the payment layer - Order status (for Digital Products:
pending/paid/delivered/failed) — your fulfillment layer
| Transaction | → | Your Order |
|---|---|---|
pending | awaiting_payment | |
successful | paid → trigger fulfillment | |
failed | payment_failed |