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

# Apple Pay withdrawal via the Payment Widget

> Pay out from a user's account to Apple Pay using the Uphold Payment Widget.

export const apmLabel_3 = "Apple Pay"

export const apmLabel_2 = "Apple Pay"

export const direction_0 = "withdrawal"

export const apmLabel_1 = "Apple Pay"

export const apmLabel_0 = "Apple Pay"

The Payment Widget handles Apple Pay selection for withdrawals via the **Select for Withdrawal flow**, where users can select Apple Pay directly in the widget. After the user confirms an Apple Pay withdrawal quote, the Payment Widget creates the transaction and completes the Apple Pay authorization via the **Authorize flow**.

## Prerequisites

* The user has [completed onboarding](/developer-guides/user-onboarding/overview).
* The `apple-pay-withdrawals` capability is enabled.
* A **funded account** to debit the funds from.
* The Payment Widget is [set up in your frontend](/widgets/payment/installation-and-setup).
* [Apple Pay's additional setup requirements](/developer-guides/apm-transfers/overview#apple-pay) are met.
* The target browser or platform [supports Apple Pay](/developer-guides/apm-transfers/overview#browser-and-platform-compatibility-payment-widget).

## Walkthrough

```mermaid theme={null}
sequenceDiagram
  autonumber
  participant Usr as User
  participant U as Your App
  participant B as Your Backend
  participant P as Payment Widget
  participant A as Uphold

  Usr->>U: Start withdrawal
  U->>B: List accounts
  B->>A: GET /core/accounts
  A-->>B: { accounts }
  B-->>U: { accounts }
  Usr->>U: Choose source account
  U->>B: Create widget session
  B->>A: Create widget session (select-for-withdrawal)
  A-->>B: { session }
  B-->>U: { session }
  U->>P: Initialize widget
  Usr->>P: Select Apple Pay
  P-->>U: complete { via, selection }
  Usr->>U: Choose amount
  U->>B: Create quote
  B->>A: Create quote (account → APM)
  A-->>B: { quote }
  B-->>U: { quote }
  U->>B: Create authorize session
  B->>A: Create widget session (authorize)
  A-->>B: { session }
  B-->>U: { session }
  U->>P: Initialize widget
  Usr->>P: Authorize with Apple Pay sheet
  P->>A: Create transaction
  A-->>P: { transaction }
  P-->>U: complete { transaction, trigger }
  B-->>Usr: Notify the user
```

***

## Select source account

{apmLabel_3} withdrawals can be sourced from any account. If the selected account is not in the {apmLabel_3} account's currency, the balance will be converted at the time of the transaction using Uphold's prevailing rate. Make sure the origin asset has the necessary [features enabled](/rest-apis/core-api/assets/introduction#features-and-deposits-/-withdrawals).

Call [List accounts](/rest-apis/core-api/accounts/list-accounts) to retrieve the user's accounts and let them pick the one to withdraw from.

```http theme={null}
GET /core/accounts
```

```json theme={null}
{
  "accounts": [
    {
      "id": "a00507fe-628c-4f27-ae81-e1c40b2a8fb8",
      "ownerId": "e4ce04dc-67b7-4e9f-af91-482cb6f9fc4a",
      "label": "My USD account",
      "asset": "USD",
      "balance": {
        "total": "500.00",
        "available": "500.00"
      }
    }
  ]
}
```

***

## Select withdrawal method

The Payment Widget's **Select for Withdrawal flow** presents the available payment methods, letting the user select Apple Pay when it's available. It performs **selection only**: it does not create the quote or the transaction.

### Create a widget session

Call [Create widget session](/rest-apis/widgets-api/payment/create-session) to start the `select-for-withdrawal` flow. To customize the theme and layout, see the example [here](/widgets/payment/installation-and-setup#1-create-a-session-on-your-backend).

```http theme={null}
POST /widgets/payment/sessions
{
  "flow": "select-for-withdrawal"
}
```

The response contains a `session` object with a `url` field that loads the widget. Return `response.session` to your frontend as is.

```json theme={null}
{
  "session": {
    "url": "https://payment-widget.enterprise.uphold.com/?sessionToken=..."
  }
}
```

### Set up the widget

<CodeGroup>
  ```javascript Web SDK [expandable] theme={null}
  import { PaymentWidget } from '@uphold/enterprise-payment-widget-web-sdk';

  // session is `response.session` from your backend
  const initializeWithdrawalWidget = async (session) => {
    const widget = new PaymentWidget<'select-for-withdrawal'>(session, { debug: true });

    widget.on('complete', (event) => {
      console.log('Complete', JSON.stringify(event.detail.value));
      widget.unmount();
    });

    widget.on('cancel', () => {
      console.log('Cancelled');
      widget.unmount();
    });

    widget.on('error', (event) => {
      console.error('Error', event.detail.error);
      widget.unmount();
    });

    widget.mountIframe(document.getElementById('payment-container'));
  };
  ```

  ```html Without SDK [expandable] theme={null}
  <div id="payment-container"></div>

  <script>
    // session is `response.session` from your backend
    async function initializeWithdrawalWidget(session) {
      const container = document.getElementById('payment-container');
      const sessionOrigin = new URL(session.url).origin;

      const iframe = document.createElement('iframe');
      iframe.src = session.url;
      iframe.setAttribute('allow', "clipboard-write 'src'; clipboard-read 'src'; payment 'src';");
      iframe.style.width = '100%';
      iframe.style.height = '100%';
      iframe.style.border = 'none';

      function teardown() {
        window.removeEventListener('message', onMessage);
        iframe.remove();
      }

      function onMessage(event) {
        if (event.origin !== sessionOrigin) return;

        switch (event.data?.type) {
          case 'load':
            // Optional: repeat theme or layout from Create session to avoid a brief flash of defaults
            iframe.contentWindow.postMessage({ options: {}, type: 'init' }, sessionOrigin);
            break;
          case 'ready':
            break;
          case 'complete':
            console.log('Complete', JSON.stringify(event.data.value));
            teardown();
            break;
          case 'cancel':
            console.log('Cancelled');
            teardown();
            break;
          case 'error':
            console.error('Error', event.data.error);
            teardown();
            break;
        }
      }

      window.addEventListener('message', onMessage);
      container.appendChild(iframe);
    }
  </script>
  ```
</CodeGroup>

<Info>
  Both examples above are for web applications — either creating the iframe yourself or letting the SDK do it. For native apps using a WebView, see [Native apps with the Web SDK](/widgets/payment/installation-and-setup#native-apps-with-the-web-sdk) for the SDK's native-bundling pattern, or [Setup without the SDK](/widgets/payment/installation-and-setup#setup-without-the-sdk) for the no-SDK approach that loads the session `url` directly as the WebView's top-level page.
</Info>

### Handle the complete event

The `complete` event fires after the user selects Apple Pay.

<CodeGroup>
  ```javascript Web SDK theme={null}
  widget.on('complete', (event) => {
    const { via, selection } = event.detail.value;

    // If via is 'apm', you can check the selected method through the property `selection.method`, which will be 'apple-pay' in this case.
    if (via === 'apm' && selection.method === 'apple-pay') {
      handleApplePaySelected();
    }

    widget.unmount();
  });
  ```

  ```javascript Without SDK theme={null}
  // Inside the onMessage switch from Set up the widget
  case 'complete': {
    const { via, selection } = event.data.value;

    // If via is 'apm', you can check the selected method through the property `selection.method`, which will be 'apple-pay' in this case.
    if (via === 'apm' && selection.method === 'apple-pay') {
      handleApplePaySelected();
    }

    teardown();
    break;
  }
  ```
</CodeGroup>

Once you have the selection, proceed to [Create a quote](#create-a-quote).

### Handle cancellations

<CodeGroup>
  ```javascript Web SDK theme={null}
  widget.on('cancel', () => {
    widget.unmount();
    // Return the user to the previous screen
  });
  ```

  ```javascript Without SDK theme={null}
  // Inside the onMessage switch from Set up the widget
  case 'cancel':
    teardown();
    // Return the user to the previous screen
    break;
  ```
</CodeGroup>

### Handle errors

The `error` event fires for critical unrecoverable errors.

<CodeGroup>
  ```javascript Web SDK theme={null}
  widget.on('error', (event) => {
    console.error('Widget error:', event.detail.error);
    widget.unmount();
    // Show a user-friendly error message
  });
  ```

  ```javascript Without SDK theme={null}
  // Inside the onMessage switch from Set up the widget
  case 'error':
    console.error('Widget error:', event.data.error);
    teardown();
    // Show a user-friendly error message
    break;
  ```
</CodeGroup>

<Warning>The Payment Widget handles most errors internally. For unrecoverable errors, the widget fires an `error` event. It is the host application's responsibility to handle these events, present an error message to the user, and unmount the widget.</Warning>

***

## Create a quote

Call [Create quote](/rest-apis/core-api/transactions/create-quote) with the user's account as the origin and Apple Pay as the destination.

Specify Apple Pay as the destination with `type: "apm"` and `method: "apple-pay"`.

```http theme={null}
POST /core/transactions/quote
{
  "origin": {
    "type": "account",
    "id": "b8618cd1-ccb0-4a72-985f-3bb0d268dabd"
  },
  "destination": {
    "type": "apm",
    "method": "apple-pay"
  },
  "denomination": {
    "asset": "USD",
    "amount": "15",
    "target": "origin"
  }
}
```

A successful response includes the quote details and a `requirements` array. For Apple Pay, it contains `authorize:apple-pay`, which indicates that the user must authorize Apple Pay before the transaction can be created.

```json [expandable] theme={null}
{
  "quote": {
    "id": "c3e8d2f7-9a41-4b75-b8e3-1d6f4a9c2e57",
    "origin": {
      "amount": "15.00",
      "asset": "USD",
      "node": {
        "type": "account",
        "id": "b8618cd1-ccb0-4a72-985f-3bb0d268dabd",
        "ownerId": "48e40cb2-6c34-44ce-b2f1-6adac459bb37"
      },
      "rate": "1"
    },
    "destination": {
      "amount": "15.00",
      "asset": "USD",
      "node": {
        "type": "apm",
        "method": "apple-pay"
      },
      "rate": "1"
    },
    "denomination": {
      "asset": "USD",
      "amount": "15.00",
      "target": "origin",
      "rate": "1"
    },
    "fees": [],
    "expiresAt": "2025-06-18T01:55:39Z",
    "requirements": [
      "authorize:apple-pay"
    ]
  }
}
```

***

## Authorize and create the transaction

After the user confirms the Apple Pay quote, hand off to the Payment Widget **Authorize flow**. It presents the Apple Pay sheet, creates the transaction, and polls until a terminal status is reached. Apple Pay authorizes **per transaction** on the user's device — there is no stored authorization to reuse, so the user confirms with Face ID, Touch ID, or their passcode every time. By default, the widget renders a full walkthrough around the authorization; in **headless mode**, it renders only the Apple Pay button so you can embed it directly into your own UI — see [Headless mode](#headless-mode) below.

### Create an authorize session

Call [Create widget session](/rest-apis/widgets-api/payment/create-session) to start the `authorize` flow, passing the `quoteId` and adding `authorize:apple-pay` to the `requirements` array. For web apps, also include the top-page `domain`. To enable [headless mode](#headless-mode), set `authorize.mode` to `headless` in `options`. To customize the theme and layout, see the example [here](/widgets/payment/installation-and-setup#1-create-a-session-on-your-backend).

<Note>
  The top-page domain is the domain shown in the browser's URL bar — the very top-level page hosting the widget iframe. For web apps, it must match the domain you registered with Apple Pay for your merchant ID.
</Note>

```http theme={null}
POST /widgets/payment/sessions
{
  "flow": "authorize",
  "data": {
    "quoteId": "<quoteId>",
    "requirements": [
      "authorize:apple-pay"
    ],
    "domain": "<top-page-domain>" // For web apps only, required for Apple Pay
  }
}
```

The response contains a `session` object with a `url` field that loads the widget. Return `response.session` to your frontend as is.

```json theme={null}
{
  "session": {
    "url": "https://payment-widget.enterprise.uphold.com/?sessionToken=..."
  }
}
```

### Set up the widget

Initialize the widget with the session. The widget presents the {apmLabel_0} sheet, collects device data, creates the transaction, and polls until a terminal status is reached.

<CodeGroup>
  ```javascript Web SDK [expandable] theme={null}
  import { PaymentWidget } from '@uphold/enterprise-payment-widget-web-sdk';

  // session is `response.session` from your backend
  const initializeAuthorizeWidget = async (session) => {
    const widget = new PaymentWidget<'authorize'>(session, { debug: true });

    widget.on('complete', (event) => {
      const { transaction, trigger } = event.detail.value;
      console.log('Complete', transaction.status, trigger.reason);
      widget.unmount();
    });

    widget.on('cancel', () => {
      console.log('Cancelled');
      widget.unmount();
    });

    widget.on('error', (event) => {
      console.error('Error', event.detail.error);
      widget.unmount();
    });

    widget.mountIframe(document.getElementById('payment-container'));
  };
  ```

  ```javascript Without SDK [expandable] theme={null}
  // session is `response.session` from your backend
  async function initializeAuthorizeWidget(session) {
    const container = document.getElementById('payment-container');
    const sessionOrigin = new URL(session.url).origin;

    const iframe = document.createElement('iframe');
    iframe.src = session.url;
    iframe.setAttribute('allow', "clipboard-write 'src'; clipboard-read 'src'; payment 'src';");
    iframe.style.width = '100%';
    iframe.style.height = '100%';
    iframe.style.border = 'none';

    function teardown() {
      window.removeEventListener('message', onMessage);
      iframe.remove();
    }

    function onMessage(event) {
      if (event.origin !== sessionOrigin) return;

      switch (event.data?.type) {
        case 'load':
          // Optional: repeat theme, layout, or authorize.mode from Create session to avoid a brief flash of defaults
          iframe.contentWindow.postMessage({ options: {}, type: 'init' }, sessionOrigin);
          break;
        case 'complete': {
          const { transaction, trigger } = event.data.value;
          console.log('Complete', transaction.status, trigger.reason);
          teardown();
          break;
        }
        case 'cancel':
          console.log('Cancelled');
          teardown();
          break;
        case 'error':
          console.error('Error', event.data.error);
          teardown();
          break;
      }
    }

    window.addEventListener('message', onMessage);
    container.appendChild(iframe);
  }
  ```
</CodeGroup>

<Info>
  Both examples above are for web applications — either creating the iframe yourself or letting the SDK do it. For native apps using a WebView, see [Native apps with the Web SDK](/widgets/payment/installation-and-setup#native-apps-with-the-web-sdk) for the SDK's native-bundling pattern, or [Setup without the SDK](/widgets/payment/installation-and-setup#setup-without-the-sdk) for the no-SDK approach that loads the session `url` directly as the WebView's top-level page.
</Info>

### Headless mode

By default, the widget renders a full authorization experience — a short walkthrough, the {apmLabel_0} button, and a processing screen while the transaction is confirmed. In **headless mode**, it renders only the {apmLabel_0} button, with no surrounding UI, so you can embed it directly into your own layout. Your app then owns the surrounding context and the post-authorization experience — progress and success feedback, and a way to cancel. {apmLabel_0 === 'Google Pay' && `Because there's no surrounding UI to present a 3DS challenge, headless mode is limited to Android devices with cards that support CRYPTOGRAM_3DS authentication.`}

To enable it, set `authorize.mode` to `headless` in the `options` of the [Create widget session](/rest-apis/widgets-api/payment/create-session) request:

```http theme={null}
POST /widgets/payment/sessions
{
  "flow": "authorize",
  "data": { ... }, // Same data as in Create an authorize session
  "options": {
    "authorize": {
      "mode": "headless"
    }
  }
}
```

See [`AuthorizeFlowOptions`](/widgets/payment/sdk-reference#authorizeflowoptions) in the SDK reference for the full type definition.

### Handle the complete event

<Warning>The `complete` event does not guarantee success. Always check `transaction.status` and `trigger.reason`.</Warning>

<CodeGroup>
  ```javascript Web SDK theme={null}
  widget.on('complete', (event) => {
    const { transaction, trigger } = event.detail.value;

    if (trigger.reason === 'transaction-status-changed') {
      if (transaction.status === 'completed') {
        // Show success — the transfer settled
      } else if (transaction.status === 'failed') {
        // Map transaction.statusDetails.reason to a user-facing message
      }
    } else if (trigger.reason === 'max-retries-reached') {
      // Widget stopped polling — continue monitoring via webhooks or polling
    }

    widget.unmount();
  });
  ```

  ```javascript Without SDK theme={null}
  // Inside the onMessage switch from Set up the widget
  case 'complete': {
    const { transaction, trigger } = event.data.value;

    if (trigger.reason === 'transaction-status-changed') {
      if (transaction.status === 'completed') {
        // Show success — the transfer settled
      } else if (transaction.status === 'failed') {
        // Map transaction.statusDetails.reason to a user-facing message
      }
    } else if (trigger.reason === 'max-retries-reached') {
      // Widget stopped polling — continue monitoring via webhooks or polling
    }

    teardown();
    break;
  }
  ```
</CodeGroup>

Failure reasons in `transaction.statusDetails.reason`:

| Reason | Description |
| - | - |
| `apm-authorization-failed` | The {apmLabel_0} authorization could not be completed |
| `card-declined` | The card was declined |
| `card-declined-by-bank` | The card was declined by the issuing bank |
| `card-expired` | The card has expired |
| `card-permanently-declined-by-bank` | The card was permanently declined |
| `card-unauthorized` | The card authorization was not completed |
| `card-unsupported` | The card is not supported for this operation |
| `insufficient-funds` | The origin account has insufficient funds |
| `provider-maximum-limit-exceeded` | The transaction exceeds provider limits |
| `velocity` | The transaction was blocked by velocity rules |
| `unspecified-error` | The transaction failed for an unspecified reason |

### Handle cancellations

The `cancel` event fires when the user dismisses the {apmLabel_0} sheet or navigates back without completing authorization.

<CodeGroup>
  ```javascript Web SDK  theme={null}
  widget.on('cancel', () => {
    widget.unmount();
    // Return the user to the previous screen
  });
  ```

  ```javascript Without SDK theme={null}
  // Inside the onMessage switch from Set up the widget
  case 'cancel':
    teardown();
    // Return the user to the previous screen
    break;
  ```
</CodeGroup>

### Handle errors

The `error` event fires for critical unrecoverable errors — except `authorize_transaction_failed`, which is retryable **in headless mode**: the widget resets itself back to its ready state, so the {apmLabel_0} button works again if you leave the widget mounted. In default mode there is no in-place retry for this code — the button does not become usable again, so unmount and create a new authorize session if you want the user to try again.

`authorize_transaction_failed` is the retryable code for {apmLabel_0} authorization and transaction-creation failures. `event.detail.error.details.reason` narrows down where it happened:

<table>
  <thead>
    <tr>
      <th>Reason</th>
      <th>Description</th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td><code>unable-to-create-payment-request</code></td>
      <td>The browser could not build the {apmLabel_0} payment request</td>
    </tr>

    <tr>
      <td><code>unable-to-make-payment</code></td>
      <td>The device or browser reported it cannot make this payment</td>
    </tr>

    {apmLabel_0 === 'Apple Pay' && (
            <tr>
              <td><code>unable-to-create-merchant-session</code></td>
              <td>Merchant session validation with Apple failed</td>
            </tr>
          )}

    <tr>
      <td><code>unable-to-show-payment-request</code></td>
      <td>The {apmLabel_0} sheet could not be shown</td>
    </tr>

    <tr>
      <td><code>invalid-payment-response</code></td>
      <td>The {apmLabel_0} sheet returned a response without the expected payment token</td>
    </tr>

    <tr>
      <td><code>unable-to-create-transaction</code></td>
      <td>{apmLabel_0} authorization succeeded, but the transaction itself could not be created — see <code>event.detail.error.cause</code> below for the underlying reason</td>
    </tr>
  </tbody>
</table>

Other failures in this flow — such as a missing or expired quote, or the SDK being unavailable — surface with their own `code` and are not retryable; handle those with a generic fallback.

As with any Widget error, the original failure is preserved in [`event.detail.error.cause`](/widgets/payment/sdk-reference#error). When `details.reason` is `unable-to-create-transaction`, `event.detail.error.cause.code` is one of:

| Code | Description |
| - | - |
| `entity_not_found` | The quote was not found or has expired |
| `insufficient_balance` | The origin account has insufficient balance |
| `operation_not_allowed` | The operation is not permitted |
| `user_capability_failure` | The user lacks the required capability for this operation |

<CodeGroup>
  ```javascript Web SDK theme={null}
  // Set this to match how you configured the widget — see Headless mode above
  const isAuthorizeHeadless = false;

  widget.on('error', (event) => {
    const { code, cause, details } = event.detail.error;
    console.error('Widget error:', code, details, cause);

    if (code === 'authorize_transaction_failed') {
      if (details.reason === 'unable-to-create-transaction') {
        // The real reason is nested here, not in the top-level `code`
        console.error('Create transaction failed:', cause?.code);
      }

      if (isAuthorizeHeadless) {
        // Retryable in headless mode — keep the widget mounted if you want the user to try again
        return;
      }
      // In default mode there is no in-place retry for this code — fall through and unmount
    }

    widget.unmount();
    // Show a user-friendly error message
  });
  ```

  ```javascript Without SDK theme={null}
  // Inside the onMessage switch from Set up the widget. `isAuthorizeHeadless` is declared once
  // outside the handler (alongside `sessionOrigin`), matching how you configured the widget.
  case 'error': {
    const { code, cause, details } = event.data.error;
    console.error('Widget error:', code, details, cause);

    if (code === 'authorize_transaction_failed') {
      if (details.reason === 'unable-to-create-transaction') {
        console.error('Create transaction failed:', cause?.code);
      }

      if (isAuthorizeHeadless) {
        // Retryable in headless mode — keep the iframe/WebView mounted so the user can try again
        break;
      }
      // In default mode there is no in-place retry for this code — fall through and teardown
    }

    teardown();
    // Show a user-friendly error message
    break;
  }
  ```
</CodeGroup>

<Warning>The Payment Widget handles most errors internally. For unrecoverable errors, the widget fires an `error` event. It is the host application's responsibility to handle these events, present an error message to the user, and unmount the widget.</Warning>

***

## Monitor for settlement

{apmLabel_2} {direction_0} transactions remain in `processing` while the payment settles. Monitor until the transaction reaches a terminal state.

* **Webhook events** (recommended):
  * [core.transaction.created](/rest-apis/core-api/transactions/webhooks/transaction-created) — `status: processing` → transaction created, pending settlement
  * [core.transaction.status-changed](/rest-apis/core-api/transactions/webhooks/transaction-status-changed) — `status: completed` → funds settled; `status: failed` → irrecoverable error
* **Polling** (fallback): [Get transaction](/rest-apis/core-api/transactions/get-transaction)

***

## Sample transaction

In a successful {apmLabel_1} withdrawal, the origin is the user's `account` and the destination is an `apm` node with the method as `{apmMethod}`. The transaction status is initially `processing` and updates to `completed` once the transfer settles.

```json [expandable] theme={null}
{
  "transaction": {
    "id": "9b2f4a17-5e3c-4d77-a8e1-9bcdef2c0a42",
    "origin": {
      "asset": "USD",
      "amount": "15.00",
      "node": {
        "type": "account",
        "id": "b8618cd1-ccb0-4a72-985f-3bb0d268dabd",
        "ownerId": "48e40cb2-6c34-44ce-b2f1-6adac459bb37"
      }
    },
    "destination": {
      "asset": "USD",
      "amount": "15.00",
      "node": {
        "type": "apm",
        "method": "apple-pay"
      }
    },
    "status": "completed",
    "quotedAt": "2025-06-18T00:55:39Z",
    "createdAt": "2025-06-18T00:56:39Z",
    "updatedAt": "2025-06-18T00:57:08Z",
    "denomination": {
      "asset": "USD",
      "amount": "15.00",
      "target": "origin"
    }
  }
}
```

***

## Notify the user

After the transaction completes, display the transaction details to the user so they can confirm the withdrawal succeeded. Here's an example:

<Frame>
  <div style={{maxWidth: '400px', margin: '0 auto'}}>
    <img src="https://mintcdn.com/uphold-d4756e17/WuOkmqXUUvhqHoz9/developer-guides/apm-transfers/_media/apple-pay-withdrawal-transaction-completed.png?fit=max&auto=format&n=WuOkmqXUUvhqHoz9&q=85&s=655e9081d02a0e161af1168285d71180" alt="Apple Pay transaction completed confirmation" width="1788" height="2400" data-path="developer-guides/apm-transfers/_media/apple-pay-withdrawal-transaction-completed.png" />
  </div>
</Frame>

***

## Troubleshooting

Having issues rendering Apple Pay? See [Troubleshooting](/widgets/payment/installation-and-setup#troubleshooting) in the Payment Widget installation guide.

***

<Check>You now support Apple Pay withdrawals via the Payment Widget.</Check>
