> ## Documentation Index
> Fetch the complete documentation index at: https://developer.uphold.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Payment Widget SDK reference

> Reference for the @uphold/enterprise-payment-widget-web-sdk package, including the PaymentWidget class, constructor options, methods, and lifecycle events.

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

```typescript theme={null}
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](/rest-apis/widgets-api/payment/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:**

```typescript theme={null}
// 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

```typescript theme={null}
type PaymentWidgetOptions = {
  authorize?: AuthorizeFlowOptions;
  debug?: boolean;
  layout?: WidgetLayout;
  maxAccountsPerAsset?: number;
  paymentMethods?: PaymentMethodOption[];
  theme?: WidgetThemeOption;
};
```

| Property              | Type                    | Default               | Description                                                                                                                                                                                                                |
| --------------------- | ----------------------- | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `authorize`           | `AuthorizeFlowOptions`  | `{ mode: 'default' }` | Configuration for the `authorize` flow. Ignored for other flows. See [AuthorizeFlowOptions](#authorizeflowoptions) for details                                                                                             |
| `debug`               | `boolean`               | `false`               | Enable debug mode for additional logging                                                                                                                                                                                   |
| `layout`              | `WidgetLayout`          | `'boxed'`             | Control how the Widget is laid out on larger viewports. See [WidgetLayout](#widgetlayout) for details                                                                                                                      |
| `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](#paymentmethodoption) for details                                                                                                         |
| `theme`               | `WidgetThemeOption`     | System preference     | Control the visual appearance of the Widget. See [WidgetThemeOption](#widgetthemeoption) 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:**

```typescript theme={null}
const widget = new PaymentWidget(session, {
  paymentMethods: [
    { type: 'card' },
    { type: 'bank' },
    { type: 'crypto' },
    { type: 'paypal' },
    { type: 'apple-pay'},
    { type: 'google-pay'}
  ]
});
```

**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:

```typescript theme={null}
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:

```typescript theme={null}
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
      }
    }
  ]
});
```

<Note>If no `assets` filter is provided, all supported assets for that payment method will be available. Use either `include` or `exclude`, not both.</Note>

**theme option:**

The `theme` option lets you control the visual appearance of the Widget. By default, the Widget automatically detects and matches the user's browser or OS appearance preference (`light` or `dark`). Use this option when you want to enforce a specific theme regardless of the user's system settings.

```typescript theme={null}
const widget = new PaymentWidget(session, {
  theme: {
    appearance: 'dark',
    primary: { light: '#6200EA', dark: '#BB86FC' },
    // Alternatively, a single color string applies to both appearances, e.g. primary: '#6200EA'
    // primary: '#6200EA',
    fontFamily: 'Inter, sans-serif',
    components: {
      button: { borderRadius: '8px' }
    }
  }
});
```

**layout option:**

The `layout` option controls how the Widget is laid out when there is enough room to frame it — on viewports that are both at least `md` wide (≥768px) and at least 600px tall, i.e. tablets and up. On smaller viewports — narrower or shorter, including phones in landscape — the Widget always fills its container regardless of this option.

* `'boxed'` (default): on viewports that are ≥768px wide and ≥600px tall, centers the Widget and frames its content as a fixed-size card; on smaller viewports it fills its container. Use this when the Widget takes up the whole page (e.g. mounted into a full-page container).
* `'fluid'`: renders the Widget so it fills its container, with no frame or centering, so your own container (e.g. a modal or a sized panel) acts as the frame.

Most integrations should rely on the default `'boxed'` and only set `layout: 'fluid'` when embedding the Widget in your own framed container.

```typescript theme={null}
const widget = new PaymentWidget(session, {
  layout: 'fluid'
});
```

<Note>Use `'fluid'` when you already provide a centered container or modal around the Widget, to avoid a card-within-a-card appearance on larger viewports.</Note>

**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.

```typescript theme={null}
const widget = new PaymentWidget(session, {
  maxAccountsPerAsset: 5
});
```

<Note>Values above `100` are capped at `100`.</Note>

**authorize option:**

The `authorize` option configures the `authorize` flow. It is only relevant for Widgets created with an `authorize` session; it is ignored for `select-for-deposit` and `select-for-withdrawal` flows. Use `mode` to control how the authorization is presented:

* `'default'` (default): the Widget renders its standard authorization UI.
* `'headless'`: the Widget renders only the payment method's button, with no surrounding UI, so you can embed it directly into your own layout. Supported for the Apple Pay authorization flow, and for Google Pay on Android devices that support `CRYPTOGRAM_3DS`.

```typescript theme={null}
const authorizeWidget = new PaymentWidget<'authorize'>(session, {
  authorize: {
    mode: 'headless'
  }
});
```

See [AuthorizeFlowOptions](#authorizeflowoptions) for the full type definition.

<Note>
  Apple Pay inside the Widget is driven by [Apple Pay on the Web](https://developer.apple.com/documentation/apple_pay_on_the_web) via the browser [Payment Request API](https://developer.mozilla.org/en-US/docs/Web/API/Payment_Request_API). In a native app this runs inside the WebView, which imposes requirements beyond the event bridge above. If they are not met, the Widget hides Apple Pay and the user never sees the button.
</Note>

<Warning>
  Because the Widget runs inside an iframe, the Payment Request API only works if the parent page delegates the `payment` [permission](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Permissions_Policy) to that iframe. `mountIframe()` sets this automatically. If you mount the Widget iframe yourself, include `payment` in the `allow` attribute alongside the permissions the Widget already needs:

  ```javascript theme={null}
  iframe.setAttribute('allow', "clipboard-write 'src'; clipboard-read 'src'; payment 'src';");
  ```
</Warning>

## Methods

### `mountIframe()`

Mounts the Payment Widget iframe to the specified DOM element.

**Parameters:**

* `element`: The HTML element where the Widget should be mounted

**Example:**

```javascript theme={null}
// Ensure the container has appropriate sizing
const container = document.getElementById('payment-container');

widget.mountIframe(container);
```

<Info>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.</Info>

### `unmount()`

Unmounts and cleans up the Payment Widget iframe.

**Example:**

```javascript theme={null}
widget.unmount();
```

<Warning>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.</Warning>

### `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:**

```javascript theme={null}
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:**

```javascript theme={null}
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.

```typescript theme={null}
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:**

```typescript theme={null}
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:

```typescript theme={null}
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:

```typescript theme={null}
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:', {
      asset: result.selection.asset,
      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:

```typescript theme={null}
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.

```typescript theme={null}
type PaymentWidgetCancelEvent = {
  detail: {};
}
```

**Example:**

```javascript theme={null}
widget.on('cancel', (event: PaymentWidgetCancelEvent) => {
  console.log('Payment cancelled by user');
  widget.unmount();
});
```

### `error`

Fired when an unrecoverable error occurs during the payment flow.

```typescript theme={null}
type PaymentWidgetError = {
  name: string;
  code: string;
  message: string;
  details?: Record<string, unknown>;
  cause?: PaymentWidgetError;
  httpStatusCode?: number;
}

type PaymentWidgetErrorEvent = {
  detail: {
    error: PaymentWidgetError;
  };
};
```

**Example:**

```javascript theme={null}
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.

```typescript theme={null}
type PaymentWidgetReadyEvent = {
  detail: {};
}
```

**Example:**

```typescript theme={null}
widget.on('ready', (event: PaymentWidgetReadyEvent) => {
  console.log('Payment Widget is ready');
});
```

## Types

### PaymentWidgetSession

The session object returned by the [Create session](/rest-apis/widgets-api/payment/create-session) endpoint.

```typescript theme={null}
type PaymentWidgetSession = {
  url: string;
  token: string;
  flow: PaymentWidgetFlow;
}
```

### `PaymentWidgetFlow`

Represents the different flows supported by the Payment Widget.

```typescript theme={null}
type PaymentWidgetFlow = 'select-for-deposit' | 'select-for-withdrawal' | 'authorize';
```

### AuthorizeFlowOptions

Configuration for the `authorize` flow, passed via the `authorize` option.

```typescript theme={null}
type AuthorizeFlowOptions = {
  mode?: AuthorizeMode;
};
```

| Property | Type            | Default     | Description                                                                                                      |
| -------- | --------------- | ----------- | ---------------------------------------------------------------------------------------------------------------- |
| `mode`   | `AuthorizeMode` | `'default'` | Selects how much UI the Widget renders around the authorization. See [AuthorizeMode](#authorizemode) for details |

### AuthorizeMode

Selects how much UI the Widget renders around the authorization. Both modes handle creating the transaction, and polling it to a final status. What differs is the UI the Widget shows — and therefore what your app is responsible for providing.

```typescript theme={null}
type AuthorizeMode = 'default' | 'headless';
```

| Value        | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `'default'`  | The Widget renders the full authorization experience: a short "what to expect" walkthrough, the authorization button, back and close controls, and a processing screen while the transaction is confirmed. Use this when the Widget owns the authorization screen.                                                                                                                                                                                                              |
| `'headless'` | The Widget renders **only** the payment method's button — no walkthrough, navigation, or processing screen. After authorization, it creates and polls the transaction in the background and hands control back to your app, which owns the surrounding context and the post-authorization experience (progress and success feedback, and a way to cancel). Supported for the Apple Pay authorization flow, and for Google Pay on Android devices that support `CRYPTOGRAM_3DS`. |

<Note>
  Regardless of mode, the Apple Pay button only appears in [supported environments](https://support.apple.com/en-us/102896), and the Google Pay button only appears on Android devices that support `CRYPTOGRAM_3DS` when `'headless'` mode is used. In `'headless'` mode there is no surrounding UI, so make sure your layout handles the case where the button is not rendered.
</Note>

### PaymentMethodOption

Defines the payment methods that can be configured in the Widget options.

```typescript theme={null}
type PaymentMethodOption =
  | { type: 'card' }
  | { type: 'bank'; assets?: PaymentAssetOptions }
  | { type: 'crypto'; assets?: PaymentAssetOptions }
  | { type: 'paypal' }
  | { type: 'apple-pay' }
  | { type: 'google-pay' };

```

| Type         | Description                                                       |
| ------------ | ----------------------------------------------------------------- |
| `card`       | Credit and debit card payments                                    |
| `bank`       | Push bank deposit methods. Supports optional `assets` filtering   |
| `crypto`     | Crypto deposits/withdrawals. Supports optional `assets` filtering |
| `paypal`     | PayPal deposits/withdrawals                                       |
| `apple-pay`  | ApplePay deposits/withdrawals                                     |
| `google-pay` | GooglePay deposits                                                |

### PaymentAssetOptions

Allows filtering which assets are available when using the `bank` or `crypto` payment methods.

```typescript theme={null}
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 |

<Note>Use either `include` or `exclude`, not both. Asset codes should be uppercase (e.g., `'BTC'`, `'ETH'`, `'XRP'`).</Note>

### Complete event result types

#### DepositSelection

Result structure for `select-for-deposit` flow:

```typescript theme={null}
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;
```

<Note>
  For complete type definitions, see the API documentation:

  * `ExternalAccount`: [External accounts](/rest-apis/core-api/external-accounts/introduction)
  * `AccountDepositMethod`: [Account deposit methods](/rest-apis/core-api/accounts/get-account-deposit-method)
  * `Account`: [Accounts](/rest-apis/core-api/accounts/introduction)
</Note>

#### WithdrawalSelection

Result structure for `select-for-withdrawal` flow:

```typescript theme={null}
type ExternalAccountSelection = {
  via: 'external-account';
  selection: ExternalAccount; // See external accounts API documentation
};

type CryptoNetworkSelection = {
  via: 'crypto-network';
  selection: {
    asset: string;  // e.g., 'BTC', 'ETH', 'XRP'
    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;
```

<Note>
  For complete `ExternalAccount` type definition, see the [External accounts](/rest-apis/core-api/external-accounts/introduction) API documentation.
</Note>

#### AuthorizeResult

Result structure for `authorize` flow:

```typescript theme={null}
type AuthorizeResult = {
  transaction: Transaction; // See Transactions API documentation
  trigger: {
    reason: 'transaction-status-changed' | 'max-retries-reached';
  };
}
```

<Note>For complete `Transaction` type definition, see the [Transactions](/rest-apis/core-api/transactions/introduction) API documentation.</Note>

### WidgetLayout

Controls how the Widget is laid out on larger viewports.

```typescript theme={null}
type WidgetLayout = 'boxed' | 'fluid';
```

| Value     | Description                                                                                                                                                                              |
| --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `'boxed'` | Default. On viewports that are ≥768px wide and ≥600px tall (tablets and up), centers the Widget and frames its content as a fixed-size card; on smaller viewports it fills its container |
| `'fluid'` | Renders the Widget so it fills its container, with no frame or centering, so your own container acts as the frame                                                                        |

### WidgetThemeOption

Controls the visual appearance of the Widget.

```typescript theme={null}
type WidgetThemeOption = {
  appearance?: 'light' | 'dark';
  primary?: ColorTokenValue;
  primaryForeground?: ColorTokenValue;
  foreground?: ColorTokenValue;
  emphasisForeground?: ColorTokenValue;
  background?: ColorTokenValue;
  fontFamily?: FontFamily;
  components?: {
    button?: { borderRadius?: string };
    input?: { borderRadius?: string };
    card?: { borderRadius?: string };
  };
};
```

| Property             | Type                | Description                                                                                            |
| -------------------- | ------------------- | ------------------------------------------------------------------------------------------------------ |
| `appearance`         | `'light' \| 'dark'` | Forces the Widget to render in light or dark mode, overriding the user's system preference             |
| `primary`            | `ColorTokenValue`   | Primary brand color, used for buttons and key interactive elements                                     |
| `primaryForeground`  | `ColorTokenValue`   | Text color rendered on top of the primary color                                                        |
| `foreground`         | `ColorTokenValue`   | Main text color                                                                                        |
| `emphasisForeground` | `ColorTokenValue`   | Emphasized text color                                                                                  |
| `background`         | `ColorTokenValue`   | Widget background color                                                                                |
| `fontFamily`         | `FontFamily`        | Font family applied across the Widget. See [FontFamily](#fontfamily) for details                       |
| `components`         | `object`            | Per-component style overrides for `button`, `input`, and `card` (each accepts `borderRadius?: string`) |

### ColorTokenValue

A color value that can be a single string applied to both light and dark modes, or separate values per mode.

```typescript theme={null}
type ColorTokenValue = string | { light: string; dark: string };
```

### FontFamily

A font family that can be a single string applied to all slots, or separate values per slot (`mono`, `sans`, `serif`).

```typescript theme={null}
type FontFamily = string | Partial<Record<'mono' | 'sans' | 'serif', string>>;
```

## Complete usage example

Here's an end-to-end example showing how to use the Payment Widget with all events and type safety:

```typescript theme={null}
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'] } },
    { type: 'paypal' },
    { type: 'apple-pay'},
    { type: 'google-pay'}
  ]
});

// 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'));
```
