Skip to content

SDK reference

Every export, option, method, type, state and error code of @wajub/js.

Every export, option, method, type, state and error code of @wajub/js. The guide pages explain when to use each piece.

Two ways to reach the same API

The runtime is one object. You either import helpers that load it for you, or you hold it yourself.

Helpers, or the runtime
import { mount, open, checkout, components, confirmPayment } from '@wajub/js';

import { loadWajub } from '@wajub/js/pure';
const rt = await loadWajub();
rt?.wajub.mount('#checkout', { sessionId });
Export from @wajub/jsReturnsNotes
mount(container, config)Promise<CheckoutInstance | null>null on the server
open(config)Promise<PopupInstance | null>null on the server
checkout(config)Promise<void | null>Redirects the page
components(sessionId, options?)Promise<ComponentsFactory | null>null on the server
confirmPayment(options)Promise<{ status, transaction? }>Rejects with WajubError
fetchSession(sessionId)Promise<SessionPreview>Works before anything is mounted
signals()Promise<ClientSignals>Device signals for a charge from your server, see Shield
preload(sessionId, options?)Promise<void | null>Gets the checkout ready before the payer reaches it. { iframe: true } also loads that session's checkout
appearanceFrom(container, source?)Promise<AppearanceConfig | null>What appearance.inherit would read for a component in container. null on the server
componentReserveHeight(type, variant?, fields?)numberThe room loader: 'skeleton' holds, in px
componentEstimatedHeight(type, variant?, fields?)numberThe same room as an estimate, identical on the server and in the browser: hold it in a server render and its hydration
getVersion()Promise<string | null>The loaded runtime version
loadWajub()Promise<WajubRuntime | null>null on the server
WajubErrorDeclared in the types onlyNot exported at runtime, read it from loadWajub()

WajubRuntime

What loadWajub() resolves to, and what the script tag puts on window.

MemberWhat it is
wajubThe SDK object, the table below
WajubThe client factory
WajubErrorThe error class

wajub

MemberSignature
mount(container, config) => CheckoutInstance
open(config) => PopupInstance
checkout(config) => void
components(sessionId, options?) => ComponentsFactory
confirmPayment(options) => Promise<{ status }>
fetchSession(sessionId) => Promise<SessionPreview>
signals() => Promise<ClientSignals>
preload(sessionId, options?) => void
appearanceFrom(container, source?) => AppearanceConfig. {} when there is nothing to read, never throws
componentReserveHeight(type, variant?, fields?) => number. The room loader: 'skeleton' holds, in px
createThe Wajub factory, same object
versionThe runtime version string

These are synchronous once you hold the runtime.

Wajub() client

A client holds a publishable key, a session, or both, so you stop repeating them.

CallWhat you get
Wajub('pk_test.…')A client that can createPayment()
Wajub.session(token)A client bound to an existing session
Wajub({ publishableKey, sessionId })Both at once
OptionWhat it does
sessionIdThe authorization_token from your server
publishableKeyYour publishable key, pk. or pk_test.

Client members

MemberWhat it does
publishableKey, sessionId, environmentWhat the client currently holds
useSession(sessionId)Binds another session, returns the client
createPayment(params)POST /payments with the publishable key
initCheckout(options)Creates the payment and shows it in one call
fetchSession(sessionId?)Session preview
signals()Device signals for a charge from your server, see Shield
preload(sessionId?, options?)Gets the checkout ready ahead of time
mount, open, checkoutThe three hosted modes, session already bound
components(sessionIdOrConfig?, config?)The fields factory
appearanceFrom(container, source?)What appearance.inherit would read
confirmPayment(options?)Submits a mounted component

Factory statics

MemberWhat it does
Wajub.session(sessionId, options?)A session bound client
Wajub.parsePublishableKey(key){ key, environment }, throws on a secret key
Wajub.createPayment(key, params, options?)One shot, no client to keep
Wajub.signals()Device signals for a charge from your server, see Shield

EmbeddedConfig

Used by mount(), by CheckoutEmbed in every framework, and as the base of PopupConfig.

