Skip to content

Wajub.js

The core browser package, what it loads, what it exports, how to call it.

@wajub/js is the package every Wajub checkout runs on. The React, Vue and Svelte packages are wrappers around it, and this page covers the core alone: what it loads, what it exports, and the three ways to reach the same API.

@wajub/js

Stable · GA

npm + CDN

Version
1.4.0
Runtime
Any modern browser (ES2020+)

Covers

  • Payments
  • Payment Links

Not in this package: Billing, Transfers, Sync, Shield, Tax.

The npm package is a loader, not the runtime

Installing @wajub/js does not put the checkout in your bundle. The package is a small loader that fetches the real runtime from https://js.wajub.com the first time you call it.

What you installSizeWhat it holds
@wajub/js from npmAbout 11 KBThe loader, the types, the exported helpers
https://js.wajub.comAbout 168 KBThe checkout itself, iframes, payment methods, states

Three entry points

They deliver the same API. What changes is when the runtime is fetched and whether you need a bundler.

Entry pointFetches the runtimeUse it when
@wajub/jsOn importYou have a bundler and the page always shows a checkout
@wajub/js/pureOnly when you call loadWajub()You render on the server, or the checkout is behind a click
https://js.wajub.comOn script loadNo bundler, plain HTML

Install the package with your usual manager. It ships as an ES module only, so a CommonJS require() will not resolve it.

npm install @wajub/js

Without a bundler, the script tag puts wajub, Wajub and WajubError on window. The .mjs build is the same runtime with named exports.

From the CDN
<script src="https://js.wajub.com"></script>

<!-- or, as a module -->
<script type="module">
  import { mount } from 'https://js.wajub.com/wajub.mjs';
</script>

Three ways to call the same API

Every method below exists in all three forms. Pick one per project and stay on it, because mixing them makes the loading order hard to read.

The named helpers are the shortest. Each one loads the runtime by itself and awaits it.

Named helpers
import { mount, open, checkout, fetchSession, confirmPayment } from '@wajub/js';

const instance = await mount('#checkout', { sessionId });

loadWajub() hands you the runtime instead, so the fetch happens where you decide. It returns null when there is no window, which is what makes a server render safe.

Holding the runtime
import { loadWajub } from '@wajub/js/pure';

const rt = await loadWajub();
if (rt) {
  const instance = await rt.wajub.mount('#checkout', { sessionId });
}

From the CDN, the same objects sit on window and there is nothing to await.

On the global
const instance = await wajub.mount('#checkout', { sessionId });

What the package exports

Three objects, one error class, and the helpers that mirror the runtime.

ExportWhat it is
loadWajub()Resolves to { wajub, Wajub, WajubError }, or null on the server
wajubThe runtime object, every method listed below
WajubThe client factory, bound to a key or a session
WajubErrorThe error class every rejection is an instance of
mount, open, checkout, components, confirmPaymentThe four modes, plus the fields submit
fetchSession, preloadRead a session, or warm the runtime before you need it
getVersion(), getCheckoutOrigin()The loaded runtime version and the origin it came from

preload() is the one worth knowing about: call it when the customer reaches the cart, and the runtime is already in cache when they reach the pay button.

The Wajub() client

The runtime methods all need a sessionId on every call. The client holds it once instead, and it is the only way to create a payment from the browser.

Three ways to build one
const client = Wajub('pk.mT9xW2kQ7vB4nL6hR1cY8dF3jS5aG0eU2pA…');

const client = Wajub.session(sessionId);

const client = Wajub({ publishableKey: 'pk.mT9xW2kQ…', sessionId });
MethodWhat it does
createPayment(params)POST /payments with the publishable key, returns the session
useSession(sessionId)Binds an existing token to the client
fetchSession()Amount, currency, merchant name, methods, saved methods, feature flags
preload()Fetches the runtime before it is needed
mount(el, config), open(config), checkout(config)The three hosted modes
components(config)The fields factory
confirmPayment(options)Submits a field component and waits for the outcome
initCheckout(options)Creates the payment and mounts it in one call

initCheckout is the whole flow without a backend. It needs a publishable key, because the amount is decided by the page.

Create and mount in one call
await Wajub('pk.mT9xW2kQ7vB4nL6hR1cY8dF3jS5aG0eU2pA…').initCheckout({
  mode: 'inline',
  container: '#checkout',
  payment: { amount: 35000, currency: 'XOF', customer: { email: 'buyer@example.com' } },
  onSuccess: (transaction) => console.log('paid', transaction),
});

On the server

loadWajub() and every helper return null when there is no window, so a server render never throws. The difference is the import itself: @wajub/js fetches the script as a side effect of being imported, @wajub/js/pure does nothing until you call it.

No side effect on import
import { loadWajub } from '@wajub/js/pure';

payButton.addEventListener('click', async () => {
  const rt = await loadWajub();
  await rt?.wajub.open({ sessionId });
});

The three framework packages already import from /pure for you. This matters when you wire the core yourself.

Where each subject is documented

This page stops at the package. Everything the runtime does has its own page.

You want toRead
Mount, open or redirect, with every option and callbackHosted checkout
Build your own layout around the fieldsPayment fields
Create the session, and what the token may doSessions and security
Change colours, theme, locale and layoutAppearance
Read every method, type and checkout stateAPI reference
Type it correctly, with or without npmTypeScript
Work out why nothing rendersTroubleshooting

What did you think of this content?