Skip to main content

Transaction Lifecycle

Payments should not be a black box. Know exactly where every transaction is at all times. Both STK Push and B2C payouts share the same state model. Understanding the lifecycle lets you handle every outcome correctly — including failures.

Transaction states

StatusWhat it means
PENDINGRequest accepted. Waiting for customer action (STK) or provider acceptance (B2C).
PROCESSINGProvider accepted. Final confirmation pending.
SUCCESSComplete. Funds moved.
FAILEDFailed — provider declined, timeout, or customer cancelled.
REVERSEDB2C wallet balance credited back after failure.
CANCELLEDCancelled 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: 30–90 seconds after the customer enters their PIN.
StateWhat to do
PENDINGRequest sent. Wait for the customer to act.
PROCESSINGPIN entered. Wait for M-Pesa confirmation.
SUCCESSFulfil the order.
FAILEDNotify the customer. Service fee is not refunded.
CANCELLEDCustomer dismissed the prompt. Retry if appropriate.

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 balance credited back)
Typical completion: 30 seconds to 5 minutes.
StateWhat to do
PENDINGRequest queued. No action needed.
PROCESSINGProvider accepted. Wait for M-Pesa.
SUCCESSPayout delivered.
FAILEDB2C wallet reversal is automatic. Retry when ready.
REVERSEDWallet credited. Safe to retry the payout.

Receiving state updates

Supply a callbackUrl on every payment request. PalPluss delivers a POST to that URL when the transaction reaches a terminal state. See the Webhooks guide for payload structure and retry policy.

Polling

Poll GET /transactions/{id} if webhooks are unavailable.
curl https://api.palpluss.com/v1/transactions/{transactionId} \
  -u "$PALPLUSS_API_KEY:"
Recommended polling intervals:
  1. Wait 15 seconds after initiation.
  2. Poll every 10 seconds while status is PENDING or PROCESSING.
  3. Stop at any terminal state.
  4. After 5 minutes without a terminal state, treat the transaction as likely failed.
Aggressive polling consumes your rate limit (60 requests/minute). Use webhooks as your primary mechanism.

Idempotency

  • Each POST /payments/stk creates a distinct transaction and a distinct M-Pesa checkout.
  • Retrying without customer action sends a new prompt — do not retry unless the customer requests it.
  • Service wallet top-ups support the Idempotency-Key header to prevent duplicate funding requests.