Skip to content
SkanPay Docs

Transaction statuses

Charges, payouts, deposits and withdrawals all move through the same small set of statuses.

Lifecycle
INITIATED ─▶ PENDING_PROVIDER ─▶ AWAITING_CUSTOMER ─▶ SUCCESSFUL ─▶ REVERSED
                    │                    │
                    └────────────────────┴──────▶ FAILED
StatusMeaningFinal?
INITIATEDReceived. You will rarely see it, except on a withdrawal waiting for a second approver.No
PENDING_PROVIDERHanded to the mobile money network; waiting for its first answer.No
AWAITING_CUSTOMERThe prompt is on the customer's phone, or the network is still working on it.No
SUCCESSFULThe money moved.Yes, unless later reversed
FAILEDThe money did not move. failure_code says why.Yes
REVERSEDA successful charge was clawed back.Yes

Out-of-order and duplicate updates

Networks can report the same outcome twice, or report it late. SkanPay records every report in the transaction's timeline, but a final status never changes afterwards except SUCCESSFUL → REVERSED. A late “pending” after “successful” is recorded and ignored; it never moves money. Apply the same rule in your own system: never let an update move an order backwards.

Failure codes

A charge that reaches the network but does not go through is not an HTTP error. It is a FAILED transaction with a failure_code and a human-readable failure_message. Show the customer a message based on the code, not the raw message.

failure_codeMeaningSuggested handling
insufficient_fundsThe wallet does not have enough balance.Ask the customer to top up and try again.
customer_declinedThe customer rejected the prompt.Offer to try again.
customer_unreachableThe handset could not be reached (off, out of coverage).Ask the customer to check their phone and retry.
wallet_not_foundThere is no mobile money wallet on that number.Check the number and the network.
wallet_limit_exceededThe payment would exceed the customer's own telco limit.Try a smaller amount.
wallet_inactiveThe wallet exists but is not active.The customer must contact their network.
invalid_msisdnThe network rejected the number.Check the number.
expiredNo answer arrived in time (about 30 minutes).Treat as not paid. A new attempt needs a new charge.
provider_rejectedThe rail refused the request outright.Retry later with a new Idempotency-Key; contact support if it persists.
provider_unavailableThe rail was down.Retry later.
unknownThe rail failed the payment without giving a reason.Treat as not paid.

Withdrawals can also fail with approval_rejected when a team member rejects them in the dashboard. Treat any code you do not recognise like unknown: new codes may be added.

Who reported each change

The timeline (GET /v1/transactions/:id) shows every status event with a source:

sourceMeaning
APISet while handling your request.
PROVIDER_CALLBACKThe network told SkanPay.
POLLSkanPay asked the network.
RECONCILIATIONDecided by the reconciliation job, for example an expiry.
ADMINResolved by SkanPay staff, always with a recorded reason.