> ## Documentation Index
> Fetch the complete documentation index at: https://paypal-sb-staging.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# PayPal Direct App Switch integration

The PayPal Direct App Switch flow lets customers complete payments directly in the PayPal mobile app when it's available.

A basic Direct App Switch flow is similar to this:

1. A user clicks the **PayPal** button in a merchant's app or website.
2. The server API creates an order.
3. A payment session starts with the `direct-app-switch` mode.
4. The user is redirected to the PayPal app (if available) or website to make a payment.
5. When the payment is approved, the user returns to the merchant app or website to complete the transaction.
6. The payment session resumes and captures the order.

This integration guide covers the implementation that is in the `directAppSwitch` example in <a href="https://github.com/paypal-examples/v6-web-sdk-sample-integration/tree/main/client/components/paypalPayments/oneTimePayment/html/src/advanced/directAppSwitch/" target="_blank">the public examples repository on GitHub</a>.

{/* Do we talk anywhere about what they need for sandbox testing versus a production environment?*/}

The integration consists of 2 main files:

* `index.html`: HTML structure with the PayPal button and an auto-redirect toggle
* `app.js`: JavaScript implementation that handles the payment flow

## Prerequisites

* PayPal SDK v6
* Server-side PayPal integration for order creation and capture, which uses these endpoints:
  * `POST /paypal-api/checkout/orders/create` creates the PayPal order.
  * `POST /paypal-api/checkout/orders/{orderId}/capture` captures completed order.
* Client token generation endpoint, which uses the `GET /paypal-api/auth/browser-safe-client-token` endpoint.

## Integration

Completing the integration involves the steps in this section.

### 1. HTML structure

In this example, you'll find these key features:

* An auto-redirect checkbox to control redirect behavior
* A hidden PayPal button that becomes visible after SDK initialization
* The JavaScript SDK v6 core script with an `onload` callback

```html theme={null}
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>One-Time Payment - Direct App Switch Flow - PayPal JavaScript SDK</title>
    <meta name="viewport" content="width=device-width, initial-scale=1" />
  </head>
  <body>
    <h1>Paypal Direct App Switch Flow</h1>
    <div>
      <input type="checkbox" id="enable-auto-redirect" checked />
      <label for="enable-auto-redirect"> Enable auto-redirect </label>
    </div>
    <div id="button-container">
      <paypal-button id="paypal-button" hidden></paypal-button>
    </div>

    <script src="app.js"></script>
    <script
      async
      onload="onPayPalWebSdkLoaded()"
      src="https://www.sandbox.paypal.com/web-sdk/v6/core"
    ></script>
  </body>
</html>
```

### 2. SDK initialization

In this example, you'll find these key features:

