Payment Request Button

    Collect payment and address information from your customers using Apple Pay, Pay with Google, and the Payment Request API by using the Payment Request Button Element.

    The paymentRequestButton Element gives you a single integration for Apple Pay, Pay with Google, and the Payment Request API—a browser standard that gives your customers the ability to quickly provide you payment and address information they’ve stored with their browser.

    Using this Element, your customers are shown either an Apple Pay button or Payment Request button, depending on what is supported by their device and browser combination. If neither is available, the button is not displayed.

    For customers that don’t use Apple Pay, the Payment Request button supports browser-saved cards and Pay with Google, including Android Pay.

    Try it out!

    You can see what it's like right here on this page! Don't worry, your card won't be charged.

    Collecting your customers’ payment information using the Payment Request Button Element requires four steps:

    1. Set up Stripe Elements
    2. Create the PaymentRequest instance
    3. Create and mount the paymentRequestButton Element
    4. Complete the payment using the emitted token

    Prerequisites

    Before you start, you need to:

    Step 1: Set up Stripe Elements

    Elements is available as part of Stripe.js. Include this in your page and create a container that will be used for the paymentRequestButton Element:

    <script src="https://js.stripe.com/v3/"></script>
    <div id="payment-request-button">
      <!-- A Stripe Element will be inserted here. -->
    </div>

    Your Stripe publishable API key is also required as it identifies your website to Stripe:

    var stripe = Stripe('pk_test_6pRNASCoBOKtIshFeQd4XMUh');
    const stripe = Stripe('pk_test_6pRNASCoBOKtIshFeQd4XMUh');

    Step 2: Create the PaymentRequest instance

    Create an instance of stripe.paymentRequest with all required options.

    var paymentRequest = stripe.paymentRequest({
      country: 'US',
      currency: 'usd',
      total: {
        label: 'Demo total',
        amount: 1000,
      },
    });
    const paymentRequest = stripe.paymentRequest({
      country: 'US',
      currency: 'usd',
      total: {
        label: 'Demo total',
        amount: 1000,
      },
    });

    Step 3: Create and mount the paymentRequestButton Element

    Create the paymentRequestButton Element and check to make sure that your customer has an active payment method using canMakePayment(). If they do, mount the Element to the container to display the Payment Request Button. If they do not, you cannot mount the Element, and we encourage you to show a traditional checkout form instead.

    var elements = stripe.elements();
    var prButton = elements.create('paymentRequestButton', {
      paymentRequest: paymentRequest,
    });
    
    // Check the availability of the Payment Request API first.
    paymentRequest.canMakePayment().then(function(result) {
      if (result) {
        prButton.mount('#payment-request-button');
      } else {
        document.getElementById('payment-request-button').style.display = 'none';
      }
    });
    const elements = stripe.elements();
    const prButton = elements.create('paymentRequestButton', {
      paymentRequest,
    });
    
    // Check the availability of the Payment Request API first.
    const result = await paymentRequest.canMakePayment();
    if (result) {
      prButton.mount('#payment-request-button');
    } else {
      document.getElementById('payment-request-button').style.display = 'none';
    }

    Step 4: Complete the payment using the emitted token

    Finally, listen to the token event to receive a Token object. Send this token to your server to charge it and complete the payment.

    paymentRequest.on('token', function(ev) {
      // Send the token to your server to charge it!
      fetch('/charges', {
        method: 'POST',
        body: JSON.stringify({token: ev.token.id}),
      })
      .then(function(response) {
        if (response.ok) {
          // Report to the browser that the payment was successful, prompting
          // it to close the browser payment interface.
          ev.complete('success');
        } else {
          // Report to the browser that the payment failed, prompting it to
          // re-show the payment interface, or show an error message and close
          // the payment interface.
          ev.complete('fail');
        }
      });
    });
    paymentRequest.on('token', async (ev) => {
      // Send the token to your server to charge it!
      const response = await fetch('/charges', {
        method: 'POST',
        body: JSON.stringify({token: ev.token.id}),
      });
    
      if (response.ok) {
        // Report to the browser that the payment was successful, prompting
        // it to close the browser payment interface.
        ev.complete('success');
      } else {
        // Report to the browser that the payment failed, prompting it to
        // re-show the payment interface, or show an error message and close
        // the payment interface.
        ev.complete('fail');
      }
    });

    Collecting shipping information

    To collect shipping information, begin by including requestShipping: true when creating the payment request.

    You may also provide an array of shippingOptions at this point, if your shipping options do not depend on the customer’s address.

    var paymentRequest = stripe.paymentRequest({
      country: 'US',
      currency: 'usd',
      total: {
        label: 'Demo total',
        amount: 1000,
      },
    
      requestShipping: true,
      // `shippingOptions` is optional at this point:
      shippingOptions: [
        // The first shipping option in this list appears as the default
        // option in the browser payment interface.
        {
          id: 'free-shipping',
          label: 'Free shipping',
          detail: 'Arrives in 5 to 7 days',
          amount: 0,
        },
      ],
    });
    const paymentRequest = stripe.paymentRequest({
      country: 'US',
      currency: 'usd',
      total: {
        label: 'Demo total',
        amount: 1000,
      },
    
      requestShipping: true,
      // `shippingOptions` is optional at this point:
      shippingOptions: [
        // The first shipping option in this list appears as the default
        // option in the browser payment interface.
        {
          id: 'free-shipping',
          label: 'Free shipping',
          detail: 'Arrives in 5 to 7 days',
          amount: 0,
        },
      ],
    });

    Next, listen to the shippingaddresschange event to detect when a customer selects a shipping address. Use the address to fetch valid shipping options from your server, update the total, or perform other business logic. The address data on the shippingaddresschange event may be anynomized by the browser to not reveal sensitive information that is not necessary for shipping cost calculation.

    Note that valid shippingOptions must be supplied at this point for the customer to proceed in the flow.

    paymentRequest.on('shippingaddresschange', function(ev) {
      if (ev.shippingAddress.country !== 'US') {
        ev.updateWith({status: 'invalid_shipping_address'});
      } else {
        // Perform server-side request to fetch shipping options
        fetch('/calculateShipping', {
          data: JSON.stringify({
            shippingAddress: ev.shippingAddress
          })
        }).then(function(response) {
          return response.json();
        }).then(function(result) {
          ev.updateWith({
            status: 'success',
            shippingOptions: result.supportedShippingOptions,
          });
        });
      }
    });
    paymentRequest.on('shippingaddresschange', async (ev) => {
      if (ev.shippingAddress.country !== 'US') {
        ev.updateWith({status: 'invalid_shipping_address'});
      } else {
        // Perform server-side request to fetch shipping options
        const response = await fetch('/calculateShipping', {
          data: JSON.stringify({
            shippingAddress: ev.shippingAddress
          })
        });
        const result = await response.json();
    
        ev.updateWith({
          status: 'success',
          shippingOptions: result.supportedShippingOptions,
        });
      }
    });

    Styling the Payment Request Button Element

    Use the following parameters to customize the Element:

    elements.create('paymentRequestButton', {
      paymentRequest: paymentRequest,
      style: {
        paymentRequestButton: {
          type: 'default' | 'donate' | 'buy', // default: 'default'
          theme: 'dark' | 'light' | 'light-outline', // default: 'dark'
          height: '64px', // default: '40px', the width is always '100%'
        },
      },
    });
    elements.create('paymentRequestButton', {
      paymentRequest,
      style: {
        paymentRequestButton: {
          type: 'default' | 'donate' | 'buy', // default: 'default'
          theme: 'dark' | 'light' | 'light-outline', // default: 'dark'
          height: '64px', // default: '40px', the width is always '100%'
        },
      },
    });

    Verifying your domain with Apple Pay

    To use Apple Pay, you need to register with Apple all of your web domains that will show an Apple Pay button. This includes both top-level domains (e.g., stripe.com) and subdomains (e.g., shop.stripe.com). You need to do this for domains you use in both production and testing. When testing locally, use a tool like ngrok to get an HTTPS domain.

    Important note: Apple's documentation for Apple Pay on the Web describes their process of "merchant validation", which Stripe handles for you behind the scenes. You do not need to create an Apple Merchant ID, CSR, etc., as described in their documentation, and should instead just follow these steps:

    1. Download this domain association file and host it at /.well-known/apple-developer-merchantid-domain-association on your site.

      For example, if you're registering https://example.com, make that file available at https://example.com/.well-known/apple-developer-merchantid-domain-association.

    2. Next, tell Stripe to register your domain with Apple. You can do this by either going to the Apple Pay tab in the Account Settings of your Dashboard, or by directly using the API with your live secret key as shown below.

      Note that we've redacted your live secret key here—head to your Dashboard and replace sk_live_•••••••••••••••••••••••• below with your live secret key. All domains, whether in production or testing, must be registered with your live secret key.

      curl https://api.stripe.com/v1/apple_pay/domains \
       -u "sk_live_••••••••••••••••••••••••": \
       -d domain_name="example.com"
      Stripe.api_key = "sk_live_••••••••••••••••••••••••"
      Stripe::ApplePayDomain.create(domain_name: 'example.com')
      stripe.api_key = "sk_live_••••••••••••••••••••••••"
      stripe.ApplePayDomain.create(
        domain_name="example.com"
      )
      \Stripe\Stripe::setApiKey("sk_live_••••••••••••••••••••••••");
      \Stripe\ApplePayDomain::create(array(
        'domain_name' => 'example.com'
      ));
      var stripe = require("stripe")(
        "sk_live_••••••••••••••••••••••••"
      );
      stripe.applePayDomains.create({
        domain_name: 'example.com'
      });
      Stripe.apiKey = "sk_live_••••••••••••••••••••••••";
      Map<String, Object> domainParams = new HashMap<String, Object>();
      domainParams.put("domain_name", "example.com");
      ApplePayDomain.create(domainParams);
    3. Once you've registered your domains, you'll be able to make payments on your site using your live API keys.

    Testing your integration

    To test your integration you must be using HTTPS and a supported browser. If you are using an iframe, it must have the allowpaymentrequest attribute set, which means demo sites like jsfiddle and Codepen will not work.

    In addition, each payment method and browser has specific requirements:

    Safari

    • Safari on Mac running macOS Sierra or later.
    • An iPhone (not an iPad; Safari doesn't support them yet) with a card in its Wallet paired to your Mac with Handoff, or a Mac with TouchID. Instructions can be found on Apple's Support website.
    • Make sure you've verified your domain with Apple Pay.
    • When using an iframe, its origin must match the top-level origin. Two pages have the same origin if the protocol, host (full domain name), and port (if one is specified) are the same for both pages.

    Mobile Safari

    • Mobile Safari on iOS 10.1 or later.
    • A card in your Wallet, by going to Settings → Wallet & Apple Pay.
    • Make sure you've verified your domain with Apple Pay.
    • When using an iframe, its origin must match the top-level origin. Two pages have the same origin if the protocol, host (full domain name), and port (if one is specified) are the same for both pages.

    Chrome

    Chrome Mobile for Android

    Note that when using Pay with Google, including Android Pay, with a test mode key, you may see an "Unrecognized app" warning. This is expected and does not show up in live mode.

    Using the Payment Request Button with Stripe Connect (optional)

    If you have a Connect application and would like to accept payments using the Payment Request Button, make these two changes to your integration:

    • On your frontend, before creating the PaymentRequest instance, set the stripeAccount option on the Stripe instance:

      var stripe = Stripe('pk_test_6pRNASCoBOKtIshFeQd4XMUh', {
        stripeAccount: 'CONNECTED_STRIPE_ACCOUNT_ID'
      });
      const stripe = Stripe('pk_test_6pRNASCoBOKtIshFeQd4XMUh', {
        stripeAccount: 'CONNECTED_STRIPE_ACCOUNT_ID'
      });
    • Register all domains on which the Payment Request Button will be shown with Apple Pay. You can use the Stripe API for this, using your platform's secret key to authenticate the request, and setting the Stripe-Account header to your connected account's Stripe ID, as described in Authentication with Connect.

      curl https://api.stripe.com/v1/apple_pay/domains \
      -u {PLATFORM_SECRET_KEY}: \
      -H "Stripe-Account: {CONNECTED_STRIPE_ACCOUNT_ID}" \
      -d domain_name="example.com"

    Next steps

    Congrats! You’re now using the Payment Request Button to collect your customer’s information with Stripe. Once you’ve sent your token to your server, you’ll be able to use the token to perform a charge or to save to a customer. Learn more about how to create charges or make use of subscriptions.