Skip to main content
Use this path when you want full control of the payment screen. If you don’t need that, the embedded checkout does all of this for you.
All calls on this page use your secret key, so they run on your server. Your frontend talks only to your own backend.

Overview

1. Create the ugwo

When the customer reaches your payment step, create an ugwo for the order and keep its uid with the order.
Node
The examples on this page use this small helper:
Node

2. Show the available mediums

ugwo.checkout.mediums lists what the customer can use, in the order you configured. For ussd and pay_with_bank, also fetch the banks they can choose from:
Node
Send the chosen id as provider. Cache the list for a few minutes; it only changes when you change PSPs or routing.

3. Charge with the chosen medium

Node
Full rules: Charge an ugwo.

4. Render the next action

If activity.status is requires_action, render activity.next_action.action by its type:
Node
See The Next action object for every field.

5. Submit customer input

For input_* actions, send what the customer typed straight to Kwugwo. Don’t log or store it.
Node
For input_otp with supports_resend: true, send { "otp": null } to resend the code.

6. Wait for the result

Payment completes asynchronously. Listen for webhooks on your server: To update the customer’s screen in real time, push these from your server to the browser (WebSocket, SSE), or have the page poll your backend, which reads Get an activity, every few seconds.

7. Retry after a failure

If the attempt fails or expires, start a new activity on the same ugwo, with the same or a different medium. Read activity.error.type to decide what to tell the customer: You don’t have to wait for an attempt to expire: if the customer changes their mind (say from bank transfer to USSD), create a new activity straight away. Stop showing the old instructions, since a customer who completes both attempts is double charged. Once the ugwo is paid, new attempts return 409 already_processed. If creating the activity itself fails with 503 payment_routing_error, no PSP could take the charge right now. Nothing was created and the ugwo is still requires_ugwo: let the customer retry in a moment or pick another medium.