Skip to main content
Waftpay Checkout is a hosted payment page. You create a checkout session from your server, send your customer to the page we host, and we handle the payment experience — mobile money (M-PESA STK & paybill), bank/PesaLink, partial payments, retries, and session expiry. Card and payment details never touch your site. There are two ways to bring the customer to it:

Redirect (this guide)

Send the browser to the checkout_url we return. Simplest to ship. The customer pays on checkout.waftpay.io and is redirected back to you.

Embedded overlay

Keep the customer on your page. Our loader script opens the checkout in an overlay and gives you JavaScript callbacks (onSuccess, onFailure, …).
Either way, you never build the payment UI. You only (1) create the session server-side and (2) place the customer in front of our page.See it working end to end in the WaftStore demo → — a sample store that creates a session and hands off to this checkout page.

How it works

1

Authenticate (server-side)

Get a product-scoped Bearer token from Get Authentication Token. Cache it and refresh only on expiry. Your consumer_key/consumer_secret stay on your server — never in the browser.
2

Create a checkout request (server-side)

Call Create Checkout Request with the customer, amount, and your redirect + callback URLs. You get back a checkout_url and expires_at.
3

Send the customer to the page

Redirect the browser to checkout_url (or use the embedded overlay).
4

Receive the callback (source of truth)

Waftpay POSTs the final result to your callback_url. Use this — not the browser redirect — to fulfil the order.
5

Handle the return redirect

We send the customer back to your success_redirect_url or fail_redirect_url for the on-screen outcome.

Prerequisites


1. Create the checkout request

Do this on your server — it uses your secret Bearer token.
Required headers
Request body (example)
See the full field reference. The fields that most affect behaviour:
  • checkout_reference — must be unique per request.
  • extra_params.expiry — optional; a default is applied if omitted.
  • extra_params.strict_amount — true requires full payment; false lets the customer pay in parts.
Response (accepted)
The last path segment of checkout_url is the request token for this session. You pass the whole checkout_url to redirect, or just the token to the embedded overlay. Generate it on your server — never in the browser.

On your server (example)

This is the merchant’s entire integration — the same on your server whether you then redirect or embed. Re-price the cart from your own catalogue (never trust client totals), cache the Bearer token, create the request, and return the checkout_url and token to the browser. This mirrors the WaftStore demo’s POST /api/checkout route.
getWaftpayToken() exchanges consumer_key + consumer_secret at Get Authentication Token for a short-lived Bearer token, caches it in memory, and refreshes ~60s before expiry (retrying once if a cached token is rejected).

2. Send the customer to the page

Redirect the browser to the checkout_url:
That’s it — Waftpay renders the page, shows your business name and the amount, lists the payment methods enabled for your account, runs a countdown against the session expiry, and (when strict_amount is false) lets the customer settle the balance in parts. Prefer to keep the customer on your own page? Use the embedded overlay instead of redirecting.

3. Receive the callback (source of truth)

When the payment resolves, Waftpay POSTs the final result to your callback_url. Fulfil the order from this callback, not from the browser redirect (a customer can close the tab before returning).
  • results.checkout_status — FULLY_PAID, PARTIALLY_PAID, or FAILED.
  • results.payments[] — one entry per payment (more than one if the customer paid in parts).
  • results.metadata — your meta_data, echoed back as a JSON string.
Verify the signature and respond 200 quickly. See Verify signature and Retries & idempotency.

4. Handle the return redirect

After paying, the customer lands on your success_redirect_url or fail_redirect_url. Use these pages for the on-screen message only; confirm fulfilment from the callback. If you need to double-check a specific order, use status checks.

Testing

Use the sandbox base URL https://dev.waftpay.io and a tool like webhook.site for your callback_url while developing. See Environments.