@xpay/sdk-js
The browser JavaScript SDK. Reference for every public export, method signature, and option type.
The XPay JavaScript SDK is a tiny CDN-loaded library that gives you a typed XPayInstance from your publishable key. From there you can mount payment UI as Elements, open a drop-in checkout, or run a single-call initCheckout and confirm a payment.
pnpm add @xpay/sdk-js
# or: npm install @xpay/sdk-js / yarn add @xpay/sdk-jsThe package ships ESM and CJS builds, plus full TypeScript types. The runtime itself is loaded on demand from https://checkout.xpay.app/sdk.js. There's also a CDN script tag if you're not using a bundler:
<script src="https://checkout.xpay.app/sdk.js"></script>This page is the reference for every public export. For walkthroughs, see Drop-in and Elements under Integrate.
Use this package when
@xpay/sdk-js is the vanilla SDK and is the right pick whenever you're not on React. That covers:
- Plain HTML and static sites (use the CDN script tag).
- Vue, Svelte, Solid, Angular, Lit, Qwik, Astro, and any other framework. Call the SDK from inside that framework's component lifecycle (mount, onMount, useEffect equivalent, etc.).
- React Native via WebView until a native package ships.
- Server-side scripts that need to type their
clientSecretpayloads (the package's TypeScript types are framework-agnostic).
For React, @xpay/sdk-react is a thin convenience wrapper on top of this package. It builds on loadXPay, xpay.initCheckout, and xpay.elements, so anything you read here applies under the hood there too.
Quick start
The recommended path is loadXPay at module level, then xpay.initCheckout() once you have a clientSecret from your server.
import { loadXPay } from "@xpay/sdk-js";
// Module-level: call once, share across the app.
const xpayPromise = loadXPay("pk_test_...");
async function startCheckout() {
const xpay = await xpayPromise;
if (!xpay) return; // SSR returns null on the server
// initCheckout accepts a Promise<string> too, so you can pass the fetch directly.
const checkout = await xpay.initCheckout({
clientSecret: fetch("/api/create-checkout", { method: "POST" })
.then((r) => r.json())
.then((d) => d.clientSecret as string),
});
// Mount the payment element.
const elements = checkout.getElements();
const paymentElement = elements.create("payment");
paymentElement.mount("#payment-element");
// Listen for state changes (promo codes, quantity updates, fee recalcs).
checkout.on("change", (session) => {
document.getElementById("total")!.textContent =
`${session.currency} ${(session.amountTotal / 100).toFixed(2)}`;
});
// Confirm when the customer submits.
document.getElementById("pay")!.addEventListener("click", async () => {
const result = await checkout.confirm({
customerDetails: { email: "customer@example.com", name: "Aya Hassan" },
});
if (result.type === "error") {
console.error(result.error.message);
return;
}
window.location.href = "/thank-you";
});
}Exports at a glance
| Export | Kind | What it is |
|---|---|---|
loadXPay(publishableKey) | function | Loads the SDK from CDN and returns an XPayInstance (or null on the server during SSR). |
XPayInstance | interface | Factory for Elements, drop-in Checkout, confirmPayment, and initCheckout. |
Elements | interface | Manages payment elements (PaymentElement) and the session lifecycle. |
PaymentElement | interface | Mountable payment-method selector with the card form, BNPL, kiosk, and wallet methods. |
ConfirmPaymentOptions | interface | Shape passed to xpay.confirmPayment() and checkout.confirm(). |
CheckoutOptions | interface | Configuration for xpay.checkout(). Drop-in modal or inline embed. |
CheckoutInstance | interface | Drop-in checkout handle: open(), close(), destroy(), plus events. |
CheckoutCompleteResult | interface | Payload for the drop-in onComplete callback. |
InitCheckoutOptions | interface | Options for xpay.initCheckout(). The modern single-call API. |
InitCheckoutResult | type | Session data merged with action methods (confirm, promo codes, etc.). |
CheckoutActions | interface | The action methods that ride on the checkout object. |
CheckoutSession | type | The session data shape: amount, currency, status, payment methods, line items. |
ActionResult | type | Tagged union: { type: "success", session } or { type: "error", error }. |
XPayError | interface | Unified error type across every SDK action. |
Appearance | type | Branding overrides for the embedded UI (color mode, border style, colors, font). |
PaymentElementChangeEvent | interface | Payload for PaymentElement change events. |
ElementsReadyEvent | interface | Payload for the Elements "ready" event. |
ElementsLoadErrorEvent | interface | Payload for the Elements "loaderror" event. |
CustomerDetails, Address | interface | Shapes for customer fields collected by your form and passed at confirm time. |
PaymentMethodInfo | type | Information about an available payment method on the session. |
SessionStatus | type | Tagged union: open, expired, or complete. |
loadXPay(publishableKey)
Loads the SDK runtime from CDN and returns an XPayInstance. Call this once at module level, not inside a component.
import { loadXPay } from "@xpay/sdk-js";
const xpayPromise = loadXPay("pk_test_...");
// later, when you have a clientSecret:
const xpay = await xpayPromise;
const elements = xpay.elements({ clientSecret: "cs_test_..." });| Parameter | Type | Description |
|---|---|---|
publishableKey | string | Your publishable API key (pk_test_... or pk_live_...). |
Returns Promise<XPayInstance | null>. null is returned during server-side rendering (no window). The XPayProvider from @xpay/sdk-react handles null gracefully by retrying on the client.
The runtime is fetched once; subsequent loadXPay calls reuse the same script tag. If a script with sdk.js is already on the page, it isn't re-injected.
XPayInstance
The factory you get back from loadXPay. Four methods.
interface XPayInstance {
elements(options: ElementsOptions): Elements;
checkout(options: CheckoutOptions): CheckoutInstance;
confirmPayment(options: ConfirmPaymentOptions): Promise<ActionResult>;
initCheckout(options: InitCheckoutOptions): Promise<InitCheckoutResult>;
}elements(options)
Creates an Elements instance for custom checkout UI. Pass it the clientSecret from a Checkout Session.
const elements = xpay.elements({
clientSecret: "cs_test_...",
appearance: { colorMode: "dark", borderStyle: "rounded" },
locale: "en",
});ElementsOptions:
| Field | Type | Description |
|---|---|---|
clientSecret | string | Promise<string> | Required. The Checkout Session client secret. Can be a Promise. |
appearance | Appearance | Optional. UI overrides merged with the session's server-side branding. |
locale | "en" | "ar" | Optional. Defaults to "en". |
checkout(options)
Creates a drop-in checkout instance. See CheckoutOptions below.
confirmPayment(options)
Submits a payment using the data collected by Elements. See ConfirmPaymentOptions below.
initCheckout(options)
Modern single-call API: returns the session data and action methods together. See InitCheckoutOptions below.
Elements
Returned by xpay.elements(). Manages one shared payment iframe and exposes session-mutation methods.
interface Elements {
create(type: "payment"): PaymentElement;
getElement(type: "payment"): PaymentElement | null;
fetchPaymentMethods(): Promise<PaymentMethodInfo[]>;
on(event: "ready" | "change" | "loaderror" | "error", handler): void;
off(event: string, handler): void;
applyPromotionCode(code: string): Promise<ActionResult>;
removePromotionCode(): Promise<ActionResult>;
updateLineItemQuantity(args: { lineItem: string; quantity: number }): Promise<ActionResult>;
submit(): Promise<{ error?: XPayError; selectedPaymentMethod?: string }>;
fetchUpdates(): Promise<ActionResult>;
changeAppearance(appearance: Appearance): void;
destroy(): void;
}Events
| Event | Handler signature | Fires when |
|---|---|---|
"ready" | (data: ElementsReadyEvent) => void | Session is loaded and elements are mountable. Fires immediately if already loaded. |
"change" | (session: CheckoutSession) => void | Session data changes (payment method selection, promo codes, fee recalculations). |
"loaderror" | (data: ElementsLoadErrorEvent) => void | Session fails to load (network error, invalid client secret, API error). |
"error" | (error: XPayError) => void | Unsolicited error not triggered by a merchant action (e.g. session expired during a fee recalculation). |
Methods
create("payment", options?): returns aPaymentElementyou can mount.getElement("payment"): returns the existing element ornullif none was created.fetchPaymentMethods(): returns the list ofPaymentMethodInfothe session supports.applyPromotionCode(code): applies a promotion code, returnsActionResult.removePromotionCode(): removes the applied code, returnsActionResult.updateLineItemQuantity({ lineItem, quantity }): updates a line item, returnsActionResult.submit(): validates element fields. Returns either anerroror theselectedPaymentMethodtype string.fetchUpdates(): re-fetches the session from the server.changeAppearance(appearance): updates branding at runtime without recreating elements.destroy(): tears down the instance and frees resources.
PaymentElement
The full payment-method selector with the card form, BNPL, kiosk, and wallet methods. Get one from elements.create("payment").
interface PaymentElement {
mount(container: string | HTMLElement): void;
unmount(): void;
destroy(): void;
focus(): void;
blur(): void;
collapse(): void;
on(event: "ready" | "loaderstart" | "loaderror", handler): void;
off(event: string, handler): void;
}PaymentElementChangeEvent is the payload for the parent Elements "change" event when triggered by a payment-method change:
| Field | Type | Description |
|---|---|---|
elementType | "payment" | Always "payment" for this element. |
empty | boolean | Whether all card fields are empty. |
complete | boolean | Whether the form is complete and ready to submit. |
collapsed | boolean | Whether the method selector is collapsed (no method selected). |
value | { type: string } | The currently selected payment method type. |
session | CheckoutSession | Latest session snapshot. |
ConfirmPaymentOptions
Shape passed to xpay.confirmPayment() and checkout.confirm().
| Field | Type | Description |
|---|---|---|
elements | Elements | Required (for xpay.confirmPayment). The Elements instance managing the form. checkout.confirm injects this for you. |
customerDetails | CustomerDetails | Optional. Customer fields collected by your form. |
customFields | Record<string, string | number | boolean> | Optional. Custom-field values for the session. |
deviceFingerprint | { visitorId: string; confidence?: number } | Optional. Device fingerprint for fraud detection. |
paymentMethod | string | Optional. Override the selected payment method type. |
redirect | "if_required" | "always" | Default "if_required". Controls post-payment navigation. |
returnUrl | string | Optional. Override the session's afterCompletion.redirect.url. |
redirect semantics:
"if_required"returns the result to your code; only redirects when the payment method requires it (e.g. 3-D Secure, BNPL)."always"always redirects toreturnUrlafter payment. The page navigates away and the function never returns on success.
CheckoutOptions
Configuration for the drop-in xpay.checkout().
| Field | Type | Description |
|---|---|---|
clientSecret | string | Required. The Checkout Session client secret. |
mode | "modal" | "inline" | "modal" (default) renders an overlay; "inline" embeds in container. |
container | string | HTMLElement | Required for inline mode. CSS selector or DOM node to embed in. |
appearance | Appearance | UI overrides merged with the session's branding. |
locale | "en" | "ar" | UI locale. Defaults to "en". |
onComplete | (result: CheckoutCompleteResult) => void | Called when payment completes successfully. |
onClose | () => void | Called when the modal closes. |
onReady | (session: CheckoutSession) => void | Called when the session loads and the UI is ready. |
onConfirmed | () => void | Called when the customer confirms payment, before the final result. |
onError | (error: CheckoutError) => void | Called when an error occurs. |
CheckoutInstance
Returned by xpay.checkout(). Imperative handle.
interface CheckoutInstance {
open(): void; // modal mode
close(): void;
destroy(): void;
on(event: "complete" | "close" | "ready" | "confirmed" | "error", handler): void;
off(event: string, handler): void;
}CheckoutCompleteResult (the payload for onComplete):
| Field | Type | Description |
|---|---|---|
status | "succeeded" | Always "succeeded" for this callback. |
paymentIntentId | string | The Payment Intent ID for server-side verification. |
chargeId | string | Optional. The Charge ID, when available. |
redirectUrl | string | Optional. The session's after-completion redirect URL. |
InitCheckoutOptions
Modern single-call API. Combines elements() with session loading and exposes session data plus action methods on a single object.
const checkout = await xpay.initCheckout({ clientSecret: "cs_test_..." });
console.log(checkout.amountTotal); // session field
const result = await checkout.confirm({ customerDetails: { email } });| Field | Type | Description |
|---|---|---|
clientSecret | string | Promise<string> | Required. The session client secret. |
appearance | Appearance | Optional. UI overrides. |
locale | "en" | "ar" | Optional. Defaults to "en". |
InitCheckoutResult is CheckoutSession & CheckoutActions. The action methods on CheckoutActions:
| Method | What it does |
|---|---|
confirm(options?) | Confirms the payment. Returns ActionResult. |
applyPromotionCode(code) | Applies a code. Returns ActionResult. |
removePromotionCode() | Removes the applied code. Returns ActionResult. |
updateLineItemQuantity({ lineItem, quantity }) | Updates a line item quantity. Returns ActionResult. |
submit() | Validates fields. Returns { error?, selectedPaymentMethod? }. |
fetchUpdates() | Re-fetches the session from the server. Returns ActionResult. |
changeAppearance(appearance) | Updates branding at runtime. |
on(event, handler) | Listen for "change", "error", or a custom event. |
getElements() | Returns the underlying Elements for element creation. |
CheckoutSession (data type)
Session data exposed to the merchant. Derived from the server's response, trimmed to the merchant-facing fields.
| Field | Type | Description |
|---|---|---|
id | string | The cs_* session ID. |
amountSubtotal | number | Subtotal in minor units (e.g. 50000 for 500.00 EGP). |
amountTotal | number | Total in minor units after fees, taxes, and discounts. |
currency | string | ISO currency code (e.g. "EGP"). |
merchantName | string | Your business display name. |
livemode | boolean | true for live keys; false for test mode. |
expiresAt | string | ISO timestamp when the session expires. |
status | SessionStatus | Tagged union: open, expired, complete. |
canConfirm | boolean | Whether the session can currently be confirmed. |
paymentMethods | PaymentMethodInfo[] | Available payment methods on this session. |
lineItems | CheckoutLineItem[] | Line items. |
totalDetails | CheckoutTotalDetails | Subtotal, tax, shipping, discount breakdown. |
fees | CheckoutFees | Fee breakdown when feesPassThrough is on. |
discounts | CheckoutDiscount[] | Applied promotion codes. |
SessionStatus:
type SessionStatus =
| { type: "open" }
| { type: "expired" }
| { type: "complete"; paymentStatus: "paid" | "unpaid" | "no_payment_required" };PaymentMethodInfo:
| Field | Type | Description |
|---|---|---|
type | string | Method type ("card", "valu", "fawry"). |
displayName | string | Localized label ("Card", "ValU", "Fawry"). |
category | "card" | "bnpl" | "kiosk" | "wallet" | Bucket for UI grouping. |
icon | string | Optional icon URL. |
nextActionText | string | Optional. Description of the next step shown to the customer. |
ActionResult and XPayError
Every action that mutates the session returns an ActionResult. It's a tagged union, so narrow by result.type before reading the payload.
type ActionResult<E = XPayError> =
| { type: "success"; session: CheckoutSession }
| { type: "error"; error: E };XPayError is the unified error shape. Payment-specific fields are null for non-payment errors.
| Field | Type | Description |
|---|---|---|
type | string | Error category: "card_error", "invalid_request_error", "api_error". |
code | string | null | Machine-readable code ("card_declined", "promotion_code_not_found"). |
message | string | Human-readable message. |
param | string | null | Parameter that caused the error (e.g. "promotionCode"). |
docUrl | string | null | Documentation URL for this error code. |
declineCode | string | null | Decline detail like "insufficient_funds". Null for non-payment errors. |
adviceCode | string | null | Retry advice: "try_again_later", "do_not_try_again", "confirm_card_data". |
chargeId | string | null | Failed charge ID. |
paymentMethodId | string | null | Failed payment method ID. |
paymentMethodType | string | null | Payment method type ("card", "valu"). |
paymentMethod | Record<string, unknown> | null | Payment method snapshot at failure time. |
For a guide on handling API errors and the three error code spaces, see Errors, API error codes, Payment error codes, and Decline codes.
Appearance
Branding overrides for the embedded UI. Mirrors a subset of the merchant-default fields you set in Branding settings.
| Field | Values |
|---|---|
colorMode | "system" | "light" | "dark" |
borderStyle | "rounded" | "sharp" | "pill" |
spacing | "condensed" | "normal" | "spacious" |
inputSize | "small" | "medium" | "large" |
inputStyle | "outlined" | "flat" | "filled" |
formLayout | "compact" | "spacious" |
colors | Object with twelve semantic tokens (primary, foreground, background, muted, accent, border, input, ring, destructive, plus the foreground pairs). |
fontFamily | CSS font-family string. |
Pass an Appearance to xpay.elements(), xpay.checkout(), or xpay.initCheckout(). Or call elements.changeAppearance() / checkout.changeAppearance() to update at runtime.
CustomerDetails and Address
Shapes for customer fields you collect on your form and pass at confirm time.
interface CustomerDetails {
email?: string;
name?: string;
phone?: string;
billingDetails?: { name?: string; email?: string; phone?: string; address?: Address };
shipping?: { name?: string; phone?: string; address?: Address };
}
interface Address {
line1?: string;
line2?: string;
city?: string;
state?: string;
postalCode?: string;
country?: string;
}For the developer-side cross-reference on what each Checkout Session field controls (collection toggles, custom fields, prefill priority), see Customer lifecycle.