Skip to content

Choose your integration

The four ways to take a payment, compared on control, code and constraints.

Every payment starts the same way, with POST /payments. What separates the four integration modes is who renders the screen where the customer confirms, and whether the charge call is yours to make or ours.

Pick on that question alone. The operators you reach, the webhooks you receive and the refunds you can issue are identical across the four, so nothing you choose here limits what you can do later.

The decision in one table

ModeWho renders the payment screenWhat you writeBest for
Hosted CheckoutWajub, on its own pageA redirect and a return handlerShipping quickly, on any stack
Embedded ComponentsWajub, inside your pageA server route plus the browser SDKStaying on your domain, with your branding
Payment LinksWajub, on its own pageNothingSelling without a site or a server
Direct APIYouThe entire payment interfaceNative apps and custom flows

What the create response hands you

Creating a payment charges nobody. It records the intent, holds it pending and answers with two fields. Which one you use is what your integration mode decides.

authorization_urlstringoptional
**Hosted Checkout.** The full URL of the Wajub-hosted payment page. Redirect your customer there. An opaque session URL: never parse it or build one yourself.
authorization_tokenstringoptional
**Embedded Components.** A browser-safe session token scoped to this payment. Pass it as sessionId to wajub.mount(). It works on every call of the payment page until the payment is final, then for 5 more minutes after a success and 1 minute after a failure. It is returned on creation only, never on a later retrieval.

In code, the whole difference between the two modes is one line:

Which field each mode uses
// Hosted Checkout: send the customer to the page Wajub renders.
res.redirect(payment.authorization_url);

// Embedded Components: hand the token to the browser and mount in place.
wajub.mount('#checkout', { sessionId: payment.authorization_token });

Direct API uses neither to take the payment. It makes a second call instead, covered further down, and needs the token only when a provider asks the payer for a code.

Hosted Checkout

Your server creates the payment and redirects to authorization_url. The customer picks an operator, enters their number and confirms on their handset, then lands back on your callback. Wajub sends the webhook in parallel, so the outcome reaches you even if the customer closes the tab on the way back.

You write two things: the route that creates the payment, and the handler that verifies it before fulfilling the order. Everything the customer sees, the operator list, the retry when a prompt times out, the wording of each failure, belongs to Wajub and stays up to date without you touching it.

The page carries your logo and your colours, set once in the Dashboard under Settings › Branding, from the Growth plan. It is the mode we recommend, and the one the Payments Quickstart walks through.

Embedded Components

The same checkout, mounted inside your own layout. Your server creates the payment and passes authorization_token to the browser, which calls wajub.mount() with it as sessionId. The customer never leaves your domain.

You write a server route and a few lines of front-end code. What you do not write is the payment interface itself: Mobile Money, cards, OTP and 3DS all come from the mounted component, and you supply the wrapper around it.

When the components show on your checkout before the order exists, while the cart can still change, create the payment with deferred: true. It is only prepared: it stays out of your payments and sends no payment.* webhook. Your server changes its amount with PATCH /payments/{id} when the total moves, then activates it with POST /payments/{id}/activate once the order is placed, from the component's onBeforeSubmit. Before the order exists walks through it.

There is a vanilla JavaScript package and React, Vue, Svelte and Angular wrappers. The Components overview compares its four modes; start with the Components quickstart, then the framework page that matches your stack.

A shareable URL, or the QR code generated from it. You create it from the Dashboard or with one API call, send it by WhatsApp, SMS or email, and the customer pays on a Wajub page. There is no server code at any point.

Two limits are worth knowing before you plan around it. Payment Links are production only, the sandbox has no equivalent, and the Pay as you go plan allows 25 links. See Payment Links for what a link can carry and how to track what it collects.

Direct API

You collect the phone number yourself, then charge with a second call, POST /payments/{id}, passing a channel such as cm.mtn and the payment details. The operator prompt goes out to the customer's handset and you render every screen around it, including the waiting state and the result. Direct API walks through the call and every answer it can get.

Cards are the exception. Live refuses raw card data on this call, so a card is collected by Hosted Checkout, the components or a mobile SDK, which pass it to the payment provider's secure fields.

This is the only mode where the payment interface is entirely yours, which is why it exists for native mobile apps and for flows no hosted page can express. It is also the only mode where a mistake is yours to catch.

Still unsure

Start with Hosted Checkout. It is the shortest path to a payment that works, and moving to Embedded Components later changes only your front end: the create call, the webhook handling and the verification stay exactly as they are.

Go to Payment Links instead if you have no site to integrate into, and to Direct API only when you have looked at Embedded Components and found something it genuinely cannot render.

What did you think of this content?