Skip to main content
Save Apple Pay as a payment method for future purchases without an initial transaction. Use PayPal’s JavaScript SDK to tokenize and save Apple Pay credentials for later use.

Prerequisites

  1. Ensure you have PayPal business account approved for Expanded Checkout.
  2. Ensure you set up developer, sandbox, and production environment accounts.
  3. Ensure you create an Apple Pay sandbox account for testing in the sandbox environment.

Load PayPal JS SDK

PayPal’s JavaScript SDK provides the necessary pre-built tools to render the Apple Pay button on your webpage and handle payment authorization. Include the PayPal SDK core and Apple Pay SDK as <script> tags in the HTML file that renders your webpage. For production environment:
{/* PayPal Web SDK */}
<script src="https://www.paypal.com/web-sdk/v6/core"></script>

{/* Apple Pay SDK */}
<script src="https://applepay.cdn-apple.com/jsapi/v1/apple-pay-sdk.js"></script>
For sandbox environment:
{/* PayPal Web SDK (Sandbox) */}
<script src="https://www.sandbox.paypal.com/web-sdk/v6/core"></script>

{/* Apple Pay SDK */}
<script src="https://applepay.cdn-apple.com/jsapi/v1/apple-pay-sdk.js"></script>

Create browser-safe client token

The browser-safe token is a client-side access token that authorizes the app to use the JavaScript SDK resources. Configure your server to call PayPal’s OAuth API and parse the access_token from the response for your client-side application. In the server-side call to the /v1/oauth2/token endpoint:
  1. Encode app credentials Client ID : Secret in Base64 format and use it in the Authorization header.
  2. Include the following data parameters:
    • grant_type: Set the parameter value to client_credentials to specify that the app is requesting to exchange client ID and secret for an access token.
    • response_type: Set the parameter value to client_token to request for a client-side access token.
    • intent: Set the parameter value to sdk_init to specify that the purpose for the request is SDK initialization.
Response: Contains the browser-safe client token in the access_token response parameter.
async function getClientToken() {
  const response = await fetch(
    "/your-server/api/paypal/browser-safe-client-token",
  );
  const tokens = await response.json();
  return tokens.access_token;
}

Initialize JS SDK and create SDK instance

Use the window.paypal.createInstance() method to create a PayPal SDK instance and include the following parameters:
  • clientToken: The browser-safe client token.
  • components: Set to ["applepay-payments"] to indicate that you intend to render Apple Pay components.
Response: Contains createApplePayOneTimePaymentSession() for creating Apple Pay payment sessions and findEligibleMethods() for checking payment method availability.
const clientToken = await getClientToken();
const sdkInstance = await window.paypal.createInstance({
  clientToken,
  components: ["applepay-payments"],
});
window.sdkInstance = sdkInstance;

Create PayPal’s Apple Pay one-time payment session

Create PayPal’s session that handles Apple Pay configuration and merchant validation. This session manages PayPal-specific operations and provides the settings needed for the native Apple Pay session created later.

Create payment session

Use the createApplePayOneTimePaymentSession() method to create the session. This method doesn’t require any parameters as it uses the configuration from SDK initialization. Response: Contains config() to get Apple Pay configuration and validateMerchant() to validate merchant with Apple Pay servers.

Get Apple Pay configuration

Use the paypalSdkApplePayPaymentSession.config() method to retrieve Apple Pay configuration. This method doesn’t require any parameters. Response: Contains the following:
  • merchantCapabilities (array): Supported payment processing capabilities.
  • supportedNetworks (array): Supported card networks.
  • isEligible (boolean): Indicates if Apple Pay is eligible.
  • merchantCountry (string): Merchant’s country code.
// Create PayPal's Apple Pay session for configuration and validation
const paypalSdkApplePayPaymentSession =
  await sdkInstance.createApplePayOneTimePaymentSession();
const { merchantCapabilities, supportedNetworks } =
  await paypalSdkApplePayPaymentSession.config();

Verify eligibility

Use the following methods to determine if you are eligible to offer Apple Pay as a payment method:
  • findEligibleMethods - Returns all the eligible payment methods.
  • isEligible - Boolean method that determines if Apple Pay is an eligible payment method.
