Transaction Lifecycle
Both STK Push and B2C payout transactions follow the same set of states, though they
progress through them differently. Understanding the lifecycle helps you build reliable
integrations that handle all outcomes correctly.
Transaction states
| Status | Description |
|---|
PENDING | Initial state. Awaiting customer action (STK) or provider acceptance (B2C). |
PROCESSING | Provider accepted the request. Final confirmation pending. |
SUCCESS | Transaction completed successfully. Funds moved. |
FAILED | Transaction failed — provider declined, timeout, or customer cancelled. |
REVERSED | Funds previously charged to B2C wallet were credited back after failure. |
CANCELLED | Cancelled before processing began. |
Terminal states (no further updates): SUCCESS, FAILED, REVERSED, CANCELLED
STK Push lifecycle
POST /payments/stk
│
▼
PENDING ──── Customer receives phone prompt ──── Customer cancels
│ │
Customer enters PIN FAILED / CANCELLED
│
▼
PROCESSING ──── Provider processing ──── Provider timeout / error
│ │
M-Pesa confirms FAILED
│
▼
SUCCESS
Typical completion time: 30–90 seconds after the customer enters their PIN.
What happens on failure:
- The service fee deducted when you initiated the STK Push is not refunded.
- Your application should handle
FAILED and CANCELLED states as separate cases.
- The customer is never charged on failure.
B2C payout lifecycle
POST /b2c/payouts
│
▼
PENDING ──── Queued for processing
│
▼
PROCESSING ──── Provider sends to M-Pesa ──── Provider error / timeout
│ │
M-Pesa confirms FAILED
│ │
▼ REVERSED
SUCCESS (B2C wallet credited back)
Typical completion time: 30 seconds to 5 minutes.
What happens on failure:
- The B2C wallet balance debited on initiation is automatically reversed.
- The service fee is not refunded.
- Your webhook receives the
FAILED state with a result_code from M-Pesa.
Receiving state updates
Webhooks (recommended)
Supply a callbackUrl on every payment request. PalPluss delivers POST requests to
that URL whenever the transaction reaches a terminal state.
See the Webhooks guide for payload structure and retry policy.
Polling
If you cannot use webhooks, poll GET /transactions/{id} at intervals:
curl https://api.palpluss.com/v1/transactions/{transactionId} \
-u "$PALPLUSS_API_KEY:"
Poll at reasonable intervals — every 5–10 seconds is sufficient. Aggressive polling
consumes your rate limit (60 requests/minute) and delays results for other requests.
Recommended polling strategy:
- Poll at 5 seconds after initiation.
- If still
PENDING or PROCESSING, poll every 10 seconds.
- Stop polling when a terminal state is reached (
SUCCESS, FAILED, REVERSED, CANCELLED).
- Treat transactions still in
PENDING after 5 minutes as likely failed — re-confirm with support if needed.
Idempotency
STK Push requests do not support client-supplied idempotency keys. However:
- Each
POST /payments/stk creates a distinct transaction and a distinct provider checkout.
- If the same customer confirms multiple prompts (e.g. from retries), multiple
SUCCESS transactions will result.
- Prevent duplicate charges in your application before calling the API again.
Service wallet top-ups (POST /wallets/service/topups) support the Idempotency-Key
header to safely retry without creating duplicate top-ups.