Skip to content

Hosted Checkout

The page Wajub renders for your customer, what it handles, and what you control.

Hosted Checkout is the shortest path to a working payment. You create the payment, send the customer to the page Wajub renders, and verify the outcome when they come back.

What your customer sees: the amount, the operators available in their country, and the prompt waiting for confirmation on their handset. You render none of it.

The integration code

The code for a redirect, an inline frame or an overlay is in Wajub Components → Hosted checkout.

Create the payment

Everything the page needs comes from the create call. Send it from your server with the secret key: the public key also creates payments, but it exists for the case where the call is made in a browser.

POSThttps://api.wajub.com/payments
amountnumberrequired
Amount in the major unit of the currency. Decimals are accepted, so 10.50 is ten dollars fifty. In XAF and XOF the payment must fall between 25 and 2 000 000.
currencystringrequired
ISO 4217 code: XAF, XOF, NGN, GHS, KES and the rest of the supported list.
customerobjectoptional
Payer identity: email, phone, name, plus address and metadata. At least one of customer, email, phone or customer_id is required, and the object is the form that grows with you.
descriptionstringoptional
A single label shown to the customer on the page. Defaults to "Payment".
itemsarrayoptional
Line items displayed on the page, each with a name, a description and a quantity. They are shown, never summed: amount remains what you charge.
callbackstring (url)optional
Where the customer is sent afterwards, whatever the outcome: success, failure, cancellation or expiry, told apart by status in the query string. Must be HTTPS, and http://localhost or http://127.0.0.1 are accepted in sandbox; any other address answers 422. Omit it and they stay on a Wajub confirmation page, in which case the webhook is your only signal.
referencestringoptional
Your own order number. It comes back on every read and in the return URL. It carries no uniqueness constraint, so it is not what prevents a double charge.
expires.inintegeroptional
How long the page stays usable, in minutes, from 5 to 43 200. Defaults to 1 440, which is 24 hours.
bearerstringoptional
Who pays the Wajub fee: merchant by default, or customer, which adds the fee on top and shows the breakdown on the page.
acceptobjectoptional
Narrows the payment methods offered, by countries, channels, types and currencies. Omit it and every method you can collect on is shown. See [Choosing what a payment accepts](/payments/payment-methods#choosing-what-a-payment-accepts).
metadataobjectoptional
Free key-value pairs, returned on reads and in webhooks.

A create call that uses the hosted page's own fields looks like this:

curl https://api.wajub.com/payments \
  -H "Authorization: sk_test.xxxxxxxxxxxxxxxx…" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 25000,
    "currency": "XAF",
    "customer": { "email": "amina@example.com", "name": "Amina N." },
    "description": "Order #4172",
    "reference": "order-4172",
    "items": [
      { "name": "Wireless earbuds", "quantity": 1 },
      { "name": "Delivery", "quantity": 1 }
    ],
    "expires": { "in": 60 },
    "callback": "https://shop.example.com/order/complete"
  }'

The response carries the payment and the page to send the customer to. Store transaction.id against your order before you redirect:

Response · 201 Created
{
"code": 201,
"status": "Created",
"message": "Payment initiated",
"authorization_url": "https://pay.wajub.com/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"authorization_token": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"transaction": {
"id": "trx_test_CSUGajfv9xh0XQ5wu2lx",
"reference": "order-4172",
"amount": 25000,
"currency": "XAF",
"status": "pending",
"sandbox": true,
"created_at": "2026-09-11T10:24:00+00:00"
}
}

authorization_url carries an opaque session token, not the transaction id. Redirect to it exactly as returned: never parse it, and never build one yourself. The host is not always pay.wajub.com either, since an account on the Scale plan can serve its checkout from its own verified domain.

What the page decides on its own

The customer sees only the methods that can take this payment, not a fixed list.

Mobile Money caps a single debit at 500 000 XAF, and the same in XOF. A payment above that is refused, and the page asks the payer for a smaller amount or another method.

If you set bearer to customer, the page shows the fee on top of your amount and the total actually being debited.

The language is English or French. It follows the Checkout — Language setting, which accepts auto, en or fr. On auto, the page uses the customer's own preferred_language, and opens in French when the customer has none.

Handle the return

Once the attempt is over, the customer comes back to your callback with the payment identified in the query string:

Return redirect
https://shop.example.com/order/complete?reference=trx_test_CSUGajfv9xh0XQ5wu2lx&status=succeeded&trxref=order-4172

reference is the Wajub payment id and trxref is the reference you sent, present only when you set one. Both come back whatever the outcome. status is succeeded, failed, cancelled or expired. After a success the page sends the customer on by itself; after a failure or an expiry, when they choose to come back. A customer who closes the page without finishing never comes back at all.

The verification call takes the id you stored before redirecting:

curl https://api.wajub.com/payments/trx_test_CSUGajfv9xh0XQ5wu2lx \
  -H "Authorization: sk_test.xxxxxxxxxxxxxxxx…"

Check the amount and the currency as well as the status, and let the webhook close the orders whose customer never came back.

Make the page yours

The look of the page is set once for the whole account, in Settings → Branding, and applies to every payment page you ever create, in sandbox as in production.

What you setWhere it shows
Rectangular logo, square logo, faviconThe header of the page and the browser tab
Primary, secondary and background coloursButtons, links and the page surface
Text and button text coloursContrast against your own palette
Success and error coloursThe confirmation and the failure states
Font and border radiusThe whole page
Appearance modesystem, light or dark
Density and cover styleHow tight the layout is, and how the header is framed

Branding needs a paid plan

Settings → Branding needs the Design Customization feature, which starts at Growth. On Pay as you go the payment page keeps the default appearance. Serving the checkout from your own domain is a separate feature, Custom domain, that starts at Scale.

You can also collect information the payment itself does not carry, a delivery note or a table number, by adding fields in Settings → Collect. Each field has a type among text, textarea, select, checkbox, number, email and tel, a label, an optional placeholder, and a required flag. They appear on the hosted page in the order you arrange them.

What did you think of this content?