OptionTypeDefault
sessionIdstringRequired
localestringSession default
layoutCheckoutLayoutSession default
appearanceAppearanceConfigYour Dashboard branding. inherit is read around the container for mount(), over the whole page for open()
loadingTextstringEmpty
showLoadingbooleantrue
CallbackReceives
onReadyCheckoutInstance
onSuccessPaymentSuccess
onErrorWajubError, a payment that failed, or nothing_to_submit when submit() had no button to press
onLoadErrorWajubError, a checkout that never started: session_not_found, session_terminal_expired or load_error. Right after it, the overlay closes or the inline checkout leaves the page, without onClose
onCancelNothing
onExpiredNothing
onStateChange{ state?: CheckoutState, method?: string }
onMethodChange{ methodId? }
onBreakdownEmbedBreakdown, { subtotal, discount, tax, total, currency } in major units
onResizeheight: number, inline only
onCloseNothing. The overlay was dismissed, or an inline checkout was ended by the payer's Done or by close()

PopupConfig

Everything in EmbeddedConfig, plus the modal.

OptionTypeDefault
widthnumber920
heightnumber680
closeOnOverlaybooleanfalse
closeOnEscapebooleantrue
closeOnSuccessbooleantrue
closeOnCancelbooleantrue
closeOnExpiredbooleantrue

The three closeOn outcome flags run after your callback, never before it.

CheckoutInstance and PopupInstance

MethodWhat it does
mount()Re-attaches after unmount(). Does nothing while mounted, or after destroy() or close()
unmount()Removes from the DOM, keeps the instance. On an overlay, onClose is not called
destroy()Full teardown. mount() no longer brings it back
update(partial)locale, appearance, currency, layout. appearance merges into the current one: a key given as undefined or null is cleared, and appearance: undefined or null clears it all. A new theme preset replaces the previous one
getState()The current CheckoutState
submit()Presses the pay button of the method the payer is on. With no button to press, nothing is pressed and onError receives nothing_to_submit
cancel()Cancels the payment in progress
retry()Retries after a failure
selectMethod(methodId)Switches payment method
close()Ends the checkout, inline or overlay, and calls onClose. destroy() ends it without a callback
isOpen()Whether the checkout is still open, inline and overlay: false once it ended (success, cancel, expiry, close)

mount() and unmount() behave the same inline and in the overlay. When a checkout comes back, onReady fires once more, and the payment resumes where the session stands. Driving the instance says when submit() has no button to press.

ComponentConfig

Passed to wajub.components(sessionId, options) as defaults, and to factory.create(type, config) per component.

OptionTypeApplies to
sessionIdstringRequired
localestringAll
appearanceAppearanceConfigAll
layoutCheckoutLayoutpayment
collectAddressshipping or billingpayment
addressModeshipping or billingaddress
collectNamebooleanpayment, address
fields.phonealways, auto, neverpayment, address
fields.customerauto or externalAll but address
fields.countryISO 3166 alpha-2mobileMoney, payment
fields.operatorchoose or detectmobileMoney, payment
variantdefault or fieldsAll but address
frameTitlestringAll. The frame's name for screen readers, Wajub <type> component by default
loadernone or skeletonAll. none by default, skeleton in the framework packages. Loading without a layout shift
readyTimeoutnumber, millisecondsAll. Without ready in time, onLoadError and loaderror receive ready_timeout. 0 or absent: no limit, and no error
CallbackReceives
onBeforeSubmitNothing. Return false, or throw, to stop the charge. Answer within 30 seconds. All but address
onReadyComponentInstance
onChangeComponentChangeEvent
onFocus, onBlurNothing
onLoadErrorWajubError: a code a checkout sends when it cannot start, or ready_timeout with readyTimeout
onSuccessThe transaction
onErrorWajubError
onMethodChange{ methodId? }
onStateChangeComponentStateChangeEvent, { state, method? }
onResize{ height }. The hosted checkout's onResize receives the number itself
onRedirectComponentRedirectEvent, { url, method }. The page leaves right after, even if the callback throws

Each callback is called just before the event of the same name. Passing one changes nothing else.

ComponentsFactory

MemberWhat it is
sessionIdThe session every component inherits
create(type, config?)A new ComponentInstance

Types. card, mobileMoney, bankTransfer, crypto, wallet, payment, address.

ComponentInstance

Every method except the readers returns the instance, so calls chain.

MethodReturns
mount(container)The instance
unmount(), destroy()Nothing
on(event, fn), off(event, fn)The instance
update({ locale, appearance, layout, frameTitle })The instance. appearance merges as on the hosted checkout
focus(), blur(), submit()The instance. focus() while a skeleton loader is up moves the focus in once the form is ready, unless the payer acted meanwhile
selectMethod(methodId)The instance
getState()CheckoutState
isComplete()boolean
getError()WajubError or null
getValue()ComponentAddressValue or null

