VOOZH about

URL: https://w3c.github.io/web-based-payment-handler/

⇱ Web-based Payment Handler API


This specification defines capabilities that enable Web applications to handle requests for payment.

The Web Payments Working Group maintains a list of all bug reports that the group has not yet addressed. This draft highlights some of the pending issues that are still to be discussed in the working group. No decision has been taken on the outcome of these issues including whether they are valid. Pull requests with proposed specification text for outstanding issues are strongly encouraged.

Introduction

This specification defines a number of new features to allow web applications to handle requests for payments on behalf of users:

This specification does not address how software built with operating-system specific mechanisms (i.e., "native apps") handle payment requests.

Overview

In this document we envision the following flow:

  1. An origin requests permission from the user to handle payment requests for a set of supported payment methods. For example, a user visiting a retail or bank site may be prompted to register a web-based payment handler from that origin. The origin establishes the scope of the permission but the origin's capabilities may evolve without requiring additional user consent.
  2. are defined in code.
  3. When the merchant (or other payee) calls the [[payment-request]] method or (e.g., when the user -- the payer -- pushes a button on a checkout page), the user agent computes a list of candidate web-based payment handlers, comparing the payment methods accepted by the merchant with those known to the user agent through any number of mechanisms, including, but not limited to:
    • Those previously registered through this API.
    • Those that may be registered through this API during the course of the transaction, e.g., identified through a .
    • Those registered through other mechanisms, e.g., the operating system.
  4. The user agent displays a set of choices to the user: the candidate payment handlers. The user agent displays these choices using information (labels and icons) provided at registration or otherwise available from the Web app.
  5. When the user selects a web-based payment handler, the user agent fires a {{PaymentRequestEvent}} (cf. the ) in the for the selected web-based payment handler. The {{PaymentRequestEvent}} includes some information from the PaymentRequest (defined in [[!payment-request]]) as well as additional information (e.g., payee's origin).
  6. Once activated, the web-based payment handler performs whatever steps are necessary to handle the payment request, and return an appropriate payment response to the . If interaction with the user is necessary, the can open a window for that purpose.
  7. The user agent receives a response asynchronously once the web-based payment handler has finished handling the request. The response becomes the (of [[!payment-request]]).

An origin may implement a payment app with more than one service worker and therefore multiple may be registered per origin. The handler that is invoked is determined by the selection made by the user.

Handling a Payment Request

A Web-based payment handler is a Web application based [=payment handler=]; that is, a Web application that can handle a request for payment on behalf of the user.

The logic of a web-based payment handler is driven by the payment methods that it supports. Some payment methods expect little to no processing by the web-based payment handler which simply returns payment card details in the response. It is then the job of the payee website to process the payment using the returned data as input.

In contrast, some payment methods, such as a crypto-currency payments or bank originated credit transfers, require that the web-based payment handler initiate processing of the payment. In such cases the web-based payment handler will return a payment reference, endpoint URL or some other data that the payee website can use to determine the outcome of the payment (as opposed to processing the payment itself).

Handling a payment request may include numerous interactions: with the user through a new window or other APIs (such as [[[WebCryptoAPI]]]) or with other services and origins through web requests or other means.

This specification does not address these activities that occur between the web-based payment handler accepting the {{PaymentRequestEvent}} and the web-based payment handler returning a response. All of these activities which may be required to configure the web-based payment handler and handle the payment request, are left to the implementation of the web-based payment handler, including:

  • how the user establishes an account with an origin that provides payment services.
  • how an origin authenticates a user.
  • how communication takes place between the payee server and the payee Web application, or between a payment app origin and other parties.

Thus, an origin will rely on many other Web technologies defined elsewhere for lifecycle management, security, user authentication, user interaction, and so on.

Relation to Other Types of Payment Apps

This specification does not address how third-party mobile payment apps interact (through proprietary mechanisms) with user agents, or how user agents themselves provide simple payment app functionality.

👁 Different types of payment apps. Web-based Payment Handler API is for Web apps.
Web-based Payment Handler API enables Web apps to handle payments. Other types of payment apps may use other (proprietary) mechanisms.

Registration

One registers a web-based payment handler with the user agent through a just-in-time (JIT) registration mechanism.

Just-in-time registration

If a web-based payment handler is not registered when a merchant invokes {{PaymentRequest/show()}} method, a user agent may allow the user to register this web-based payment handler during the transaction ("just-in-time").

The remaining content of this section is non-normative.

A user agent may perform just-in-time installation by deriving web-based payment handler information from the that is found through the that the merchant requested.

Management

This section describes the functionality available to a web-based payment handler to manage its own properties.

Extension to the `ServiceWorkerRegistration` interface

 partial interface ServiceWorkerRegistration {
 [SameObject] readonly attribute PaymentManager paymentManager;
 };
 

The paymentManager attribute exposes web-based payment handler management functionality.

PaymentManager interface

 [SecureContext, Exposed=(Window)]
 interface PaymentManager {
 attribute DOMString userHint;
 Promise<undefined> enableDelegations(sequence<PaymentDelegation> delegations);
 };
 

The {{PaymentManager}} is used by s to manage their supported delegations.

userHint attribute

When displaying web-based payment handler name and icon, the user agent may use this string to improve the user experience. For example, a user hint of "**** 1234" can remind the user that a particular card is available through this web-based payment handler.

enableDelegations() method

This method allows a to asynchronously declare its supported list.

PaymentDelegation enum

 enum PaymentDelegation {
 "shippingAddress",
 "payerName",
 "payerPhone",
 "payerEmail"
 };
 
"shippingAddress"
The web-based payment handler will provide shipping address whenever needed.
"payerName"
The web-based payment handler will provide payer's name whenever needed.
"payerPhone"
The web-based payment handler will provide payer's phone whenever needed.
"payerEmail"
The web-based payment handler will provide payer's email whenever needed.

Can make payment

If the supports , the may use it to help with filtering of the available web-based payment handlers.

Implementations may impose a timeout for developers to respond to the . If the timeout expires, then the implementation will behave as if {{CanMakePaymentEvent/respondWith()}} was called with `false`.

Extension to `ServiceWorkerGlobalScope`

 partial interface ServiceWorkerGlobalScope {
 attribute EventHandler oncanmakepayment;
 };
 

oncanmakepayment attribute

The {{ServiceWorkerGlobalScope/oncanmakepayment}} attribute is an whose corresponding is "canmakepayment".

The CanMakePaymentEvent

The is used to as a signal for whether the web-based payment handler is able to respond to a payment request.

 [Exposed=ServiceWorker]
 interface CanMakePaymentEvent : ExtendableEvent {
 constructor(DOMString type);
 undefined respondWith(Promise<boolean> canMakePaymentResponse);
 };
 

respondWith() method

This method is used by the web-based payment handler as a signal for whether it can respond to a payment request.

Handling a CanMakePaymentEvent

Upon receiving a , the MUST run the following steps:

  1. If settings prohibit usage of (e.g., in private browsing mode), terminate these steps.
  2. Let registration be a {{ServiceWorkerRegistration}}.
  3. If registration is not found, terminate these steps.
  4. "canmakepayment" using on registration.

Example of handling the

This example shows how to write a service worker that listens to the . When a is received, the service worker always returns true.

 self.addEventListener("canmakepayment", function(e) {
 e.respondWith(new Promise(function(resolve, reject) {
 resolve(true);
 }));
 });
 

Filtering of Payment Handlers

Given a and a web-based payment handler that matches on , this algorithm returns true if this web-based payment handler can be used for payment:

  1. Let methodName be the string specified in the .
  2. Let methodData be the payment method specific data of .
  3. Let paymentHandlerOrigin be the of the {{ServiceWorkerRegistration}} scope URL of the web-based payment handler.
  4. Let paymentMethodManifest be the and for the methodName.
  5. If methodName is a with the "*" string in paymentMethodManifest, return true.
  6. Otherwise, if the methodName has the same as paymentHandlerOrigin, fire the in the web-based payment handler and return the result.
  7. Otherwise, if in paymentMethodManifest is an ordered set of [=url/origin=] that contains the paymentHandlerOrigin, fire the in the web-based payment handler and return the result.
  8. Otherwise, return `false`.

Invocation

Once the user has selected a web-based payment handler, the user agent fires a {{PaymentRequestEvent}} and uses the subsequent to create a for [[!payment-request]].

Payment Request API supports delegation of responsibility to manage an abort to a payment app. There is a proposal to add a paymentRequestAborted event to the Web-based Payment Handler interface. The event will have a respondWith method that takes a boolean parameter indicating if the paymentRequest has been successfully aborted.

Extension to

This specification extends the interface.

 partial interface ServiceWorkerGlobalScope {
 attribute EventHandler onpaymentrequest;
 };
 

onpaymentrequest attribute

The attribute is an whose corresponding is {{PaymentRequestEvent}}.

The PaymentRequestDetailsUpdate

The PaymentRequestDetailsUpdate contains the updated total (optionally with modifiers and shipping options) and possible errors resulting from user selection of a payment method, a shipping address, or a shipping option within a web-based payment handler.

 dictionary PaymentRequestDetailsUpdate {
 DOMString error;
 PaymentCurrencyAmount total;
 sequence<PaymentDetailsModifier> modifiers;
 sequence<PaymentShippingOption> shippingOptions;
 object paymentMethodErrors;
 AddressErrors shippingAddressErrors;
 };
 

error member

A human readable string that explains why the user selected web-based payment method, shipping address or shipping option cannot be used.

total member

Updated total based on the changed payment method, shipping address, or shipping option. The total can change, for example, because the billing address of the payment method selected by the user changes the Value Added Tax (VAT); Or because the shipping option/address selected/provided by the user changes the shipping cost.

modifiers member

Updated modifiers based on the changed payment method, shipping address, or shipping option. For example, if the overall total has increased by €1.00 based on the billing or shipping address, then the totals specified in each of the modifiers should also increase by €1.00.

shippingOptions member

Updated shippingOptions based on the changed shipping address. For example, it is possible that express shipping is more expensive or unavailable for the user provided country.

paymentMethodErrors member

Validation errors for the payment method, if any.

shippingAddressErrors member

Validation errors for the shipping address, if any.

The PaymentRequestEvent

The PaymentRequestEvent represents the data and methods available to a Payment Handler after selection by the user. The user agent communicates a subset of data available from the to the Payment Handler.

 [Exposed=ServiceWorker]
 interface PaymentRequestEvent : ExtendableEvent {
 constructor(DOMString type, optional PaymentRequestEventInit eventInitDict = {});
 readonly attribute USVString topOrigin;
 readonly attribute USVString paymentRequestOrigin;
 readonly attribute DOMString paymentRequestId;
 readonly attribute FrozenArray<PaymentMethodData> methodData;
 readonly attribute object total;
 readonly attribute FrozenArray<PaymentDetailsModifier> modifiers;
 readonly attribute object? paymentOptions;
 readonly attribute FrozenArray<PaymentShippingOption>? shippingOptions;
 Promise<WindowClient?> openWindow(USVString url);
 Promise<PaymentRequestDetailsUpdate?> changePaymentMethod(DOMString methodName, optional object? methodDetails = null);
 Promise<PaymentRequestDetailsUpdate?> changeShippingAddress(optional AddressInit shippingAddress = {});
 Promise<PaymentRequestDetailsUpdate?> changeShippingOption(DOMString shippingOption);
 undefined respondWith(Promise<PaymentHandlerResponse> handlerResponsePromise);
 };
 

topOrigin attribute

Returns a string that indicates the of the top level web page. This attribute is initialized by .

paymentRequestOrigin attribute

Returns a string that indicates the where a was initialized. When a is initialized in the , the attributes have the same value, otherwise the attributes have different values. For example, when a is initialized within an iframe from an origin other than , the value of this attribute is the origin of the iframe. This attribute is initialized by .

paymentRequestId attribute

When getting, the attribute returns the {{ PaymentRequest/[[details]] }}. from the that corresponds to this {{PaymentRequestEvent}}.

methodData attribute

This attribute contains dictionaries containing the for the that the web site accepts and any associated specific data. It is populated from the using the defined below.

total attribute

This attribute indicates the total amount being requested for payment. It is of type dictionary as defined in [[payment-request]], and initialized with a copy of the field of the provided when the corresponding object was instantiated.

modifiers attribute

This sequence of dictionaries contains modifiers for particular payment method identifiers (e.g., if the payment amount or currency type varies based on a per-payment-method basis). It is populated from the using the defined below.

paymentOptions attribute

The value of in the . Available only when shippingAddress and/or any subset of payer's contact information are requested.

shippingOptions attribute

The value of in the dictionary of the corresponding .( inherits ShippingOptions from ). Available only when shipping address is requested.

openWindow() method

This method is used by the web-based payment handler to show a window to the user. When called, it runs the .

changePaymentMethod() method

This method is used by the web-based payment handler to get updated total given such payment method details as the billing address. When called, it runs the .

changeShippingAddress() method

This method is used by the web-based payment handler to get updated payment details given the shippingAddress. When called, it runs the .

changeShippingOption() method

This method is used by the web-based payment handler to get updated payment details given the shippingOption identifier. When called, it runs the .

respondWith() method

This method is used by the web-based payment handler to provide a when the payment successfully completes. When called, it runs the with |event| and handlerResponsePromise as arguments.

Should payment apps receive user data stored in the user agent upon explicit consent from the user? The payment app could request permission either at installation or when the payment app is first invoked.

PaymentRequestEventInit dictionary

 dictionary PaymentRequestEventInit : ExtendableEventInit {
 USVString topOrigin;
 USVString paymentRequestOrigin;
 DOMString paymentRequestId;
 sequence<PaymentMethodData> methodData;
 PaymentCurrencyAmount total;
 sequence<PaymentDetailsModifier> modifiers;
 PaymentOptions paymentOptions;
 sequence<PaymentShippingOption> shippingOptions;
 };
 

The topOrigin, paymentRequestOrigin, paymentRequestId, methodData, total, modifiers, paymentOptions, and shippingOptions members share their definitions with those defined for {{PaymentRequestEvent}}

MethodData Population Algorithm

To initialize the value of the , the user agent MUST perform the following steps or their equivalent:

  1. Let registeredMethods be the set of registered s of the invoked web-based payment handler.
  2. Create a new empty .
  3. Set dataList to the newly created .
  4. For each item in @[[\methodData]] in the corresponding payment request, perform the following steps:
    1. Set inData to the item under consideration.
    2. Set commonMethods to the set intersection of inData. and registeredMethods.
    3. If commonMethods is empty, skip the remaining substeps and move on to the next item (if any).
    4. Create a new object.
    5. Set outData to the newly created .
    6. Set outData. to a list containing the members of commonMethods.
    7. Set outData.data to a copy of inData.data.
    8. Append outData to dataList.
  5. Set to dataList.

Modifiers Population Algorithm

To initialize the value of the , the user agent MUST perform the following steps or their equivalent:

  1. Let registeredMethods be the set of registered s of the invoked web-based payment handler.
  2. Create a new empty .
  3. Set modifierList to the newly created .
  4. For each item in @[[\paymentDetails]]. in the corresponding payment request, perform the following steps:
    1. Set inModifier to the item under consideration.
    2. Set commonMethods to the set intersection of inModifier. and registeredMethods.
    3. If commonMethods is empty, skip the remaining substeps and move on to the next item (if any).
    4. Create a new object.
    5. Set outModifier to the newly created .
    6. Set outModifier. to a list containing the members of commonMethods.
    7. Set outModifier. to a copy of inModifier..
    8. Append outModifier to modifierList.
  5. Set to modifierList.

Internal Slots

Instances of {{PaymentRequestEvent}} are created with the internal slots in the following table:

Internal Slot Default Value Description (non-normative)
[[\windowClient]] null The currently active WindowClient. This is set if a web-based payment handler is currently showing a window to the user. Otherwise, it is null.
[[\respondWithCalled]] false YAHO

Handling a PaymentRequestEvent

Upon receiving a by way of and subsequent user selection of a web-based payment handler, the MUST run the following steps:

  1. Let registration be the {{ServiceWorkerRegistration}} corresponding to the web-based payment handler selected by the user.
  2. If registration is not found, reject the {{Promise}} that was created by with an {{"InvalidStateError"}} {{DOMException}} and terminate these steps.
  3. "paymentrequest" using {{PaymentRequestEvent}} on registration with the following properties:

    {{PaymentRequestEvent/topOrigin}}
    the [=serialization of an origin=] of the top level payee web page.
    the [=serialization of an origin=] of the context where PaymentRequest was initialized.
    {{PaymentRequestEvent/methodData}}
    The result of executing the .
    The result of executing the .
    {{PaymentRequestEvent/total}}
    A copy of the total field on the from the corresponding .
    \[\[details\]\]. from the .
    A copy of the paymentOptions dictionary passed to the constructor of the corresponding .
    A copy of the shippingOptions field on the from the corresponding .

    Then run the following steps in parallel, with dispatchedEvent:

    1. Wait for all of the promises in the of dispatchedEvent to resolve.
    2. If the has not provided a , reject the {{Promise}} that was created by with an {{"OperationError"}} {{DOMException}}.

Windows

An invoked web-based payment handler may or may not need to display information about itself or request user input. Some examples of potential web-based payment handler display include:

A that requires visual display and user interaction, may call openWindow() to display a page to the user.

Since user agents know that this method is connected to the {{PaymentRequestEvent}}, they SHOULD render the window in a way that is consistent with the flow and not confusing to the user. The resulting window client is bound to the tab/window that initiated the . A single SHOULD NOT be allowed to open more than one client window using this method.

Open Window Algorithm

This algorithm resembles the in the Service Workers specification.

Should we refer to the Service Workers specification instead of copying their steps?

  1. Let |event| be this {{PaymentRequestEvent}}.
  2. If |event|'s {{Event/isTrusted}} attribute is false, return a {{Promise}} rejected with a {{"InvalidStateError"}} {{DOMException}}.
  3. Let request be the that triggered this {{PaymentRequestEvent}}.
  4. Let url be the result of the url argument.
  5. If the url parsing throws an exception, return a {{Promise}} rejected with that exception.
  6. If url is about:blank, return a {{Promise}} rejected with a {{TypeError}}.
  7. If url's origin is not the same as the 's origin associated with the web-based payment handler, return a {{Promise}} resolved with null.
  8. Let promise be a new {{Promise}}.
  9. Return promise and perform the remaining steps in parallel:
  10. If |event|.{{ PaymentRequestEvent/[[windowClient]] }} is not null, then:
    1. If |event|.{{ PaymentRequestEvent/[[windowClient]] }}. is not "unloaded", reject promise with an {{"InvalidStateError"}} {{DOMException}} and abort these steps.
  11. Let newContext be a new .
  12. newContext to url, with exceptions enabled and replacement enabled.
  13. If the navigation throws an exception, reject promise with that exception and abort these steps.
  14. If the origin of newContext is not the same as the origin associated with the web-based payment handler, then:
    1. Resolve promise with null.
    2. Abort these steps.
  15. Let client be the result of running the algorithm with newContext as the argument.
  16. Set |event|.{{ PaymentRequestEvent/[[windowClient]] }} to client.
  17. Resolve promise with client.

Example of handling the {{PaymentRequestEvent}}

This example shows how to write a service worker that listens to the {{PaymentRequestEvent}}. When a {{PaymentRequestEvent}} is received, the service worker opens a window to interact with the user.

 async function getPaymentResponseFromWindow() {
 return new Promise((resolve, reject) => {
 self.addEventListener("message", listener = e => {
 self.removeEventListener("message", listener);
 if (!e.data || !e.data.methodName) {
 reject();
 return;
 }
 resolve(e.data);
 });
 });
 }

 self.addEventListener("paymentrequest", e => {
 e.respondWith((async() => {
 // Open a new window for providing payment UI to user.
 const windowClient = await e.openWindow("payment_ui.html");

 // Send data to the opened window.
 windowClient.postMessage({
 total: e.total,
 modifiers: e.modifiers
 });

 // Wait for a payment response from the opened window.
 return await getPaymentResponseFromWindow();
 })());
 });
 

Using the simple scheme described above, a trivial HTML page that is loaded into the might look like the following:

<form id="form">
<table>
 <tr><th>Cardholder Name:</th><td><input name="cardholderName"></td></tr>
 <tr><th>Card Number:</th><td><input name="cardNumber"></td></tr>
 <tr><th>Expiration Month:</th><td><input name="expiryMonth"></td></tr>
 <tr><th>Expiration Year:</th><td><input name="expiryYear"></td></tr>
 <tr><th>Security Code:</th><td><input name="cardSecurityCode"></td></tr>
 <tr><th></th><td><input type="submit" value="Pay"></td></tr>
</table>
</form>

<script>
navigator.serviceWorker.addEventListener("message", e => {
 /* Note: message sent from payment app is available in e.data */
});

document.getElementById("form").addEventListener("submit", e => {
 const details = {};
 ["cardholderName", "cardNumber", "expiryMonth", "expiryYear", "cardSecurityCode"]
 .forEach(field => {
 details[field] = form.elements[field].value;
 });

 const paymentAppResponse = {
 methodName: "https://example.com/pay",
 details
 };

 navigator.serviceWorker.controller.postMessage(paymentAppResponse);
 window.close();
});
</script>
 

Response

PaymentHandlerResponse dictionary

The user agent receives a successful response from the web-based payment handler through resolution of the Promise provided to the {{PaymentRequestEvent/respondWith}} function of the corresponding {{PaymentRequestEvent}} interface. The application is expected to resolve the Promise with a instance containing the payment response. In case of user cancellation or error, the application may signal failure by rejecting the Promise.

The PaymentHandlerResponse is conveyed using the following dictionary:

 dictionary PaymentHandlerResponse {
 DOMString methodName;
 object details;
 DOMString? payerName;
 DOMString? payerEmail;
 DOMString? payerPhone;
 AddressInit shippingAddress;
 DOMString? shippingOption;
 };
 

methodName attribute

The for the that the user selected to fulfil the transaction.

details attribute

A object that provides a specific message used by the merchant to process the transaction and determine successful fund transfer.

payerName attribute

The user provided payer's name.

payerEmail attribute

The user provided payer's email.

payerPhone attribute

The user provided payer's phone number.

shippingAddress attribute

The user provided shipping address.

shippingOption attribute

The identifier of the user selected shipping option.

Change Payment Method Algorithm

When this algorithm is invoked with methodName and methodDetails parameters, the user agent MUST run the following steps:

  1. Run the with |event| constructed using the given methodName and methodDetails parameters.
  2. If |event|. is not run, return null.
  3. If |event|. throws, rethrow the error.
  4. If |event|. times out (optional), throw {{"InvalidStateError"}} {{DOMException}}.
  5. Construct and return a from the detailsPromise in |event|..

Change Payment Details Algorithm

When this algorithm is invoked with shippingAddress or shippingOption the user agent MUST run the following steps:

  1. Run the with |event| constructed using the updated details (shippingAddress or shippingOption).
  2. If |event|. is not run, return null.
  3. If |event|. throws, rethrow the error.
  4. If |event|. times out (optional), throw {{"InvalidStateError"}} {{DOMException}}.
  5. Construct and return a from the detailsPromise in |event|..

Respond to PaymentRequest Algorithm

When this algorithm is invoked with |event| and handlerResponsePromise parameters, the user agent MUST run the following steps:

  1. If |event|'s {{Event/isTrusted}} is false, then throw an "InvalidStateError" {{DOMException}} and abort these steps.
  2. If |event|'s [=Event/dispatch flag=] is unset, then throw an {{"InvalidStateError"}} {{DOMException}} and abort these steps.
  3. If |event|.{{ PaymentRequestEvent/[[respondWithCalled]] }} is true, throw an {{"InvalidStateError"}} {{DOMException}} and abort these steps.
  4. Set |event|.{{ PaymentRequestEvent/[[respondWithCalled]] }} to true.
  5. Set the |event|'s [=Event/stop propagation flag=] and event's [=Event/stop immediate propagation flag=].
  6. Add handlerResponsePromise to the |event|'s
  7. Increment the |event|'s by one.
  8. of handlerResponsePromise with |reason|:
    1. Run the with |reason|, and terminate these steps.
  9. of handlerResponsePromise:
    1. Let handlerResponse be |value| {{PaymentHandlerResponse}}. If this throws an exception, run the with an {{"OperationError"}} {{DOMException}}, and terminate these steps.
    2. Validate that all required members exist in handlerResponse and are well formed.
      1. If handlerResponse. is not present or not set to one of the values from |event|., run the with an {{"OperationError"}} {{DOMException}}, and terminate these steps.
      2. If handlerResponse. is not present or not , run the with an {{"OperationError"}} {{DOMException}}, and terminate these steps.
      3. Let shippingRequired be the value of the associated PaymentRequest's . If shippingRequired and handlerResponse. is not present, run the with an {{"OperationError"}} {{DOMException}}, and terminate these steps.
      4. If shippingRequired and handlerResponse. is not present or not set to one of shipping options identifiers from |event|., run the with an {{"OperationError"}} {{DOMException}}, and terminate these steps.
      5. Let payerNameRequired be the value of the associated PaymentRequest's . If payerNameRequired and handlerResponse. is not present, run the with an {{"OperationError"}} {{DOMException}}, and terminate these steps.
      6. Let payerEmailRequired be the value of the associated PaymentRequest's . If payerEmailRequired and handlerResponse. is not present, run the with an {{"OperationError"}} {{DOMException}}, and terminate these steps.
      7. Let payerPhoneRequired be the value of the associated PaymentRequest's . If payerPhoneRequired and handlerResponse. is not present, run the with an {{"OperationError"}} {{DOMException}}, and terminate these steps.
    3. Serialize required members of handlerResponse ( methodName and details are always required; shippingAddress and shippingOption are required when shippingRequired is true; payerName, payerEmail, and payerPhone are required when payerNameRequired, payerEmailRequired, and payerPhoneRequired are true, respectively.):
      1. For each memberin handlerResponseLet serializeMemberbe the result of with handlerResponse.member. Rethrow any exceptions.
    4. The user agent MUST run the as defined in [[!payment-request]], replacing steps 9-15 with these steps or their equivalent.
      1. Deserialize serialized members:
        1. For each serializeMemberlet memberbe the result of with serializeMember. Rethrow any exceptions.
      2. If any exception occurs in the above step, then run the with an {{"OperationError"}} {{DOMException}}, and terminate these steps.
      3. Assign methodName to associated PaymentRequest's ..
      4. Assign details to associated PaymentReqeust's ..
      5. If shippingRequired, then set the attribute of associated PaymentReqeust's to shippingAddress. Otherwise, set it to null.
      6. If shippingRequired, then set the attribute of associated PaymentReqeust's to shippingOption. Otherwise, set it to null.
      7. If payerNameRequired, then set the attribute of associated PaymentReqeust's to payerName. Otherwise, set it to null.
      8. If payerEmailRequired, then set the attribute of associated PaymentReqeust's to payerEmail. Otherwise, set it to null.
      9. If payerPhoneRequired, then set the attribute of associated PaymentReqeust's to payerPhone. Otherwise, set it to null.
  10. or of handlerResponsePromise, to perform the following steps:
    1. Decrement the |event|'s by one.
    2. Let registration be the 's 's associated 's .
    3. If registration is not null, invoke with registration.

The following example shows how to respond to a payment request:

 paymentRequestEvent.respondWith(new Promise(function(accept,reject) {
 /* ... processing may occur here ... */
 accept({
 methodName: "https://example.com/pay",
 details: {
 cardHolderName: "John Smith",
 cardNumber: "1232343451234",
 expiryMonth: "12",
 expiryYear : "2020",
 cardSecurityCode: "123"
 },
 shippingAddress: {
 addressLine: [
 "1875 Explorer St #1000",
 ],
 city: "Reston",
 country: "US",
 dependentLocality: "",
 organization: "",
 phone: "+15555555555",
 postalCode: "20190",
 recipient: "John Smith",
 region: "VA",
 sortingCode: ""
 },
 shippingOption: "express",
 payerEmail: "john.smith@gmail.com",
 });
 }));
 

[[!payment-request]] defines an that parties in the ecosystem (including payment app providers and payees) can use for reconciliation after network or other failures.

Payment App Failure Algorithm

When this algorithm is invoked with |reason|, the user agent MUST run the following steps:

  1. If |reason| is an {{"OperationError"}} {{DOMException}}, then run the as defined in [[!payment-request]].
  2. Otherwise, run the as defined in [[!payment-request]].

    Previous versions of this specification did not define what happened when the was invoked. In practice, implementors acted as if the was run. To maintain as much backwards compatibility as possible, while still introducing a way for web-based payment handlers to indicate internal error, this specification now maps all reason values other than a {{"OperationError"}} {{DOMException}} to user abort. Future versions of this specification may add additional handled values.

Security and Privacy Considerations

Addresses

The Web Payments Working Group removed support for shipping and billing addresses from the original version of Payment Request API due to privacy issues; see issue 842. In order to provide documentation for implementations that continue to support this capability, the Working Group is now restoring the feature with an expectation of addressing privacy issues. In doing so the Working Group may also make changes to Payment Request API based on the evolution of other APIs (e.g., the Content Picker API).

Information about the User Environment

  • The API does not share information about the user's registered web-based payment handlers. Information from origins is only shared with the payee with the consent of the user.
  • User agents should not share payment request information with any web-based payment handler until the user has selected that payment handler.
  • In a browser that supports Web-based Payment Handler API, when a merchant creates a PaymentRequest object with URL-based payment method identifiers, a will fire in registered web-based payment handlers from a finite set of origins: the origins of the payment method manifests and their . This event is fired before the user has selected that payment handler, but it contains no information about the triggering origin (i.e., the merchant website) and so cannot be used to track users directly.
  • We acknowledge the risk of a timing attack via :
    • A merchant website sends notice via a backend channel (e.g., the fetch API) to a web-based payment handler origin, sharing that they are about to construct a PaymentRequest object.
    • The merchant website then constructs the PaymentRequest, triggering a to be fired at the installed web-based payment handler.
    • That web-based payment handler contacts its own origin, and on the server side attempts to join the two requests.
  • User agents should allow users to disable support for the .
  • In a browser that supports Web-based Payment Handler API, will fire in registered web-based payment handlers that can provide all merchant requested information including shipping address and payer's contact information whenever needed.

User Consent to Install a Payment Handler

  • This specification does not define how the user agent establishes user consent when a web-based payment handler is first registered. The user agent might notify and/or prompt the user during registration.
  • User agents MAY reject web-based payment handler registration for security reasons (e.g., due to an invalid SSL certificate) and SHOULD notify the user when this happens.

User Consent before Payment

  • One goal of this specification is to minimize the user interaction required to make a payment. However, we also want to ensure that the user has an opportunity to consent to making a payment. Because web-based payment handlers are not required to open a window for user interaction, user agents should take necessary steps to make sure the user (1) is made aware when a payment request is invoked, and (2) has an opportunity to interact with a web-based payment handler before the merchant receives the response from that payment handler.

User Awareness about Sharing Data Cross-Origin

  • By design, a web-based payment handler from one origin shares data with another origin (e.g., the merchant site).
  • To mitigate phishing attacks, it is important that user agents make clear to users the origin of a web-based payment handler.
  • User agents should help users understand that they are sharing information cross-origin, and ideally what information they are sharing.

Secure Communications

  • See
  • Payment method security is outside the scope of this specification and is addressed by web-based payment handlers that support those payment methods.

Authorized Payment Apps

  • The party responsible for a payment method authorizes payment apps through a . See the algorithm for details.
  • The user agent is not required to make available web-based payment handlers that pose security issues. Security issues might include:
    • Certificates that are expired, revoked, self-signed, and so on.
    • Mixed content
    • Page available through HTTPs redirects to one that is not.
    • Payment handler is known from safe browsing database to be malicious

    When a web-based payment handler is unavailable for security reasons, the user agent should provide rationale to the web-based payment handler developers (e.g., through console messages) and may also inform the user to help avoid confusion.

Supported Origin

  • authorize origins to distribute payment apps for a given payment method. When the user agent is determining whether a web-based payment handler matches the origin listed in a , the user agent uses the scope URL of the web-based payment handler's .

Data Validation

  • To mitigate the scenario where a hijacked payee site submits fraudlent or malformed payment method data (or, for that matter, payment request data) to the payee's server, the payee's server should validate the data format and correlate the data with authoritative information on the server such as accepted payment methods, total, display items, and shipping address.

Private Browsing Mode

  • When the Payment Request API is invoked in a "private browsing mode," the user agent should launch web-based payment handlers in a private context. This will generally prevent sites from accessing any previously-stored information. In turn, this is likely to require either that the user log in to the origin or re-enter payment details.
  • The event should not be fired in private browsing mode. The user agent should behave as if was called with `false`. We acknowledge a consequent risk: if an entity controls both the origin of the Payment Request API call and the origin of the web-based payment handler, that entity may be able to deduce that the user may be in private browsing mode.

Payment Handler Display Considerations

When ordering web-based payment handlers, the user agent is expected to honor user preferences over other preferences. User agents are expected to permit manual configuration options, such as setting a preferred web-based payment handler display order for an origin, or for all origins.

User experience details are left to implementers.

Dependencies

This specification relies on several other underlying specifications.

Payment Request API
The terms payment method, PaymentRequest, PaymentResponse, supportedMethods, PaymentCurrencyAmount, paymentDetailsModifier, paymentDetailsInit, paymentDetailsBase, PaymentMethodData, PaymentOptions, PaymentShippingOption, AddressInit, AddressErrors, PaymentMethodChangeEvent, PaymentRequestUpdateEvent, ID, canMakePayment(), show(), updateWith(detailsPromise), user accepts the payment request algorithm, payment method changed algorithm, PaymentRequest updated algorithm, and JSON-serializable are defined by the Payment Request API specification [[!payment-request]].
ECMAScript
The terms internal slot and JSON.stringify are defined by [[!ECMASCRIPT]].
Payment Method Manifest
The terms payment method manifest, ingest payment method manifest, parsed payment method manifest, and supported origins are defined by the Payment Method Manifest specification [[!payment-method-manifest]].
Service Workers
The terms service worker, service worker registration, service worker client, ServiceWorkerRegistration, ServiceWorkerGlobalScope, fire functional event, extend lifetime promises,pending promises count, containing service worker registration, Try Clear Registration, Try Activate, ExtendableEvent, ExtendableEventInit, and scope URL are defined in [[!SERVICE-WORKERS]].

There is only one class of product that can claim conformance to this specification: a user agent.

User agents MAY implement algorithms given in this specification in any way desired, so long as the end result is indistinguishable from the result that would be obtained by the specification's algorithms.

User agents MAY impose implementation-specific limits on otherwise unconstrained inputs, e.g., to prevent denial of service attacks, to guard against running out of memory, or to work around platform-specific limitations. When an input exceeds implementation-specific limit, the user agent MUST throw, or, in the context of a promise, reject with, a {{TypeError}} optionally informing the developer of how a particular input exceeded an implementation-specific limit.