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;
paymentMethods?: PaymentMethodOption[];
};
| Property | Type | Default | Description |
|---|
debug | boolean | false | Enable debug mode for additional logging |
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.
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'));