The Select for Withdrawal use case allows users to select an external account to off-board their funds. Users can choose previously linked external accounts or add new ones to withdraw to.

Available Payment Methods

  • Credit/Debit Cards - Visa and Mastercard
  • FPS (Faster Payment System) - Instant payment service for UK residents

Integration

Here’s how you can leverage the Payment Widget SDK to offer easy withdrawals:

Create Select for Withdrawal session

Before initializing the Widget, create a payment session for the Select for Withdrawal flow using the REST API as shown below.
curl -X POST https://api.enterprise.uphold.com/widgets/payment/sessions \
  -H "Authorization: Bearer <API_TOKEN>" \
  -H "Content-Type: application/json" \
  -H "X-On-Behalf-Of: user <USER_ID>" \
  -d '{
    "flow": "select-for-withdrawal"
  }'

Setting Up the Widget

The example code below is for web applications. For native applications using a WebView, you’ll still need to implement communication through a bridge to send events to the native side, as highlighted in the Using the SDK page.
Once you have the session, initialize the Payment Widget for the Select for Withdrawal flow:
import { PaymentWidget } from '@uphold/enterprise-payment-widget-web-sdk';

const initializeWithdrawalWidget = async () => {
  // Create the session
  const sessionData = await createWithdrawalSession();

  // Initialize the Widget with the session
  const widget = new PaymentWidget<'select-for-withdrawal'>(sessionData.session, { debug: true });

  // Set up event handlers (see sections below)
  setupEventHandlers(widget);

  // Mount the Widget
  widget.mountIframe(document.getElementById('payment-container'));
};

Handling the complete event

The complete event is fired when the user successfully selects a withdrawal method.
widget.on('complete', (event) => {
  const result = event.detail.value;
  console.log('Withdrawal destination selected:', result);

  // result.via indicates the type of selection
  const { via, selection } = result;

  // Process the selected external account
  handleWithdrawalMethodSelected(via, selection);

  // Clean up the Widget
  widget.unmount();
});

Event Data

The complete event payload contains two primary properties:
  • via - Specifies the type of deposit method selected:
    • external-account - Previously linked payment method (e.g., saved card)
  • selection - Contains the method data structure
External Account Selection (via: "external-account") When an external account is selected, the selection property contains an external account object with the saved payment method details.
const handleWithdrawalMethodSelected = (via, selection) => {
  if (via === 'external-account') {
    // selection is an ExternalAccount
    console.log('Selected external account:', {
      id: selection.id,
      type: selection.type, // 'card' or 'bank'
      label: selection.label,
      // Additional properties depend on external account type
    });

    // Proceed with existing external account
    proceedWithExternalAccount(selection);
  }
};

Handling the cancel event

The cancel event is fired when the user closes the Widget without selecting an external account.
widget.on('cancel', () => {
  console.log('User cancelled withdrawal destination selection');

  // Handle cancellation
  handleWithdrawalCancelled();

  // Clean up the Widget
  widget.unmount();
});

const handleWithdrawalCancelled = () => {
  // Redirect back to the previous page or main withdrawal page
};

Handling the error event

The error event is fired when an error occurs during the external account selection process.
widget.on('error', (event) => {
  const error = event.detail.error;
  console.error('Withdrawal Widget error:', error);

  // Handle the error
  handleWithdrawalError(error);

  // Clean up the Widget
  widget.unmount();
});

const handleWithdrawalError = (error) => {
  console.error('Error details:', {
    code: error.code,
    message: error.message
  });

  // Show user-friendly error message like 'An error occurred. Please try again later.'
};
The Payment Widget does not offer user-facing error handling. It’s the responsibility of the host application to present an error message to the user and unmount the Widget.

Complete Implementation Example

Here’s a complete example combining all the event handlers:
import { PaymentWidget } from '@uphold/enterprise-payment-widget-web-sdk';

class WithdrawalDestinationSelector {
  constructor() {
    this.widget = null;
  }

  async initialize() {
    try {
      // Create session for withdrawal flow
      const sessionData = await this.createWithdrawalSession();

      // Initialize Widget
      this.widget = new PaymentWidget<'select-for-withdrawal'>(sessionData.session, { debug: true });

      // Set up all event handlers
      this.setupEventHandlers();

      // Mount the Widget in an iframe
      this.widget.mountIframe(document.getElementById('payment-container'));
    } catch (error) {
      console.error('Failed to initialize Withdrawal Widget:', error);
      this.handleInitializationError(error);
    }
  }

  async createWithdrawalSession() {
    const response = await fetch('https://api.enterprise.uphold.com/widgets/payment/sessions', {
      method: 'POST',
      headers: {
        'Authorization': 'Bearer <API_TOKEN>',
        'Content-Type': 'application/json',
        'X-On-Behalf-Of': 'user <USER_ID>'
      },
      body: JSON.stringify({
        flow: 'select-for-withdrawal'
      })
    });

    if (!response.ok) {
      throw new Error('Failed to create withdrawal session');
    }

    return await response.json();
  }

  setupEventHandlers() {
    // Handle successful selection
    this.widget.on('complete', (event) => {
      const { via, selection } = event.detail.value;
      console.log('External account selected:', { via, selection });

      this.handleWithdrawalMethodSelected(via, selection);
      this.widget.unmount();
    });

    // Handle cancellation
    this.widget.on('cancel', () => {
      console.log('Selection cancelled');
      this.handleCancellation();
      this.widget.unmount();
    });

    // Handle errors
    this.widget.on('error', (event) => {
      console.error('Widget error:', event.detail.error);
      this.handleError(event.detail.error);
      this.widget.unmount();
    });
  }

  handleWithdrawalMethodSelected(via, selection) {
    if (via === 'external-account') {
      // This is an ExternalAccount
      console.log('External account selected:', selection);
    }
  }

  handleCancellation() {
    // Show cancellation message
    alert('Withdrawal method selection was cancelled');
  }

  handleError(error) {
    alert('An error occurred. Please try again later.');
  }

  handleInitializationError(error) {
    console.error('Initialization failed:', error);
    alert('Failed to load withdrawal methods. Please try again later.');
  }
}

// Usage
const withdrawalSelector = new WithdrawalDestinationSelector();
withdrawalSelector.initialize();

Next Steps

After the user selects an external account to withdraw to, you’ll typically want to:
  1. Collect withdrawal details - Collect remaining instructions from the user (e.g. amount, origin account)
  2. Create withdrawal transaction - Use the selected external account to create the actual withdrawal. If the selected payment method is a card, you’ll need to use the Authorize flow for additional authentication

Additional Resources