Events

EventPayload
readyComponentInstance
changeComponentChangeEvent
focus, blurNothing
loaderrorWajubError: a code a checkout sends when it cannot start, or ready_timeout with readyTimeout
resize{ height }
successPaymentSuccess
errorWajubError
statechangeComponentStateChangeEvent, { state, method? }
methodchange{ methodId }
redirectComponentRedirectEvent, { url, method }. Right before your page leaves for the provider's own page

on() and off() type the payload of each event above through ComponentEventMap: card.on('statechange', (event) => event.state) needs no cast.

update({ frameTitle }) renames the frame for screen readers.

error also carries submission_failed when a submission you asked for, with submit() or confirmPayment(), was refused before any charge.

ConfirmPaymentOptions

OptionTypeDefault
sessionIdstringRequired
componentsComponentInstanceRequired, one mounted component
timeoutnumber60000, in milliseconds. 0 waits forever. Paused while the payment waits on the payer

Resolves with { status, transaction }, transaction being a PaymentSuccess. Rejects with a WajubError carrying missing_component, wallet_not_supported or address_not_payment before anything is submitted. After, it rejects with confirmation_timeout, or with the payment's own error: checkout_validation, submission_failed, payment_error, payment_cancelled, session_expired, component_unmounted, a decline code, or the component's load error.

The time does not run while the payment waits on the payer (OTP_REQUIRED, PIN_REQUIRED, PHONE_REQUIRED, BIRTHDAY_REQUIRED, ADDRESS_REQUIRED, APPROVAL_REQUIRED, USSD_REQUIRED, 3DS_REQUIRED, PENDING), nor once your page has left for the provider's (redirect). A component removed from the page while you wait rejects with component_unmounted, as unmount() and destroy() do.

confirmation_timeout only stops the wait. It cancels nothing: the payment goes on and can still succeed. Before offering to pay again, listen for success on the component or wait for the payment.succeeded webhook.

PaymentSuccess

What onSuccess, the success event and confirmPayment() hand over. It is the checkout's own summary, not the API's payment object, and it comes from the browser: confirm the payment on your server, with GET /payments/{id} or the payment.succeeded webhook, before you deliver anything.

FieldTypeWhat it is
idstringWajub's id of the payment, what GET /payments/{id} takes
referencestringYour reference, the one you sent on POST /payments
amountnumberWhat the payer paid, fee included when the payer bears it, in major units
currencystringISO 4217 code
methodstringThe method family: mobile_money, card…, unknown when the session was already paid
status"success"Always success
timestampstringWhen the payment completed, ISO 8601
receipt_urlstringThe payer's hosted receipt, when you have receipts on

Amounts are in major units, like the API: 12.5 for 12.50 EUR, 1500 for 1 500 XAF.

CreatePaymentParams

What client.createPayment() sends. The same fields as POST /payments, narrowed to what a browser may set.

FieldType
amountnumber, required
currencystring, required
referencestring
descriptionstring
customer{ email?, name?, phone?, country? }, required with an email or a phone, or the API answers 422
bearermerchant or customer, who pays the fee
callbackHTTPS URL, redirect flow only
metadataRecord<string, string>

CreatePaymentResult

FieldWhat it is
sessionIdPass this to mount, open or components
authorizationTokenThe same value, under the API's name
authorizationUrlThe hosted page, or null
transactionThe transaction object, or null
rawThe untouched API response

InitCheckoutOptions

Creates the payment and shows it in one call. Everything in EmbeddedConfig applies too.

OptionTypeWhat it does
modeinline, overlay, redirectHow the checkout appears
containerstring or HTMLElementRequired for inline
sessionIdstringSkips createPayment()
paymentCreatePaymentParamsUsed when there is no sessionId
checkoutPartial<EmbeddedConfig>Options for the embed itself

It resolves with { session, instance }, and throws missing_container when inline has nowhere to go.

SessionPreview

What fetchSession(sessionId) resolves to. Read it before mounting to show an amount, a merchant name, or a sandbox banner.

FieldType
session_idstring
statusstring
environmentsandbox or live
amountnumber, in major units like the API
currencystring
merchant_namestring
payment_methodsArray<{ id, type, label }>
saved_methodsArray<{ id, type, label }>, returning customers your server named

