The Purse widget allows you to quickly build a secure and dynamic payment interface using your configured experiences.
Although the Purse API can be used directly, the Widget Library greatly simplifies frontend integration across multiple PSPs.
Installation
First, include the Purse Checkout script in your HTML page. This script loads all necessary components to initialize the checkout.
Using API V1
<script src="https://cdn.purse-sandbox.com/dropin/v3-latest/purse.js"></script>
Using API V2
You can recover the script from the widget url in the client session API response.
<script src="{widget_url}"></script>
The widget orchestrates one or more payment providers and handles rendering, session management, and submission.
Even if your experience only includes a single payment method, the widget will handle it cleanly and consistently.
You’ll use the WidgetManager to build and mount the widgets associated with a payment session or wallet session.
Using API V1
const env = {
apiKey: "YOUR_API_KEY",
entityId: "YOUR_ENTITY_ID",
environment: "sandbox",
};
const manager = UpStreamPay.WidgetManager.buildForCredentials(env);
await manager.setPaymentSession(session);
Using API V2
const widgetManager = await UpStreamPay
.WidgetManager
.buildForWidgetData(clientSession.widget.data);
The widget.data and widget.js_url values are returned by the /v2/client-sessions API.
Once the manager is initialized, create the widgets you need:
const payment = await manager.createWidget({
name: "my_unique_payment_widget_name",
interface: "PAYMENT",
});
const button = await manager.createWidget({
name: "my_unique_pay_button_widget_name",
interface: "PAY_BUTTON",
});
await payment.mount("widget-payment");
await button.mount("widget-button");
Rendered Output
- The
widget-payment displays available methods:
- The
widget-button links to the payment widget and sends payment data:
The widget uses the ID HTML attribute to target its rendering place. Here, we assume that the DOM contains an
element with the id widget-button
const payButton = await manager.createWidget({
ui: {
translations: {
overrides: {
WIDGET_PAY_BUTTON_TEXT: "Proceed to payment"
}
}
},
interface: "PAY_BUTTON"
});
await payButton.mount("widget-button");
Example Implementation
- Widget API V1
- Widget API V2
let widgetManager;
let widgetPaymentContainer;
let widgetAmountContainer;
let widgetButtonContainer;
async function createWidgetManager() {
const credentials = {
apiKey: apiKey,
entityId: entityId,
environment: id,
};
widgetManager = UpStreamPay.WidgetManager.buildForCredentials(credentials);
await createPaymentWidget();
await createAmountWidget();
await createButtonWidget();
}
async function createButtonWidget() {
const button = await widgetManager.createWidget({ interface: 'PAY_BUTTON' });
await button.mount('widget-button');
}
async function createPaymentWidget() {
const widget = await widgetManager.createWidget({
interface: 'PAYMENT',
ui: {
layout: { name: 'ACCORDION' }
}
});
await widget.mount('widget-payment');
}
async function createAmountWidget() {
const widget = await widgetManager.createWidget({ interface: 'AMOUNT' });
await widget.mount('widget-amount');
}
<h1>Let's test Purse</h1>
<div class="main">
<div id="widget-payment" bind:this={widgetPaymentContainer} />
</div>
<div class="secondary">
<div id="widget-amount" bind:this={widgetAmountContainer} />
<div id="widget-button" bind:this={widgetButtonContainer} />
</div>
let widgetManager;
let widgetPaymentContainer;
let widgetAmountContainer;
let widgetButtonContainer;
async function createWidgetManager() {
const clientSession = "data-from-your-create-client-session";
widgetManager = await UpStreamPay.WidgetManager.buildForWidgetData(clientSession.widget.data);
await createPaymentWidget();
await createAmountWidget();
await createButtonWidget();
}
async function createButtonWidget() {
const button = await widgetManager.createWidget({ interface: 'PAY_BUTTON' });
await button.mount('widget-button');
}
async function createPaymentWidget() {
const widget = await widgetManager.createWidget({
interface: 'PAYMENT',
ui: {
layout: { name: 'ACCORDION' }
}
});
await widget.mount('widget-payment');
}
async function createAmountWidget() {
const widget = await widgetManager.createWidget({ interface: 'AMOUNT' });
await widget.mount('widget-amount');
}
<h1>Let's test Purse</h1>
<div class="main">
<div id="widget-payment" bind:this={widgetPaymentContainer} />
</div>
<div class="secondary">
<div id="widget-amount" bind:this={widgetAmountContainer} />
<div id="widget-button" bind:this={widgetButtonContainer} />
</div>
Callbacks overrides
Hook into the Validation Process
You may want to execute logic before or after payment validation (e.g. saving an order in your system).
You can pass preValidate and postValidate callbacks to the widget manager.
widgetManager = await UpStreamPay.WidgetManager.buildForWidgetData(widgetData, [], {
preValidate: async () => console.log('Prevalidate working'),
postValidate: async () => console.log('PostValidate working'),
});
- If
preValidate throws an error or rejects, the validation is cancelled.
- If
postValidate fails, the validation still proceeds normally.
Redirection Mode
By default, the widget will follow the redirection after the payment is validated. However, you can override this behavior by setting a redirectionHandler callback in the buildFor... method.
widgetManager.buildForCredentials({
hooks: {
redirectionHandler(redirectionParams: RedirectionHandlerParams) {
if (redirectionParams.type === 'redirection') {
window.location.href = redirectionParams.url;
} else if (redirectionParams.type === 'jsonFormSubmit') {
const form = document.createElement('form');
form.method = redirectionParams.method || 'POST';
form.action = redirectionParams.url;
if (redirectionParams.JSONPayload) {
const input = document.createElement('input');
input.type = 'hidden';
input.name = 'payload';
input.value = redirectionParams.JSONPayload;
form.appendChild(input);
}
document.body.appendChild(form);
form.submit();
} else if (redirectionParams.type === 'htmlFormSubmit') {
const container = document.getElementById(redirectionParams.containerId);
if (container) {
const form = document.createElement('form');
form.method = 'POST';
form.action = redirectionParams.url;
form.innerHTML = redirectionParams.responseForm;
container.appendChild(form);
}
}
}
}
});
The following redirection types are supported:
type RedirectionHandlerParams =
| {
type: 'redirection';
url: string;
}
| {
type: 'jsonFormSubmit';
url: string;
JSONPayload?: string;
method?: 'GET' | 'POST';
}
| { type: 'htmlFormSubmit'; containerId: string; responseForm: any };