Call findEligibleMethods() with an options object containing the following:
  • apiCode: Set to restApi to specify the API methodology.
  • countryCode: Set to the two-letter country code. Example: US.
  • currencyCode: Set to the three-letter currency code. Example: USD.
  • paymentMethods: Set to ["APPLE_PAY"] to check Apple Pay eligibility.
Response: Contains a paymentMethods object with isEligible() method to check if Apple Pay is eligible.
const options = {};
options.apiCode = "restApi";
options.countryCode = "US";
options.currencyCode = "USD";
options.paymentMethods = ["APPLE_PAY"];

const paymentMethods = await sdkInstance.findEligibleMethods(options);
let isApplePayEligible = paymentMethods.isEligible("applepay");
setMessage("Apple Pay eligibility: ", { isApplePayEligible });

Render Apple Pay button

After confirming eligibility, render the Apple Pay button on your webpage. To render the Apple Pay button:
  1. Define the container for the Apple Pay button: In the HTML file corresponding to the webpage where you want to render the button, include a container element as shown in the sample code:
<section class="payment-method-container" id="applepay-section">
  <h2>Apple Pay Button</h2>
  <p>This example uses the Apple Pay button web component to launch the vault without purchase flow.</p>
  {/* Button will be added dynamically if eligible */}
</section>
  1. Add the Apple Pay button element: Dynamically insert the Apple Pay button HTML element into the container. The <apple-pay-button> web component supports the following attributes:
    • id: Unique identifier for the button element.
    • buttonstyle: Visual style of the button. Example: black.
    • type: Button label type. Example: buy.
    • locale: Language code for button text. Example: en.
const applepaySection = document.querySelector("#applepay-section");
const applepayButton = document.createElement("apple-pay-button");
applepayButton.id = "btn-appl";
applepayButton.buttonstyle = "black";
applepayButton.type = "buy";
applepayButton.locale = "en";
applepaySection.appendChild(applepayButton);
  1. Attach the event handler: Use addEventListener() to register the onClickApplePay callback handler that executes when customers select the Apple Pay button. This handler manages:
    • Apple Pay session creation.
    • Merchant validation with Apple Pay servers.
    • Payment authorization and token creation.
    • Vault setup token and payment token generation.
document
  .getElementById("btn-appl")
  .addEventListener("click", onClickApplePay);
Result: Successful button rendering:
  • Sets up the Apple Pay button on your webpage.
  • Defines the on-click flow for your button.

Define on-click event handler function

Create an event handler to process Apple Pay button clicks and start the payment session. This function contains all the logic needed to handle the Apple Pay vault flow.
async function onClickApplePay() {
  // Step 1: Create payment request object
  // Step 2: Verify Apple Pay availability
  // Step 3: Create new Apple Pay session
  // Step 4: Set up event handlers
  // Step 5: Start Apple Pay flow
}

1. Create payment request object

Define the payment request with required billing fields and zero amount.
const paymentRequest = {
          countryCode: "US",
          currencyCode: "USD",
          merchantCapabilities,
          supportedNetworks,
          requiredBillingContactFields: [
            "name",
            "phone",
            "email",
            "postalAddress",
          ],
          requiredShippingContactFields: [],
          total: {
            label: "Save Payment Method",
            amount: "0.00",
            type: "final",
          },
          lineItems: [
            {
              label: "Subscription (Recurring)",
              amount: 100,
              recurringPaymentStartDate: "2025-09-07T04:01:17.188Z",
              paymentTiming: "recurring"
            }
          ],
          recurringPaymentRequest: {
            paymentDescription: "Recurring transaction description",
            regularBilling: {
              label: "Recurring",
              amount: 100,
              paymentTiming: "recurring",
              recurringPaymentStartDate: "2025-09-07T04:01:17.188Z"
            },
            billingAgreement: "Billing Agreement Description",
            managementURL: "https://www.your-domain.com/management-url/"
          }
        };

2. Verify Apple Pay availability

Check browser support and device capability for Apple Pay.
// Check Apple Pay availability
if (!window.ApplePaySession) {
  console.log("Apple Pay is not available - ApplePaySession not found");
  return;
}

if (!ApplePaySession.canMakePayments()) {
  console.log("Apple Pay is not available - canMakePayments returned false");
  return;
}

console.log("Apple Pay version supported:", ApplePaySession.supportsVersion(4));
console.log("Payment request:", paymentRequest);

3. Create new Apple Pay session

