What’s New in the Payment Request API for Apple Pay
Since announcing last April that WebKit supports the W3C Payment Request API for Apple Pay, we’ve been hard at work adding even more features to the API. From support for phonetic names in the Apple Pay payment method to new standard features like the paymentmethodchange
event and PaymentResponse.retry()
, WebKit’s Payment Request implementation is now more capable than ever. Anything you could’ve done in the Apple Pay JS API can now be done directly with the Payment Request API using the Apple Pay payment method.
Let’s take a closer look at some of the improvements we’ve made to Payment Request in the past year.
The paymentmethodchange event
When the user selects a card in the Apple Pay payment sheet, WebKit now dispatches the paymentmethodchange
event to your PaymentRequest
object. WebKit populates the event’s methodDetails
attribute with an ApplePayPaymentMethod
dictionary, which you can use to determine information about the card such as its type.
Listening for paymentmethodchange
is optional, but if you do, be sure to call the event’s updateWith()
method with a promise for updated payment details.
const request = new PaymentRequest(...);
request.onpaymentmethodchange = (event) => {
// Compute new details based on event.methodDetails
const detailsUpdatePromise = computeDetails(event.methodDetails);
event.updateWith(detailsUpdatePromise);
};
Whether or not you listen for the paymentmethodchange
event, WebKit continues to support payment details modifiers
, a declarative way to vary payment details based on the user’s selected card. See last year’s blog post for more information about modifiers.
Requesting Phonetic Names
The Apple Pay payment method now supports requesting a phonetic spelling of your customer’s name as part of shipping and billing contact information. Here’s an Apple Pay payment method that requests a shipping contact containing a localized name, a phonetic name, and a postal address:
const applePayMethod = {
supportedMethods: "https://apple.com/apple-pay",
data: {
...,
requiredShippingContactFields: ["name", "phoneticName", "postalAddress"],
},
};
When your customer authorizes payment, WebKit provides the phonetic name as part of the ApplePayPayment
dictionary that’s stored in the PaymentResponse
‘s details
attribute.
const request = new PaymentRequest([applePayMethod], ...);
request.show().then((response) => {
const shippingContact = response.details.shippingContact;
const phoneticFamilyName = shippingContact.phoneticFamilyName;
const phoneticGivenName = shippingContact.phoneticGivenName;
});
Reporting Errors
When handling contact information, you might encounter an error that needs to be resolved by the customer before they can proceed with the transaction. Common examples include invalid addresses, unserviceable addresses, and missing contact information.
So that you can report these errors to your customers, WebKit now supports Payment Request’s fine-grained error reporting capabilities in the PaymentDetailsUpdate
dictionary. You can specify shippingAddressErrors
for errors with shipping address attributes, payerErrors
for errors with names, email addresses, and phone numbers, and paymentMethodErrors
for errors specific to the selected payment method. The Apple Pay payment method treats paymentMethodErrors
as a sequence of ApplePayError
objects.
Here’s how you might report an error for an invalid postal code:
const request = new PaymentRequest([applePayMethod], details, { requestShipping: true });
request.onshippingaddresschange = (event) => {
// Compute new details based on shippingAddress
const detailsUpdate = computeDetails(request.shippingAddress);
// Check for an invalid postal code
if (!isValid(request.shippingAddress.postalCode))
detailsUpdate.shippingAddressErrors = { postalCode: "Invalid postal code" };
event.updateWith(detailsUpdate);
};
When you report errors, WebKit displays them in the Apple Pay payment sheet and prompts your customer to make corrections — perhaps by editing their shipping address or selecting from a list of stored address. Here’s what the shipping address error we specified above looks like on an iPhone.
When your customer taps on the erroneous shipping address, the Apple Pay sheet displays your custom error message. If they decide to edit their address, the fields you flagged with errors (postalCode
, in this case) are highlighted to help guide them through making corrections.
Once the user finishes making corrections, WebKit fires the shippingaddresschange
event again. If you are satisfied with the corrections, you can proceed with the transaction by calling the updateWith()
method again without specifying errors.
When handling errors in shippingaddresschange
, keep in mind that WebKit redacts some parts of the shipping contact before payment authorization. The rules vary by country, but in general, WebKit reveals only the contact information necessary to calculate tax and shipping costs. Once the customer authorizes payment, WebKit reveals all the requested contact information.
Retrying Authorizations
While many errors can be detected when handling events like shippingaddresschange
, the redaction rules mentioned above mean that some errors can only be detected once the user has authorized payment. For instance, you might require an email address to send a purchase confirmation, only to find after authorization that the customer did not provide a valid one.
To handle these cases, WebKit now implements PaymentResponse
‘s retry()
method, allowing you to ask the user to retry the payment after correcting for errors.
When you detect an error in a PaymentResponse
, you can call retry()
with a PaymentValidationErrors
dictionary. Like in PaymentDetailsUpdate
, you can specify shippingAddress
errors, payer
errors, and paymentMethod
errors. When you call retry()
, it returns a promise that resolves once the PaymentResponse
is re-authorized.
Here’s how you might handle an invalid email address:
const handleResponse = (response) => {
if (!isValid(response.payerEmail)) {
response.retry({
payer: { email: "Invalid email address" },
}).then(() => { handleResponse(response) });
return;
}
response.complete("success");
};
const request = new PaymentRequest([applePayMethod], ...);
request.show().then(response => handleResponse(response));
Keep in mind that retry()
is for errors that can be corrected by the user. If you detect a fatal error — for example, the card was declined or an item is no longer in stock — call PaymentResponse
‘s complete()
method with a PaymentComplete
value of 'fail'
. The Apple Pay payment sheet will display an appropriate error to the user and then dismiss itself.
Availability
These new Payment Request features are available starting in Safari 12.1 on macOS, Safari on iOS 12.2, and Safari Technology Preview.
Feedback
We’ve received some great developer feedback so far, and we look forward to more of your bug reports and feature requests. If you find a Payment Request bug in WebKit, please report it at bugs.webkit.org. On Twitter, you can reach the WebKit team at @webkit, or our web technologies evangelist Jonathan Davis at @jonathandavis.