saved_methods lists the methods a customer paid with before, and only on a payment whose customer your server named: one created with POST /payments and your secret key (or a restricted key) with a customer, one activated with POST /payments/{id}/activate, or the payment of an invoice linked to one of your customers. A payment link, a payment created with your publishable key and an invoice addressed to a name only never list any, because the e-mail typed on those pages may be someone else's. Paying with a saved method on such a payment is refused before any charge, with HTTP 422, the code saved_method_not_allowed and the message "Saved payment methods cannot be used for this payment."

ClientSignals

What signals() resolves to: an opaque object holding the payer's device signals, for a charge you make from your own server. Do not build, edit or store it. How to send it is on Shield.

AppearanceConfig

The full key list, the presets and the filtering rules are on Appearance.

GroupKeys
Presettheme: stripe, night, flat, none. light, dark, system or auto sets colorScheme when none is given
ColourprimaryColor, secondaryColor, backgroundColor, buttonTextColor, inputBackgroundColor, inputBorderColor, textMutedColor, successColor, errorColor
ShapefontFamily, borderRadius, shadow
BehaviourcolorScheme, labels, disableAnimations
Tokensvariables, sixteen design token keys
Selectorsrules, .Input and .Label only
Your pageinherit: true, or an InheritSource, { input?, label?, button?, background? }, each a CSS selector or an element. Taking your page's look

States

getState() and onStateChange both speak this vocabulary.

CheckoutState
INITIATED → COLLECTING_DETAILS → PROCESSING → SUCCESS
                                ↘ OTP_REQUIRED, PIN_REQUIRED, PHONE_REQUIRED
                                ↘ BIRTHDAY_REQUIRED, ADDRESS_REQUIRED
                                ↘ 3DS_REQUIRED, USSD_REQUIRED, APPROVAL_REQUIRED
                                ↘ VERIFYING, PENDING
                                ↘ FAILED, CANCELLED, EXPIRED

A new instance reports INITIATED until the payment moves. PIN_REQUIRED, PHONE_REQUIRED, BIRTHDAY_REQUIRED and ADDRESS_REQUIRED are the steps some payments add after the first submit: a wallet PIN, a phone number to confirm, a date of birth, an address.

On the hosted checkout the outcome does not arrive through onStateChange: it arrives through onSuccess, onError, onCancel or onExpired, and getState() keeps the last step before it.

WajubError

Every rejection and every error callback receives one.

FieldType
messagestring, written for a human
typeapi_error, authentication_error, invalid_request_error, payment_error, rate_limit_error
codestring, the machine name
decline_codestring or null, why the payment was declined, when it was
retryableboolean
paramstring or null, the field at fault

Codes raised by the SDK itself

They are integration mistakes.

CodeCause
secret_key_in_browserA secret key passed to Wajub()
invalid_publishable_keyA key that is not a publishable key
invalid_initWajub() called with neither a publishable key nor a session token
missing_publishable_keycreatePayment() without a key
missing_session_tokencreatePayment() got an answer without a session token
missing_sessionNo sessionId on the client
missing_containerinitCheckout in inline mode with nowhere to mount
missing_componentconfirmPayment without a submittable component
wallet_not_supportedconfirmPayment on a wallet component
address_not_paymentconfirmPayment on an address component
confirmation_timeoutNo outcome within timeout. The payment goes on and can still succeed
ready_timeoutA payment field sent no ready within readyTimeout. Reaches onLoadError and loaderror, and is retryable
component_unmountedThe component was unmounted, destroyed or removed from the page while confirmPayment waited on it
components_unavailableThe components runtime did not load
load_errorThe checkout failed to load

Codes a checkout sends when it cannot start

onLoadError on the hosted checkout, and onLoadError or the loaderror event on a payment field, receive one of these. Nothing was paid.

CodeCause
session_not_foundThe token is unknown, or the session could not be read
session_terminal_expiredThe payment ended and its token has stopped. On a payment field, the session expired unpaid, and the field shows its notice
session_terminal_cancelledPayment fields only, the session was already cancelled. The field shows its notice
session_terminal_failedPayment fields only, the session already ended on a failed payment. The field shows its notice
component_origin_missingPayment fields only, a field not mounted with Wajub.js or a framework package. Mount it with one of them
invalid_componentPayment fields only, a component type that does not exist
method_unavailablePayment fields only, the session offers no method this component can take

With readyTimeout, a payment field's onLoadError and loaderror can also receive ready_timeout, which the SDK raises itself when the field is not ready in time.