Initialize a new Apple Pay session with the payment request details.
console.log("Creating Apple Pay session for vault...");
let appleSdkApplePayPaymentSession = new ApplePaySession(
  4,
  paymentRequest,
);

4. Set up event handlers

Event handlers manage the different outcomes when your customers attempt to save Apple Pay. Configure event handlers for the Apple Pay session lifecycle.

a. Handle merchant validation

In your app code, include the logic to validate the merchant identity with Apple Pay servers through PayPal. Use the paypalSdkApplePayPaymentSession.validateMerchant() method to validate the merchant with Apple Pay servers and include the following parameters:
  • validationUrl: The validation URL provided by Apple Pay (from event.validationURL).
  • displayName (optional): Merchant display name.
  • domainName (optional): Merchant domain name.
Response: Contains merchantSession: the merchant session object to pass to Apple Pay.
appleSdkApplePayPaymentSession.onvalidatemerchant = (event) => {
  console.log("Validating Apple Pay merchant & domain...");
  console.log("Validation URL:", event.validationURL);

  paypalSdkApplePayPaymentSession
    .validateMerchant({
      validationUrl: event.validationURL,
    })
    .then((payload) => {
      console.log("Merchant validation success:", payload);
      appleSdkApplePayPaymentSession.completeMerchantValidation(
        payload.merchantSession,
      );
      console.log("Completed merchant validation");
    })
    .catch((err) => {
      console.log("PayPal validatemerchant error:", err);
      console.log(`Merchant validation failed: ${err.message || err}`);
      appleSdkApplePayPaymentSession.abort();
    });
};

b. Handle payment method selection

In your app code, include the logic to handle when the customer selects a different payment card in Apple Wallet. Use the completePaymentMethodSelection() method to confirm the selection with newTotal parameter set to the payment total object (from paymentRequest.total). Response: Updates the Apple Pay sheet with the confirmed selection.
appleSdkApplePayPaymentSession.onpaymentmethodselected = () => {
  appleSdkApplePayPaymentSession.completePaymentMethodSelection({
    newTotal: paymentRequest.total,
  });
};

c. Handle payment authorization

In your app code, include the logic to process the Apple Pay payment authorization and create vault tokens. Use the completePayment() method to notify Apple Pay of the transaction status with status parameter set to the payment status (window.ApplePaySession.STATUS_SUCCESS or window.ApplePaySession.STATUS_FAILURE). Response: Closes the Apple Pay sheet and displays the appropriate success or failure message to the customer.
appleSdkApplePayPaymentSession.onpaymentauthorized = async (event) => {
  try {
    // Step 1: Encode the Apple Pay token
    function encodePaymentToken(token) {
      var data = { partner: "paypal", paymentData: token.paymentData };
      return btoa(JSON.stringify(data));
    }

    // Step 2: Create vault setup token
    const vaultSetupTokenData = {
      payment_source: {
        apple_pay: {
          token: encodePaymentToken(event.payment.token),
        },
      },
    };
    
    const vaultSetupToken = await createVaultSetupToken(vaultSetupTokenData);
    
    // Step 3: Create payment token
    const vaultPmtTokenData = {
      payment_source: {
        token: {
          type: "SETUP_TOKEN",
          id: vaultSetupToken.setupToken,
        },
      },
    };
    
    const vaultPaymentToken = await createVpmtToken(vaultPmtTokenData);
    setMessage("✅Payment Token created successfully: " + vaultPaymentToken.setupToken);
    
    // Step 4: Complete the payment
    appleSdkApplePayPaymentSession.completePayment({
      status: window.ApplePaySession.STATUS_SUCCESS,
    });
    
  } catch (error) {
    console.error("Payment authorization error:", error);
    appleSdkApplePayPaymentSession.completePayment({
      status: window.ApplePaySession.STATUS_FAILURE,
    });
  }
};
Create vault setup token
Create a setup token for saving payment methods without an initial payment. This token is different from the browser-safe client token and is used to generate the payment method token. First, encode the Apple Pay payment data using a helper function that formats the token data in the required structure for PayPal’s Vault API:
function encodePaymentToken(token) {
  var data = { partner: "paypal", paymentData: token.paymentData };
  return btoa(JSON.stringify(data));
}
In the server-side call to the /v3/vault/setup-tokens endpoint:
  1. Use a Bearer token in the Authorization header.
  2. Include the following in the request body:
    • payment_source.apple_pay.token: Set to the Base64 encoded Apple Pay token containing payment data.
