How to use JavaScript Payment Request API

published: 30 Sep 2022

2 min read

Working with JavaScript Payment Request API

The Payment Request API is a new JavaScript API that provides a cross-browser standard to collect a payment, address, and contact information from customers that can be used to process an order.

It also facilitates the exchange of this information between the browser and the website. The fundamental idea behind this is to improve the user's online shopping experience by making it easy for users to store payment and contact information in the browser.

Browser Support

The Payment Request API is still in active development and is only supported by the last few versions of modern browsers. Before we start making a payment request, we should feature detect to ensure that the API is supported by the browser:

if (window.PaymentRequest) {
  // Yes, we can use the API
} else {
  // No, fallback to the checkout page
  window.location.href = '/checkout'
}

Note: You can only use the Payment Request API on sites serving over https.

PaymentRequest Object

A payment request is always started by creating a new object of PaymentRequest - using the PaymentRequest() constructor. The constructor takes two mandatory parameters and one optional parameter:

  • paymentMethods defines which forms of payment are accepted. For example, you may only accept Visa and MasterCard credit cards.
  • paymentDetails contains the total payment amount due, taxes, shipping cost, display items, etc.
  • options is an optional argument used to request additional details from the user, such as name, email, phone, etc.

Let's create a new payment request with only the required parameters:

const paymentMethods = [
  {
    supportedMethods: ['basic-card']
  }
]

const paymentDetails = {
  total: {
    label: 'Total Amount',
    amount: {
      currency: 'USD',
      value: 8.49
    }
  }
}

const paymentRequest = new PaymentRequest(paymentMethods, paymentDetails)

Notice the supportedMethods parameter in paymentMethods object. When it is set to basic-card, both debit and credit cards of all networks will be accepted. However, we can limit the supported networks and types of cards. For example, with the following only Visa, MasterCard, and Discover credit cards are accepted:

const paymentMethods = [
  {
    supportedMethods: ['basic-card'],
    data: {
      supportedNetworks: ['visa', 'mastercard', 'discover'],
      supportedTypes: ['credit']
    }
  }
]
// ...

Payment Details

The second parameter passed to the PaymentRequest constructor is the payment details object. It contains the total of the order and an optional array of display items. The total parameter must include a label parameter and an amount parameter with currency and value.

You can also add additional display items to provide a high-level breakdown of the total:

const paymentDetails = {
  total: {
    label: 'Total Amount',
    amount: {
      currency: 'USD',
      value: 8.49
    }
  },
  displayItems: [
    {
      label: '15% Discount',
      amount: {
        currency: 'USD',
        value: -1.49
      }
    },
    {
      label: 'Tax',
      amount: {
        currency: 'USD',
        value: 0.79
      }
    }
  ]
}

The displayItems parameter is not meant to display a long list of items. Since space is limited for the browser's payment UI on mobile devices, you should use this to display only top-level fields such as subtotal, discount, tax, shipping cost, etc.

The PaymentRequest API does not perform any calculations. So, your web application is responsible for providing the pre-calculated total amount.

Requesting Additional Details

The third optional parameter can be used to request additional information from the user, such as name, email address, and phone number:

// ...
const options = {
  requestPayerName: true,
  requestPayerPhone: true,
  requestPayerEmail: true
}

const paymentRequest = new PaymentRequest(paymentMethods, paymentDetails, options)

By default, all of these values are false, but adding any of them to the options object with a value true will result in an extra step in the payment UI. If the user has already stored these details in the browser, they will be pre-populated.

Display Payment UI

After creating a PaymentRequest object, you must call the show() method to display the payment request UI to the user. The show() method returns a promise that resolves with a PaymentResponse object if the user has successfully filled in the details. If there is an error or the user closes the UI, the promise rejects.

// ...
const paymentRequest = new PaymentRequest(paymentMethods, paymentDetails, options)

paymentRequest
  .show()
  .then(paymentResponse => {
    // close the payment UI
    paymentResponse.complete().then(() => {
      // TODO: call REST API to process the payment at the backend server
      // with the data from 'paymentResponse'.
    })
  })
  .catch(err => {
    // user closed the UI or the API threw an error
    console.log('Error:', err)
  })

With the above code, the browser will show the payment UI to the user. Once the user has filled in the details and clicked on the 'Pay' button, you will receive a PaymentResponse object in the show() promise. The payment request UI is closed immediately when you call the PaymentResponse.complete() method. This method returns a new promise so that you can call the backend server with the information collected and process the payment.

Payment Request UI

If you want to call the backend server to process the payment while the payment UI is showing a spinner, you can delay the call to complete(). Let us create a mock function for payment processing with the backend server. It takes paymentResponse as a parameter and returns a promise after 1.5 seconds that resolves to a JSON object:

const processPaymentWithServer = paymentResponse => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve({ status: true })
    }, 1500)
  })
}

//...
paymentRequest
  .show()
  .then(paymentResponse => {
    processPaymentWithServer(paymentResponse).then(data => {
      if (data.status) {
        paymentResponse.complete('success')
      } else {
        paymentResponse.complete('fail')
      }
    })
  })
  .catch(err => {
    console.log('Error:', err)
  })

In the example above, the browser payment UI will show a processing screen until the promise returned by the processPaymentWithServer() method is settled. We also used 'success' and 'fail' strings to tell the browser about the transaction outcome. The browser will show an error message to the user if you call complete('fail').

Payment Request Abort

If you want to cancel the payment request due to no activity or any other reason, you can use the PaymentRequest.abort() method. It immediately closes the payment request UI and rejects the show() promise.

// ...
setTimeout(() => {
  paymentRequest
    .abort()
    .then(() => {
      // aborted payment request
      console.log('Payment request aborted due to no activity.')
    })
    .catch(err => {
      // error while aborting
      console.log('abort() Error: ', err)
    })
}, 5000)

Conclusion

That's the end of a quick introduction to JavaScript Payment Request API. It provides a browser-based method to collect customer payment and contact information that can be sent to the backend server to process the payment.

The aim is to reduce the number of steps in completing an online payment. It makes the whole checkout process smoother by remembering the user's preferred way of paying for goods and services.

If you want to learn more about the Payment Request API, here is a good resource that discusses the main concepts and usage of the API.

How to use JavaScript Payment Request API | Coding Tips And Tricks

Are we missing something?  Help us improve this article. Reach out to us.

Are you looking for other code tips?

Check out what's on in the category: javascript, programming
Check out what's on in the tag: javascript, programming, array