Payment Statuses
Status values
| Status | Applies to | Meaning |
|---|---|---|
PENDING | Collection | Created, but the customer has not acted yet: the push is waiting for a PIN, or a link has not been opened. |
PROCESSING | Both | Dispatch is in flight inside MALIPOPAY. |
PROCESSED | Both | Handed to the operator, who accepted it and will call back with the final outcome. |
AWAITING_APPROVAL | Payout | Created and waiting for approval. No money has moved. |
APPROVED | Payout | Approved and debited from your wallet; being dispatched. |
SUCCESSFUL | Both | Completed. Money has moved. |
PARTIAL | Collection | Some of the amount has been paid. Compare paidAmount with amount. |
PAID | Collection | The requested amount has been received in full. |
FAILED | Both | Could not complete. failureReason says why. A failed payout is refunded automatically. |
CUSTOMER_REJECTED | Collection | The customer declined the prompt. |
REJECTED | Both | Rejected by MALIPOPAY or the operator before reaching the customer. |
CANCELLED | Both | Cancelled before completion. |
Treat SUCCESSFUL, PAID, FAILED, REJECTED, CUSTOMER_REJECTED and CANCELLED as terminal. Anything else can still change.
Collection flow
PENDING → PROCESSING → PROCESSED → SUCCESSFUL / PAID
↘ PARTIAL
↘ FAILED
↘ CUSTOMER_REJECTED
↘ CANCELLED
Disbursement flow
AWAITING_APPROVAL → APPROVED → PROCESSING → SUCCESSFUL
↘ FAILED (balance refunded)
A payout never skips AWAITING_APPROVAL. If you are waiting for a payout that never arrives, check that it was approved before you look at anything else. See Payment Disbursement Flow.
Which transitions fire a webhook
Not every status change notifies you. Only the outcomes do:
| Event | Fired when |
|---|---|
payment.confirmed | A collection reaches SUCCESSFUL, PAID or PARTIAL |
payment.failed | A collection reaches FAILED, REJECTED, CANCELLED or expires |
payment.refunded | A collection is refunded or reversed |
payout.approved | A payout reaches APPROVED |
payout.confirmed | A payout reaches SUCCESSFUL |
payout.failed | A payout fails |
PROCESSING and the initial creation fire nothing. Do not build a state machine that waits for an "in progress" webhook, because none is coming.
Polling vs webhooks
Use webhooks. If you must poll, use GET /api/v1/payment/reference/{reference}, no more than once every 10 seconds, and stop after 5 minutes. A collection that has not resolved within the 90-second USSD window is not going to resolve because you asked again.