Deep Dive into the Payment Request API

作者:Matt Gaunt

Deep Dive into the Payment Request API

By

MattGaunt

Matt is a contributor to Web

Fundamentals

Payment request UI on desktop and mobile Chrome.

In this guide we'll explore the ins and outs of the Payment Request API, looking at how our input affects the payment request UI, how we can request information from the user (like name and phone number), and how the final payment and user information is passed to your site.

If you are unsure of what the Payment Request API is or why it's useful, check out the introduction article.

One thing to keep in the back of your mind when working with the Payment Request API is that the API manages the UI but performs no arithmetic; it will simply display whatever input you pass to it. Throughout the examples we'll discuss what this means for the developer and user.

Dogfood: PaymentRequest is still in development. While we think it's stable enough to implement, it may continue to change. We'll keep this page updated to always reflect the current status of the API. Meanwhile, to protect yourself from API changes that may be backwards incompatible, we're offering a shim that can be embedded on your site. The shim will paper over any API differences for two major Chrome versions.

Feature Detect

Payment Request has been available since Chrome 53 for Android and has been enabled by default since Chrome 61 on desktop. Before we start covering how to use Payment Request, we should feature detect to ensure it's available and fallback to a traditional checkout page in browsers that don't support it.

The feature detect is simply:

if(window.PaymentRequest) {
  // Use Payment Request API
} else {
  // Fallback to traditional checkout
  window.location.href = '/checkout/traditional';
}

Note:Payment Request is only available on sites served over HTTPS.

PaymentRequest Constructor

Once you are ready to collect payment details from the user, you'll need to construct a new PaymentRequest object.

const supportedPaymentMethods = [
  {
    supportedMethods: 'basic-card',
  }
];
const paymentDetails = {
  total: {
    label: 'Total',
    amount:{
      currency: 'USD',
      value: 0
    }
  }
};
// Options isn't required.
const options = {};

new PaymentRequest(
  supportedPaymentMethods,
  paymentDetails,
  options
);

The constructor takes three arguments. Thefirst argumentdefines which forms of payment you can accept; for example, you may only accept 'visa' and 'mastercard'. ThepaymentDetailsargument defines the total and display items. Theoptional third argumentis an object used to request additional information from the user; for example, you can request the payer's name, email address, and phone number.

All of these options affect the UI presented to the user as well as the amount of information the browser will need to collect from them.

Constructing a newPaymentRequestobject can be done at any point in your app. Nothing will be shown to the user until you call itsshow()method.

const request = new PaymentRequest(
  supportedPaymentMethods,
  paymentDetails,
  options
);

// Call when you wish to show the UI to the user.
request.show()
.then(...).catch(...);

Let's start by looking at the arguments we can pass into thePaymentRequestconstructor, starting with the supported payment methods.

Defining Supported Payment Methods

The Payment Request API is designed to support credit and debit card payments as well as third party payment methods (such as Android Pay).

You must supply an array of objects indicating your supported payment methods where each payment method must include asupportedMethodsparameter that identifies the payment method. Each object can contain an optional data object.

const supportedPaymentMethods = [
  {
    supportedMethods: 'name-of-payment-method',
    data: {
      // Optional data for this payment method
    }
  }
];

new PaymentRequest(supportedPaymentMethods, paymentDetails, options);

First we'll look at how to define support for credit and debit cards, followed by a brief look at supporting Android Pay.

Payment Method: 'basic-card'

To support credit and debit cards, we need to change thesupportedMethodsparameter to contain 'basic-card', like so:

const creditCardPaymentMethod = {
  supportedMethods: 'basic-card',
};

const supportedPaymentMethods = [creditCardPaymentMethod];

new PaymentRequest(supportedPaymentMethods, paymentDetails, options);

If the user has no cards set up they'll be prompted to add details, otherwise an existing card will be selected for them.

Example of basic-card support in the Payment Request API.

At the time of writing, Chrome supports 'amex', 'diners', 'discover', 'jcb', 'maestro', 'mastercard', 'unionpay', 'mir', and 'visa', which you can see listed across the top of the UI.

To restrict the supported cards, we can add the optional data parameter and definesupportedNetworks. The following code restricts the accepted cards to visa, mastercard and amex.

const creditCardPaymentMethod = {
  supportedMethods: 'basic-card',
};

const bobPayPaymentMethod = {
  supportedMethods: "https://example.com/bobpay",
  data: {
    merchantIdentifier: "XXXX",
    bobPaySpecificField: true
  }
};

