Error Handling
This guide explains how to handle errors returned by the Drop-in Checkout.
Error Sources
Errors can originate from two sources:
| Source | Delivery | When |
|---|---|---|
| Event listener | event.code === "error" | Initialization failures, internal errors |
| Method return | result instanceof Error | submitPayment(), 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
| Scenario | Suggested Action |
|---|---|
| Network error | Display retry option |
| Session expired | Fetch new session and call setSession() |
| Payment declined | Show decline message, allow retry |
| Validation error | Prompt user to correct input |
Session Expiration
When a session expires, the Drop-in shows a blocking overlay. You have two options.
Automatic refresh with onRefreshSession (recommended)
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
- API Reference — Complete API documentation
- Getting Started — Integration guide