* It creates an SDK instance with a client token.
* It initializes a one-time payment session with PayPal.
* It handles the return from an external app using `hasReturned()`. For more information about return URL handling, see [Return URL handling](#return-url-handling).
* It resumes a session or sets up the button accordingly.

```javascript theme={null}
async function onPayPalWebSdkLoaded() {
  try {
    const clientToken = await getBrowserSafeClientToken();
    const sdkInstance = await window.paypal.createInstance({
      clientToken,
      components: ["paypal-payments"],
      pageType: "checkout",
    });
    const paypalPaymentSession = sdkInstance.createPayPalOneTimePaymentSession(
      paymentSessionOptions,
    );

    if (paypalPaymentSession.hasReturned()) {
      await paypalPaymentSession.resume();
    } else {
      setupPayPalButton(paypalPaymentSession);
    }
  } catch (error) {
    console.error(error);
  }
}
```

### 3. Payment session configuration

This example uses the following callbacks:

* `onApprove`: Triggered when payment is approved to capture the order
* `onCancel`: Handles payment cancellation
* `onError`: Handles payment errors

```javascript theme={null}
const paymentSessionOptions = {
  async onApprove(data) {
    console.log("onApprove", data);
    const orderData = await captureOrder({
      orderId: data.orderId,
    });
    console.log("Capture result", orderData);
  },
  onCancel(data) {
    console.log("onCancel", data);
  },
  onError(error) {
    console.log("onError", error);
  },
};
```

### 4. Button setup and payment initiation

In this example, note the Direct App Switch configuration, which includes these features:

* `presentationMode: "direct-app-switch"` enables the Direct App Switch flow
* `autoRedirect.enabled` controls automatic redirection behavior
* `redirectURL` redirects to the PayPal app or site

For more information about return URL handling, see [Return URL handling](#return-url-handling).

```javascript theme={null}
async function setupPayPalButton(paypalPaymentSession) {
  const enableAutoRedirect = document.querySelector("#enable-auto-redirect");
  const paypalButton = document.querySelector("#paypal-button");
  paypalButton.removeAttribute("hidden");

  paypalButton.addEventListener("click", async () => {
    const createOrderPromiseReference = createRedirectOrder();

    try {
      const { redirectURL } = await paypalPaymentSession.start(
        {
          presentationMode: "direct-app-switch",
          autoRedirect: {
            enabled: enableAutoRedirect.checked,
          },
        },
        createOrderPromiseReference,
      );
      if (redirectURL) {
        console.log(`redirectURL: ${redirectURL}`);
        window.location.assign(redirectURL);
      }
    } catch (error) {
      console.error(error);
    }
  });
}
```

### 5. Server integration functions

These examples show how to set up client token retrieval, order creation, and order capture. Select a tab to see and use the corresponding example.

In this order creation example, you see these settings:

* `shippingPreference: "NO_SHIPPING"` means that no shipping is required.
* `userAction: "CONTINUE"` means that the user continues after approval.
* `returnUrl` and `cancelUrl` use the URL of the current page.

{/* Where do we describe their options, both the ones the example uses and the ones we don't show here? Make sure that we add this content somewhere if it doesn't already exist on a public page, and link to it from anywhere applicable.*/}

<Tabs>
  <Tab>
    ```javascript Client token retrieval theme={null}
    async function getBrowserSafeClientToken() {
      const response = await fetch("/paypal-api/auth/browser-safe-client-token", {
        method: "GET",
        headers: {
          "Content-Type": "application/json",
        },
      });
      const { accessToken } = await response.json();
      return accessToken;
    }
    ```
  </Tab>

  <Tab>
    ```javascript Order creation theme={null}
    async function createRedirectOrder() {
      const orderPayload = {
        intent: "CAPTURE",
        paymentSource: {
          paypal: {
            experienceContext: {
              shippingPreference: "NO_SHIPPING",
              userAction: "CONTINUE",
              returnUrl: window.location.href,
              cancelUrl: window.location.href,
            },
          },
        },
        purchaseUnits: [
          {
            amount: {
              currencyCode: "USD",
              value: "10.00",
              breakdown: {
                itemTotal: {
                  currencyCode: "USD",
                  value: "10.00",
                },
              },
            },
          },
        ],
      };

      const response = await fetch("/paypal-api/checkout/orders/create", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify(orderPayload),
      });
      const { id } = await response.json();
      return { orderId: id };
    }
    ```
  </Tab>

  <Tab>
    ```javascript Order capture theme={null}
    async function captureOrder({ orderId }) {
      const response = await fetch(
        `/paypal-api/checkout/orders/${orderId}/capture`,
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
          },
        },
      );
      const data = await response.json();
      return data;
    }
    ```
  </Tab>
</Tabs>

## Return URL handling

To understand return URL handing, keep these points in mind:

* Both `returnUrl` and `cancelUrl` point to `window.location.href`.
* The `hasReturned()` method detects when user returns from external flow
* The  `resume()` method continues the payment process.

When you enable auto-redirect, it automatically redirects users to the PayPal app (if available) or website. If you disable this functionality, it shows the redirect URL for manual handling.

{/* We don't tell them where they can get more information about return URLs in general, other options they have, and so on.*/}

## Best practices

These examples demonstrate some best practices. Specifically, best practices for Direct App Switch integrations include:

* Always wrap payment operations in `try`-`catch` blocks for better error handling.
* To detect returning users, use `hasReturned()`.
* To continue or return to a payment session, call `resume()`.
* Use responsive design to ensure a device-optimized experience for users.

## Testing

* **Web-fallback behavior:** While it might be obvious to test on devices that have the PayPal app, also test your app or website on devices that don't have the PayPal app installed.
* **Auto-redirect:** Test auto-redirect functionality to ensure that it provides the experience that you expect for users.
* **Payment cancellation:** Be sure to test what happens when payment fails or is cancelled.
* **Order capture:** Validate that captured orders accurately reflect the intended purchase for a successful payment.