Response: Contains the setup token in the id response parameter.
// Client-side helper function to create vault setup token
async function createVaultSetupToken(vaultData) {
  setMessage("Creating vault setup token");

  const defaultHeaders = {
    "Content-Type": "application/json",
  };

  try {
    const response = await fetch(
      "/your-server/api/paypal/vault/setup-token",
      {
        headers: {
          ...defaultHeaders,
        },
        method: "POST",
        body: JSON.stringify(vaultData),
      },
    );

    const data = await response.json();

    if (!response.ok) {
      throw new Error(data.message || "Failed to create setup token");
    }

    return data;
  } catch (error) {
    throw new Error(error);
  }
}
Create Payment Method Token (PMT)
Convert the setup token to a reusable payment method token for future transactions. In the server-side call to the /v3/vault/payment-tokens endpoint:
  1. Use a Bearer token in the Authorization header.
  2. Include the following in the request body:
    • payment_source.token.type: Set to SETUP_TOKEN to specify the token type.
    • payment_source.token.id: Set to the setup token ID from the previous step.
Response: Contains the payment token in the id response parameter, which is the reusable token for future transactions.
// Convert the setup token to a reusable payment token
const vaultPmtTokenData = {
  payment_source: {
    token: {
      type: "SETUP_TOKEN",
      id: vaultSetupToken.setupToken,  // The setup token ID from the previous step
    },
  },
};

setMessage("Processing vault PaymentToken for Apple Pay...");
const vaultPaymentToken = await createVpmtToken(vaultPmtTokenData);
setMessage(
  "✅Payment Token created successfully: " + vaultPaymentToken.setupToken,  // This is the reusable token for future transactions
);

// Store the payment token ID for future use
// This token can be used to process payments without requiring the customer to re-authenticate
const paymentTokenId = vaultPaymentToken.setupToken;

// Client-side helper function
async function createVpmtToken(vaultData) {
  setMessage("Creating vault payment token");

  const defaultHeaders = {
    "Content-Type": "application/json",
  };

  try {
    const response = await fetch(
      "/your-server/api/paypal/vault/payment-token",
      {
        headers: {
          ...defaultHeaders,
        },
        method: "POST",
        body: JSON.stringify(vaultData),
      },
    );

    const data = await response.json();

    if (!response.ok) {
      throw new Error(data.message || "Failed to create payment token");
    }

    return data;
  } catch (error) {
    throw new Error(error);
  }
}
Complete transaction
Notify Apple Pay that the payment was processed successfully.
appleSdkApplePayPaymentSession.completePayment({
  status: window.ApplePaySession.STATUS_SUCCESS,
});

d. Handle cancellation

In your app code, include the logic to handle cancellation when the customer closes the Apple Pay payment sheet. Use the onCancel() callback function to handle cleanup operations when the customer cancels. This method doesn’t require any parameters. Response: Performs any necessary cleanup and resets the payment flow state.
appleSdkApplePayPaymentSession.oncancel = () => {
  console.log("Apple Pay Cancelled!");
  onCancel();
};

e. Handle errors

In your app code, include the logic to handle errors that occur during the authentication flow. Use the onError() callback function to handle errors with data parameter containing the error details. Response: Logs the error and displays an appropriate error message to the customer.
function onError(data) {
  console.log("onError: ", data);
  setMessage(data);
}

f. Handle completion

In your app code, include the logic to handle when the authentication flow finishes. Use the onComplete() callback function to handle completion with an optional data parameter that may contain completion details. Response: Performs any final cleanup or UI updates needed after the authentication flow completes.
function onComplete(data) {
  console.log("onComplete: ", data);
}

5. Start Apple Pay flow

In your app code, start the Apple Pay payment session after configuring all event handlers. Use the appleSdkApplePayPaymentSession.begin() method to display the Apple Pay payment sheet. This method doesn’t require any parameters. Response: The Apple Pay payment sheet appears, allowing the customer to:
  • View the payment request details
  • Select their preferred payment method from Apple Wallet
  • Authorize the payment
  • Complete the save payment method flow
// Start the Apple Pay payment session
appleSdkApplePayPaymentSession.begin();

Test and go live

Validate your integration in the PayPal sandbox environment before deploying to production. For more information, see Test and go live.
I