For one of the three session_terminal_ codes, start a new payment and mount the field on its token. A field whose session is already paid shows its notice and sends ready, not an error.

Codes a payment can end with

onError, the error event and a confirmPayment() rejection carry the decline code when there is one, insufficient_funds for example. Otherwise they carry one of these.

CodeCause
payment_declinedThe payment was declined without a more precise reason
blockedRefused by Shield or by a restriction on your account
validation_errorA field the payer filled was refused, such as a phone number that is not valid
rate_limitedToo many payment attempts on this session. Wait a short while before offering another attempt
saved_method_not_allowedA saved method was used on a payment that lists none, see SessionPreview. Nothing was charged, and the payer can still pay with a method they enter
server_errorA temporary failure. retryable says whether another attempt is worth offering
submission_failedPayment fields only. A submission you asked for with submit() or confirmPayment() was refused before any charge: a form not ready, such as a Mobile Money number that is not valid, a card left incomplete, fields still loading, a bank transfer with no IBAN or account number or a crypto payment with no asset, a card number refused, or a payment window that was closed or could not open. message says why, in the payer's language

Framework packages

@wajub/react, @wajub/vue and @wajub/svelte export these, each in its framework's idiom.

ExportWhat it is
WajubProviderLoads the runtime once for a subtree
CheckoutEmbedThe hosted checkout, inline
CardComponent, MobileMoneyComponent, WalletComponent, PaymentComponent, AddressComponent, BankTransferComponent, CryptoComponentOne field group each
ComponentEmbedThe same, with type as a prop
useWajub, useWajubOptional, useLoadWajubReach the runtime
useConfirmPaymentSubmit a field component
WajubContext in React, WAJUB_INJECTION_KEY in Vue, getWajubContext and setWajubContext in Svelte, and useWajubContext in all threeThe raw context, for your own hook, composable or helper

@wajub/angular exports these.

ExportWhat it is
provideWajub(options?)Provides Wajub to the application or a route, in place of WajubProvider. With defer: true, nothing loads until you call WajubService.load()
WajubServiceLoads the runtime once: the runtime, loading and error signals, runtime$, load() and getRuntime(), in place of useWajub, useWajubOptional and useLoadWajub
WAJUB_OPTIONSThe injection token provideWajub() sets
WajubCheckoutEmbedComponent<wajub-checkout-embed>, the hosted checkout, inline
WajubCardComponent, WajubMobileMoneyComponent, WajubWalletComponent, WajubPaymentComponent, WajubAddressComponent, WajubBankTransferComponent, WajubCryptoComponent<wajub-card>, <wajub-mobile-money>, <wajub-wallet>, <wajub-payment>, <wajub-address>, <wajub-bank-transfer>, <wajub-crypto>: one field group each
WajubComponentEmbedComponent<wajub-component>, the same with a type input
injectConfirmPayment(sessionId?)Submits a field component, in place of useConfirmPayment. isConfirming is a signal
Component propApplies toDefault
className in React, class in Vue and Svelte, and on the host element in AngularBothnone
style, in React and Vue, and on the host element in AngularBothnone
minHeightCheckoutEmbed480
minHeightField componentsUnset. With loader: 'none', pass 0 to fit the inputs. Inside your own payment method box
loaderField componentsskeleton, where @wajub/js itself defaults to none
onInstance, the (instance) output in AngularField componentsnone, fires with null on unmount

In Angular, the props are inputs and outputs of the same names: every option is an input, every callback an output named without on, such as (loadError) for onLoadError, and onBeforeSubmit is the beforeSubmit input, since an output cannot answer.

Every option of ComponentConfig is a prop of the field components, the callbacks included, and a new handler takes over without a reload. A change to appearance, locale, layout or frameTitle applies to the mounted field without a reload. A new sessionId, type, variant, fields, loader, readyTimeout, collectAddress, addressMode or collectName mounts a new field in the same container. CheckoutEmbed applies appearance, locale and layout the same way, and loads again for a new sessionId.

Each framework package also re-exports every type of @wajub/js, so import type { PaymentSuccess } from '@wajub/react' works as well as from @wajub/js.

useWajubOptional() returns the runtime or null in React. It returns a ref in Vue and a store in Svelte, both null until the runtime has loaded. In Angular, the runtime signal of WajubService holds null until then.

Each package has its own page: React, Vue, Svelte, Angular.

What did you think of this content?