The route_selected callback in the diagram maps to the Widget complete event and returns { via, selection }.The Select for Withdrawal flow lets users pick or add an external account or provide a crypto address to withdraw funds. Refer to the Bank Withdrawal flow or Crypto Withdrawal flow for the backend steps needed to process outgoing funds.
The example code below is for web applications. For native apps using a WebView, you’ll still need a bridge for events, as outlined in Installation & Setup.
Once you have the session, initialize the Payment Widget for the Select for Withdrawal flow:
Copy
Ask AI
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); // Optional: listen for the Widget to be fully loaded widget.on('ready', () => { console.log('Payment Widget is ready'); }); // Mount the Widget in an iframe widget.mountIframe(document.getElementById('payment-container'));};
The complete event is fired when the user successfully selects a withdrawal method.
Copy
Ask AI
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();});
crypto-network - Crypto withdrawal requiring a destination address
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.Crypto Network Method Selection (via: "crypto-network")
When a crypto network is selected, the selection property contains an object with the following structure:
network - The destination crypto network (e.g. bitcoin)
address - The destination crypto address (e.g. 1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa)
reference - The destination address reference, such as a destination tag (if applicable)
After your application collects the withdrawal details and creates the transaction, the Payment Widget does not monitor for the completion of the withdrawal.Your application may optionally implement transaction monitoring to detect when the withdrawal has been processed and provide real-time user feedback. This can be achieved by polling the transactions endpoint to identify when the withdrawal transaction status changes.The following example demonstrates how to poll for withdrawal transaction status:
Monitor withdrawal transaction
Copy
Ask AI
const monitorWithdrawal = async (transactionId) => { const checkWithdrawalStatus = async () => { try { const response = await fetch(`https://api.enterprise.uphold.com/transactions/${transactionId}`, { headers: { 'Authorization': 'Bearer <API_TOKEN>', 'Content-Type': 'application/json', 'X-On-Behalf-Of': 'user <USER_ID>' } }); const transaction = await response.json(); return transaction; } catch (error) { console.error('Error checking withdrawal status:', error); return; } }; // Poll every 30 seconds for up to 10 minutes const pollInterval = 30000; // 30 seconds const maxAttempts = 20; // 10 minutes total let attempts = 0; const poll = setInterval(async () => { attempts++; const transaction = await checkWithdrawalStatus(); if (!transaction) { return; } const isTerminalStatus = ['completed', 'failed', 'cancelled'].includes(transaction.status); if (isTerminalStatus || attempts >= maxAttempts) { clearInterval(poll); if (isTerminalStatus) { handleWithdrawalStatusChange(transaction); return; } if (attempts >= maxAttempts) { console.log('Polling timeout reached without terminal status'); handleWithdrawalTimeout(); } } }, pollInterval);};const handleWithdrawalStatusChange = (transaction) => { console.log('Withdrawal status changed:', transaction); // Check transaction status to determine outcome if (transaction.status === 'completed') { // Update UI to show successful withdrawal showWithdrawalSuccess(transaction); } else if (transaction.status === 'failed') { // Update UI to show failed withdrawal showWithdrawalFailed(transaction); } else if (transaction.status === 'cancelled') { // Update UI to show cancelled withdrawal showWithdrawalCancelled(transaction); }};const handleWithdrawalTimeout = () => { console.log('Withdrawal monitoring timed out'); // Show message that withdrawal is taking longer than expected showWithdrawalPending();};
The cancel event is fired when the user closes the Widget without selecting an external account.
Copy
Ask AI
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};
The error event is fired when an error occurs during the external account selection process.
Copy
Ask AI
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.