Spec changes since the initial launch

Web Payments have shipped in browsers since 2016, and the Payment Request API is now present in Chrome, Safari and Edge, with Firefox to follow. The Payment Handler API has evolved alongside it. The changes below do not break existing code, but they are worth tracking. The "Web Payments Overview" remains the starting point for newcomers.

Instrument checks: hasEnrolledInstrument() and canMakePayment()

The spec update replaces canMakePayment() with hasEnrolledInstrument() without altering what the check does: it reports whether the user has a payment instrument on file. The new method has consensus from all major browsers. Chrome implemented it in version 74; Webkit and Gecko both carry tracking bugs but had not shipped it as of June 2019.

Code that calls canMakePayment() should be rewritten against the new name.

// Before
const canMakePayment = await request.canMakePayment();

With code that looks like this:

// After
const hasEnrolledInstrument = await request.hasEnrolledInstrument();

Because presence checking moved to hasEnrolledInstrument(), canMakePayment() was narrowed to cover only payment app availability. That behavior change is tied to implementing the new method, so as of June 2019 only Chrome 74 carries it. Feature-detect hasEnrolledInstrument() before calling it.

if (request.hasEnrolledInstrument) {
  // Use hasEnrolledInstrument()
}

Address and payment detail updates

PaymentAddress.languageCode no longer appears on shipping or billing addresses for basic-card. Billing addresses supplied by other payment methods, Google Pay among them, are unaffected. Chrome 74, Firefox and Safari have implemented the removal.

PaymentRequest.show() now accepts an optional detailsPromise, letting a merchant open the payment request UI before the final total is settled. The promise must resolve within ten seconds or it times out — the design targets a quick server-side roundtrip. Chrome 75 and Safari have shipped this.

const detailsPromise = fetch('/final-details').then(r => r.json());
await request.show(detailsPromise);

Payment handler-driven method changes

PaymentRequestEvent.changePaymentMethod() lets a payment handler such as Google Pay fire the onpaymentmethodchange event handler. The method returns a promise resolving to a merchant response carrying updated price information, such as a tax recalculation. Both changePaymentMethod() and the paymentmethodchange event are available in Chrome 76, and Webkit has implemented the event in its Technology Preview.

// In the payment handler
self.addEventListener('paymentrequest', event => {
  event.changePaymentMethod('https://example.com/basic-card', {});
});

Merchant example:

request.addEventListener('paymentmethodchange', event => {
  // Recalculate based on event.methodDetails
});

Local development in Chrome 76

Two flags make Web Payments testable on a development machine. With a self-signed certificate, --ignore-certificate-errors lets Chrome exercise the APIs. For a local web server without HTTPS, --unsafely-treat-insecure-origin-as-secure=<origin> makes Chrome treat the HTTP origin as secure.