Complete reference documentation for the @uphold/enterprise-payment-widget-web-sdk package.
The main class for creating and managing Payment Widget instances is PaymentWidget. It requires a PaymentWidgetSession object that must be created through the API before instantiating the Widget.
Constructor
new PaymentWidget<T extends PaymentWidgetFlow = PaymentWidgetFlow>(
session: PaymentWidgetSession,
options?: PaymentWidgetOptions
)
Parameters:
| Parameter | Type | Required | Description |
|---|
session | PaymentWidgetSession | Yes | Payment session object obtained from the Create session endpoint |
options | PaymentWidgetOptions | No | Configuration options for the Widget |
Generic type parameter:
The constructor accepts an optional generic type parameter that specifies the flow type. When provided, it enables better type inference for event handlers, particularly for the complete event.
Examples:
// Generic flow type (default)
const widget = new PaymentWidget(session);
// Specific flow type for better type inference
const depositWidget = new PaymentWidget<'select-for-deposit'>(session);
const withdrawWidget = new PaymentWidget<'select-for-withdrawal'>(session);
const authorizeWidget = new PaymentWidget<'authorize'>(session);
Options
type PaymentWidgetOptions = {
debug?: boolean;
maxAccountsPerAsset?: number;
paymentMethods?: PaymentMethodOption[];
};
| Property | Type | Default | Description |
|---|
debug | boolean | false | Enable debug mode for additional logging |
maxAccountsPerAsset | number | No limit | Limit the number of accounts that can be created per asset. When the limit is reached, the Widget reuses the most recent account instead of creating a new one. Must be greater than 0. Maximum effective value is 100 |
paymentMethods | PaymentMethodOption[] | All available methods | Restrict which payment methods are available to users. See PaymentMethodOption for details |
paymentMethods option:
The paymentMethods option allows you to control which payment methods the Widget displays to users. When not specified, all supported payment methods are available.
Basic usage:
const widget = new PaymentWidget(session, {
paymentMethods: [
{ type: 'card' },
{ type: 'bank' },
{ type: 'crypto' }
]
});
Filtering assets:
For bank and crypto payment methods, you can filter which assets are available using the assets property. This works the same way for both methods:
const widget = new PaymentWidget(session, {
paymentMethods: [
{ type: 'card' },
{
type: 'bank',
assets: {
include: ['GBP', 'EUR', 'ETH', 'BTC'] // Only these assets will be available
}
},
{
type: 'crypto',
assets: {
include: ['BTC', 'ETH', 'XRP'] // Only these assets will be available
}
}
]
});
You can also exclude specific assets while allowing all others:
const widget = new PaymentWidget(session, {
paymentMethods: [
{
type: 'bank',
assets: {
exclude: ['BTC'] // All assets except BTC
}
},
{
type: 'crypto',
assets: {
exclude: ['DOGE', 'SHIB'] // All assets except these
}
}
]
});
If no assets filter is provided, all supported assets for that payment method will be available. Use either include or exclude, not both.
maxAccountsPerAsset option:
When generating deposit details, depending on the rail’s constraints, the Widget allows users to select a target account for the deposit. The maxAccountsPerAsset option controls how many accounts can be created per asset. For example, setting it to 1 ensures only a single account exists per asset, while setting it to 5 allows up to five accounts for the same asset (e.g. one USD account for general use, another for a vacation fund, and so on). Once the limit is reached, the Widget automatically reuses the most recent account instead of creating a new one.
const widget = new PaymentWidget(session, {
maxAccountsPerAsset: 5
});
Values above 100 are capped at 100.
Methods
mountIframe()
Mounts the Payment Widget iframe to the specified DOM element.
Parameters:
element: The HTML element where the Widget should be mounted
Example:
// Ensure the container has appropriate sizing
const container = document.getElementById('payment-container');
widget.mountIframe(container);
The container element should have explicit dimensions set via CSS. The Widget will fill the entire container. Minimum recommended size is 400px width × 600px height for optimal user experience.
unmount()
Unmounts and cleans up the Payment Widget iframe.
Example:
The Widget will not unmount itself when a flow is finished, either by successful completion, user cancellation, or unrecoverable error, so it must always be called manually.
on()
Registers an event listener for Widget events.
Parameters:
event: The event name to listen for
callback: Function to execute when the event is triggered
Example:
widget.on('complete', (event) => {
console.log('Payment completed:', event.detail.value);
});
off()
Removes an event listener for Payment Widget events.
Parameters:
event: The event name to stop listening for
callback: The specific function to remove (must be the same reference as used in on())
Example:
const handleComplete = (event) => {
console.log('Payment flow completed:', event.detail.value);
};
// Register the listener
widget.on('complete', handleComplete);
// Remove the listener
widget.off('complete', handleComplete);
Events
The Payment Widget emits several events during its lifecycle that you can listen to using the on() method.
complete
Fired when the Payment flow is completed.
type PaymentWidgetCompleteValue<T extends PaymentWidgetFlow = PaymentWidgetFlow> =
T extends 'select-for-deposit' ? DepositSelection :
T extends 'select-for-withdrawal' ? WithdrawalSelection :
T extends 'authorize' ? AuthorizeResult :
never;
type PaymentWidgetCompleteEvent<T extends PaymentWidgetFlow = PaymentWidgetFlow> = {
detail: {
value: PaymentWidgetCompleteValue<T>;
};
};
The event.detail.value contains the payment flow result. The structure depends on the flow type.
Example:
widget.on('complete', (event: PaymentWidgetCompleteEvent) => {
const result = event.detail.value;
console.log('Payment flow completed:', result);
// Process the result based on your flow type
// See flow-specific examples below
widget.unmount();
});
Usage in different flows:
For select-for-deposit flows:
const depositWidget = new PaymentWidget<'select-for-deposit'>(session);
depositWidget.on('complete', (event) => {
const result = event.detail.value;
if (result.via === 'external-account') {
// User selected a saved payment method (e.g., card)
console.log('Selected external account:', result.selection);
} else if (result.via === 'deposit-method') {
// User selected a bank or crypto transfer method
const { depositMethod, account } = result.selection;
if (depositMethod.type === 'bank') {
console.log('Bank transfer details:', depositMethod.details);
} else if (depositMethod.type === 'crypto') {
console.log('Crypto transfer details:', depositMethod.details);
}
console.log('Target account:', account);
}
depositWidget.unmount();
});
For select-for-withdrawal flows:
const withdrawWidget = new PaymentWidget<'select-for-withdrawal'>(session);
withdrawWidget.on('complete', (event) => {
const result = event.detail.value;
if (result.via === 'external-account') {
// User selected a saved payment method (e.g., card, bank account)
console.log('Selected external account:', result.selection);
} else if (result.via === 'crypto-network') {
// User provided a crypto withdrawal address
console.log('Crypto withdrawal details:', {
network: result.selection.network,
address: result.selection.address,
reference: result.selection.reference // Destination tag for XRP, memo for XLM, etc.
});
}
withdrawWidget.unmount();
});
For authorize flows:
const authorizeWidget = new PaymentWidget<'authorize'>(session);
authorizeWidget.on('complete', (event) => {
const result = event.detail.value;
if (result.trigger.reason === 'transaction-status-changed') {
// Check transaction status - it may have succeeded or failed
if (result.transaction.status === 'completed') {
console.log('Transaction successful:', result.transaction);
} else if (result.transaction.status === 'failed') {
console.error('Transaction failed:', result.transaction);
// Handle failure case
}
} else if (result.trigger.reason === 'max-retries-reached') {
console.log('Polling timeout reached, transaction may still be processing: ', result.transaction);
// Implement additional polling or show a message indicating that the transaction is still processing and to try again later
}
authorizeWidget.unmount();
});
cancel
Fired when the user cancels the payment flow.
type PaymentWidgetCancelEvent = {
detail: {};
}
Example:
widget.on('cancel', (event: PaymentWidgetCancelEvent) => {
console.log('Payment cancelled by user');
widget.unmount();
});
error
Fired when an unrecoverable error occurs during the payment flow.
type PaymentWidgetError = {
name: string;
code: string;
message: string;
details?: Record<string, unknown>;
cause?: PaymentWidgetError;
httpStatusCode?: number;
}
type PaymentWidgetErrorEvent = {
detail: {
error: PaymentWidgetError;
};
};
Example:
widget.on('error', (event: PaymentWidgetErrorEvent) => {
const { error } = event.detail;
console.error('Payment error:', error);
// Handle specific error types
if (error.code === 'entity_not_found') {
// Quote expired - redirect to create new quote
handleExpiredQuote();
} else if (error.code === 'insufficient_balance') {
// Not enough funds - show funding options
handleInsufficientFunds();
} else {
// Generic error handling
showGenericError(error.message);
}
widget.unmount();
});
ready
Fired when the Payment Widget has finished loading.
type PaymentWidgetReadyEvent = {
detail: {};
}
Example:
widget.on('ready', (event: PaymentWidgetReadyEvent) => {
console.log('Payment Widget is ready');
});
Types
The session object returned by the Create session endpoint.
type PaymentWidgetSession = {
url: string;
token: string;
flow: PaymentWidgetFlow;
}
Represents the different flows supported by the Payment Widget.
type PaymentWidgetFlow = 'select-for-deposit' | 'select-for-withdrawal' | 'authorize';
PaymentMethodOption
Defines the payment methods that can be configured in the Widget options.
type PaymentMethodOption =
| { type: 'card' }
| { type: 'bank'; assets?: PaymentAssetOptions }
| { type: 'crypto'; assets?: PaymentAssetOptions };
| Type | Description |
|---|
card | Credit and debit card payments |
bank | Push bank deposit methods. Supports optional assets filtering |
crypto | Crypto deposits. Supports optional assets filtering |
PaymentAssetOptions
Allows filtering which assets are available when using the bank or crypto payment methods.
type PaymentAssetOptions = {
include?: string[];
exclude?: string[];
};
| Property | Type | Description |
|---|
include | string[] | List of asset codes to include. When specified, only these assets will be available |
exclude | string[] | List of asset codes to exclude. When specified, all assets except these will be available |
Use either include or exclude, not both. Asset codes should be uppercase (e.g., 'BTC', 'ETH', 'XRP').
Complete event result types
DepositSelection
Result structure for select-for-deposit flow:
type ExternalAccountSelection = {
via: 'external-account';
selection: ExternalAccount; // See external accounts API documentation
};
type AccountDepositMethodSelection = {
via: 'deposit-method';
selection: {
depositMethod: AccountDepositMethod; // See account deposit methods API documentation
account: Account; // See accounts API documentation
};
};
type DepositSelection = ExternalAccountSelection | AccountDepositMethodSelection;
For complete type definitions, see the API documentation:
WithdrawalSelection
Result structure for select-for-withdrawal flow:
type ExternalAccountSelection = {
via: 'external-account';
selection: ExternalAccount; // See external accounts API documentation
};
type CryptoNetworkSelection = {
via: 'crypto-network';
selection: {
network: string; // e.g., 'bitcoin', 'ethereum', 'xrp-ledger'
address: string; // The destination crypto address
reference?: string; // Destination tag for XRP, memo for XLM, etc.
};
};
type WithdrawalSelection = ExternalAccountSelection | CryptoNetworkSelection;
For complete ExternalAccount type definition, see the External accounts API documentation.
AuthorizeResult
Result structure for authorize flow:
type AuthorizeResult = {
transaction: Transaction; // See Transactions API documentation
trigger: {
reason: 'transaction-status-changed' | 'max-retries-reached';
};
}
For complete
Transaction type definition, see the
Transactions API documentation.
Complete usage example
Here’s an end-to-end example showing how to use the Payment Widget with all events and type safety:
import { PaymentWidget } from '@uphold/enterprise-payment-widget-web-sdk';
// Create a Payment Widget session from your backend
const session = await createPaymentWidgetSession();
// Initialize the Widget with type inference and configuration
const widget = new PaymentWidget<'select-for-deposit'>(session, {
debug: true,
paymentMethods: [
{ type: 'card' },
{ type: 'bank' },
{ type: 'crypto', assets: { include: ['BTC', 'ETH', 'XRP'] } }
]
});
// Handle ready event
widget.on('ready', () => {
console.log('Payment Widget is ready');
});
// Handle completion with flow-specific type-safe result
widget.on('complete', (event) => {
const result = event.detail.value;
if (result.via === 'external-account') {
console.log('User selected saved payment method:', result.selection);
} else if (result.via === 'deposit-method') {
console.log('User selected deposit method:', result.selection.depositMethod);
console.log('Target account:', result.selection.account);
}
widget.unmount();
});
// Handle cancellation
widget.on('cancel', () => {
console.log('Payment cancelled by user');
widget.unmount();
});
// Handle errors with specific error handling
widget.on('error', (event) => {
const { error } = event.detail;
console.error('Payment error:', error);
if (error.code === 'entity_not_found') {
handleExpiredQuote();
} else if (error.code === 'insufficient_balance') {
handleInsufficientFunds();
} else {
showGenericError(error.message);
}
widget.unmount();
});
// Mount the Widget to a DOM element
widget.mountIframe(document.getElementById('payment-container'));