Skip to main content
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:
ParameterTypeRequiredDescription
sessionPaymentWidgetSessionYesPayment session object obtained from the Create session endpoint
optionsPaymentWidgetOptionsNoConfiguration 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[];
};
PropertyTypeDefaultDescription
debugbooleanfalseEnable debug mode for additional logging
paymentMethodsPaymentMethodOption[]All available methodsRestrict 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:
widget.unmount();
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

PaymentWidgetSession

The session object returned by the Create session endpoint.
type PaymentWidgetSession = {
  url: string;
  token: string;
  flow: PaymentWidgetFlow;
}

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 };
TypeDescription
cardCredit and debit card payments
bankPush bank deposit methods. Supports optional assets filtering
cryptoCrypto 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[];
};
PropertyTypeDescription
includestring[]List of asset codes to include. When specified, only these assets will be available
excludestring[]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'));