Skip to main content

Direct Charge (Complete Flow)

This guide shows you how to go from creating a payment → completing it → verifying it.

If you follow this exactly, your integration will work.

⚠️ Important

  • A payment is NOT successful until confirmed
  • Always use webhooks OR transaction status to verify final state
  • The initial API response only tells you what to do next

Step 1: Create a Payment

Send a request to initiate the charge.

curl -X POST "https://api.modempay.com/h2h/v1/payments" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": {
"amount": 10,
"network": "afrimoney",
"account_number": "7012345"
}
}'

Step 2: Handle the Response

You will receive a response like this:

{
"transactionId": "cos-212q2mbrg8z6m",
"next_step": {
"requiresAuthorization": true,
"auth_mode": "confirm",
"openExternal": true,
"launch_url": "https://pay.wave.com/..."
},
"payment_intent_id": "8178ffbf..."
}

Now follow the correct path based on next_step.

Step 3: Complete the Payment (3 Possible Flows)

✅ Case 1: External Authorization (Wave, etc)

"openExternal": true

👉 Action:

  • Redirect user to launch_url
  • User completes payment externally

👉 Next:

  • Wait for webhook or check status

❗ Do NOT call confirm endpoint

✅ Case 2: Manual Confirmation (Afrimoney, USSD)

"auth_mode": "confirm",
"openExternal": false

👉 Action:

  • Show instructions to user (confirmation_steps)
  • Ask user to confirm after completing payment

👉 Then call:

POST /payments/confirm/:transactionId

👉 Next:

  • Wait for webhook or check status

✅ Case 3: PIN / OTP Required (Qmoney|APS)

"auth_mode": "pin"

👉 Action:

  • Collect PIN/OTP from user

👉 Then call:

POST /payments/finalize/:transactionId
{
"pin": "123456"
}

👉 Response will contain updated payment status

Step 4: Verify Payment Status (CRITICAL)

This is where most integrations fail.

  • Listen for payment updates
  • Mark payment as successful only when status = completed

✅ Option 2: Polling

GET /transactions/:transactionId

Check:

"status": "completed"

Payment Status Values

StatusMeaning
pendingPayment initiated
processingIn progress
completed✅ SUCCESS
failed❌ Failed
cancelledUser cancelled
abandonedUser did nothing

Full Flow Summary

  1. Create payment

  2. Check next_step

  3. Follow correct flow:

    • Redirect → external
    • Confirm → manual
    • Finalize → PIN
  4. Wait for webhook OR poll

  5. Only mark success when status = completed