Skip to main content

Error Handling

This guide explains how to handle errors returned by the Drop-in Checkout.

Error Sources​

Errors can originate from two sources:

SourceDeliveryWhen
Event listenerevent.code === "error"Initialization failures, internal errors
Method returnresult instanceof ErrorsubmitPayment(), mount(), setSession(), setWalletSession()

Handling Event Errors​

Listen for errors through the eventListener callback:

const dropin = await Purse.createDropinCheckout({
session: clientSession.widget.data,
eventListener: (event) => {
if (event.code === "error") {
console.error("Error:", event.payload.message);
showErrorToUser(event.payload.message);
}
}
});

Error Event Structure​

{
code: "error";
payload: {
message: string; // Human-readable description
code?: string; // Error code (when available)
};
}

Handling Method Errors​

Wrap async method calls in try/catch:

submitPayment()​

try {
await dropin.submitPayment();
// Success - SDK handles redirection
} catch (error) {
console.error("Payment failed:", error.message);
payButton.disabled = false;
payButton.textContent = "Pay";
showErrorToUser(error.message);
}

mount()​

try {
await dropin.mount(container);
} catch (error) {
console.error("Mount failed:", error.message);
// Show fallback or error state
}

setWalletSession()​

try {
await dropin.setWalletSession(walletSession);
} catch (error) {
console.error("Wallet session failed:", error.message);
}

setSession()​

setSession() handles errors internally. Errors are reported through the eventListener callback:

await dropin.setSession(newSessionData);
// Errors are emitted via the eventListener, not thrown

Common Error Scenarios​

ScenarioSuggested Action
Network errorDisplay retry option
Session expiredFetch new session and call setSession()
Payment declinedShow decline message, allow retry
Validation errorPrompt user to correct input

Session Expiration​

When a session expires, the Drop-in shows a blocking overlay. You have two options.

Provide a hooks.onRefreshSession callback when creating the Drop-in. A Refresh session button is shown on the overlay and calls your hook when clicked. The Drop-in reinitializes automatically with the new session.

const dropin = await Purse.createDropinCheckout({
session: clientSession.widget.data,
hooks: {
async onRefreshSession() {
const newSession = await fetchClientSessionFromBackend();
return newSession.widget.data;
}
}
});

The refresh button is only shown when the hook is provided. If the callback returns void or throws, the overlay remains and the user can retry.

Manual refresh with setSession()​

You can also update the session programmatically at any time:

async function refreshSession() {
const newSession = await fetchClientSessionFromBackend();
await dropin.setSession(newSession.widget.data);
}

Example: Comprehensive Error Handling​

const payButton = document.getElementById("pay-button");

try {
const dropin = await Purse.createDropinCheckout({
session: clientSession.widget.data,
eventListener: (event) => {
if (event.code === "ready") {
document.getElementById("loading-spinner").style.display = "none";
}
if (event.code === "error") {
showError(event.payload.message);
}
}
});

await dropin.mount(container);

// Enable pay button when payment method is selected
dropin.isPaymentFulfilled.subscribe((isFulfilled) => {
payButton.disabled = !isFulfilled;
});

payButton.addEventListener("click", async () => {
payButton.disabled = true;
payButton.textContent = "Processing...";
hideError();

try {
await dropin.submitPayment();
} catch (error) {
showError(error.message || "Payment failed. Please try again.");
payButton.disabled = false;
payButton.textContent = "Pay";
}
});
} catch (error) {
showError("Failed to load payment form. Please refresh.");
}

Next Steps​