collection_mode.
Mode per operator (Cameroon)
The request is identical in both modes: same endpoint, same fields. Only the response and the player experience differ. Collection modes apply to deposits only; withdrawals work the same way for every operator.
Side by side
Merchant-initiated flow
1
Create the deposit
Call
POST /api/v1/deposits. The response has collection_mode: "merchant_initiated" and instructions: null.2
The player receives a payment request
winam-payments sends the request to the number given in
msisdn. Tell the player to check their phone and enter their Mobile Money PIN.3
Wait for the outcome
Wait for the webhook on your
callback_url, or poll GET /api/v1/transactions/{winam_tx_id}.status: "failed", the operator rejected the request at initiation (invalid number, amount below the operator minimum…). Read state_reason from GET /api/v1/transactions/{winam_tx_id} and let the player retry with a new reference.
Customer-initiated flow
1
Create the deposit
Call
POST /api/v1/deposits, optionally with lang (fr default, or en). The response has collection_mode: "customer_initiated", status: "pending" and an instructions object.2
Display the instructions
Show
instructions.steps in order, the code instructions.ussd_string, a Dial button that opens instructions.dial_uri and a Copy button that copies instructions.copy_text.3
The player pays from their phone
The player dials the code from the number given in
msisdn and confirms with their Mobile Money secret code. Nothing is sent to their phone by winam-payments.4
Wait for the outcome
Poll
GET /api/v1/transactions/{winam_tx_id} every instructions.polling_interval_seconds seconds, or wait for the webhook. The deposit stays pending until the payment is confirmed.What to display
Rules that decide whether a payment is credited
The payment is matched to the deposit using the paying number and the exact amount.- Paying number. The player must pay from the number sent in
msisdn. A payment made from another number is not matched to this deposit. - Exact amount. The player must not change the amount in the code. A payment of a different amount is not matched.
- One player per number and amount. If deposits from two different
player_idvalues are open (or expired recently) for the same number and the same amount, an incoming payment is not credited automatically. - Several deposits from the same player. One payment completes exactly one deposit. Prefer returning the existing
pendingdeposit to the player over creating a new one for the same number and amount.
The player’s Mobile Money secret code is typed on their phone only. Never ask for it, transmit it or store it.
Late payments
The player can pay afterexpires_at. You then receive payment.expired, and later payment.succeeded for the same winam_tx_id when the payment arrives within the late-payment window (24 hours by default) and matches the deposit. Your webhook handler must accept payment.succeeded on a transaction it already saw as expired, and credit the player.
When the channel is unavailable
POST /api/v1/deposits answers 503 and creates no transaction when the channel cannot confirm payments at the moment. Offer another payment method or let the player retry later. GET /api/v1/{country}/providers/status reports the provider as degraded or unavailable.
Handling both modes
payment.succeeded, payment.failed or payment.expired webhook, and the state returned by GET /api/v1/transactions/{winam_tx_id}.
Integration checklist
- Branch on
collection_mode, not onoperator. - Render
instructionswhen present: code, Dial, Copy, steps. - Tell the player to pay from the number they entered and not to change the amount.
- Keep the deposit screen open while
pendingand poll, or rely on the webhook. - Accept
payment.succeededafterpayment.expiredfor the samewinam_tx_id. - Handle
503on creation by offering another payment method. - Reuse the same
referencewhen retrying the same payment: the same transaction and instructions are returned.