const supportedPaymentMethods = [
  creditCardPaymentMethod,
  bobPayPaymentMethod
];

new PaymentRequest(supportedPaymentMethods, paymentDetails, order);

The payment request UI will restrict the accepted cards and the user will be prevented from selecting other cards:

Example of reduced the list of supported cards in the Payment Request API.

In the screenshot above, the user must add a payment. If browsers have this information readily available, they have the option of pre-selecting an appropriate payment for the user. This means that the wider your card support, the higher the odds are of the browser being able to pre-populate these details, speeding up the checkout flow. For example, if I had a card saved in Chrome, the UI would start with a suitable card already selected:

Cards will be preselected if available.

ThesupportedTypesparameter tells Chrome which types of cards to filter out, i.e. if a merchant definedsupportedTypesas['credit', 'debit'], Chrome would strip out any 'prepaid' cards the user has.

This means thatsupportedTypesdoes not guaranteethat the final card you receive will be a supported type. The user can enter details for a new card, which could be an unsupported type, and the Payment Request API will allow this. ThesupportedTypesoption isjustfor filtering out existing cards. Merchants still need to check the card type on their backend.

Chrome version 61 added support for thesupportedTypesoption. In older versions of Chrome you would receive the following console warning:

Cannot yet distinguish credit, debit, and prepaid cards.

It's safe to use this option. The only difference is that some cards wouldn't be filtered automatically for the user.

const androidPayPaymentMethod = {
  supportedMethods: 'https://android.com/pay',
  data: {
    merchantName: 'Android Pay Demo',
    merchantId: '00000000000000000000',
    environment: 'TEST',
    allowedCardNetworks: ['AMEX', 'DISCOVER', 'MASTERCARD', 'VISA'],
    paymentMethodTokenizationParameters: {
      tokenizationType: 'GATEWAY_TOKEN',
      parameters: {
        'gateway': 'stripe',
        'stripe:publishableKey': 'xx_demo_xxxxxxxxxxxxxxxxxxxxxxxx',
        'stripe:version': '2016-07-06',
      },
    },
  },
};

Android Pay example in payment request UI.

We won't go into details of how to add Android Pay in this article,we have a section dedicated to that here.

Edge Cases

There are some edge cases to be aware of when defining your supported payment methods.

Unsupported Payment MethodsIf you try to callshow()on aPaymentRequestobject and there are no supported payment methods, the returned promise will reject immediately with the following error:

DOMException: The payment method is not supported

This shouldn't be a problem if you include 'basic-card' as a supported payment method. If, however, you only support a third party payment method, like Android Pay, there is a strong chance that it won't be supported by a browser that supports the Payment Request API.

Third Party Payment Method Skipping the Payment Request UIIn the screenshot above you can see "Android Pay" as the pre-selected payment option. This has occurred because the example supports both Android Pay and basic cards. If you define Android Pay as youronlypayment method and the browser supports it, the browser can (and Chrome does, at the time of writing) skip the payment request UI altogether after theshow()method is called. Users will be taken straight to the Android Pay app to complete the payment.

Defining Payment Details

The second argument we need to pass to thePaymentRequestconstructor is the payment details object. This object contains the total for the order and an optional array of display items (i.e. a high level breakdown of the total).

Transaction Details: Total

The contents of thetotalparameter should contain alabelparameter and anamountparameter consisting of acurrencyandvalue. A basic example would be:



This controls the "order summary" section of the UI:

How the total parameter affects the UI.

Thetotalparameter is the only_required_piece of information in the payment details object.

Thelabelcan be any piece of text you like, thecurrencymust be a string currency code following theISO 4217 standard, and thevalueis the amount for the order.

To give another example, we can define the total as:



This produces the following order summary:

Another example of how the total parameter affects the UI.

Transaction Details: Display Items

Display items can used to provide a high level breakdown of the total. This would typically include subtotal, tax, deductions, and shipping cost.

The format of the display items should be an array of items following the same structure as the total (i.e., alabeland anamountwithcurrencyandvalue).



If we provided the above example, we'd get the following UI.

Displaying the items from the payment details object.

The order of the items in thedisplayItemsarray will dictate their display order in the UI.

Please bear in mind thatdisplayItemsare not designed to display a long list of items. You should use this for high level entries instead of an itemized list, for example subtotal, discount, tax and shipping cost.

It's worth repeating that the the

PaymentRequest

API does not perform any arithmetic. If you look at the above example, all the items values do not add up to the total. This is because we've set the total to have a value of zero.

It is the responsibility of your web app to calculate the correct total.

results matching ""

    No results matching ""