The Payment Request API [[!PAYMENT-REQUEST-API]] provides a standard way to initiate payment requests from Web pages and applications. User agents implementing that API prompt the user to select a way to handle the payment request, after which the user agent returns a payment response to the originating site. This specification adds payment apps to that user experience. It defines how users register payment apps with user agents, how user agents support the display of information about payment options the user can select to handle the payment request, how the user selects a payment app, and how communication takes place between user agents and payment apps to fulfill the requirements of the underlying Payment Request API.

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

The Web Payments Working Group seeks to streamline payments on the Web to help reduce payment "abandonment" and make it easier to use new payment methods on the Web. It has published the Payment Request API [[!PAYMENT-REQUEST-API]] as a standard way to initiate payment requests from Web pages and applications. This specification adds payment apps to that user experience. A payment app is software that enables the user to fulfill a payment request using the user's preferred payment method.

This specification defines:

Payment apps may be implemented in a variety of ways: as Web applications, native operating system applications, user agent extensions, built-in user agent components, interface-less Web services, or a combination. This specification does not cover every aspect of communication on every platform.

The Web Payments Working Group has used the term "mediator" to refer to the software (here, the user agent) that carries out the activities defined in this specification (matching, information display, etc.).

This specification defines one class of products:

Conforming user agent

A user agent MUST behave as described in this specification in order to be considered conformant. In this specification, user agent means a Web browser or other interactive user agent as defined in [[!HTML5]].

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.

A conforming Payment App API user agent MUST also be a conforming implementation of the IDL fragments of this specification, as described in the “Web IDL” specification. [[!WEBIDL]]

Dependencies

This specification relies on several other underlying specifications.

Payment Request API
The terms PaymentRequest, PaymentResponse, and user accepts the payment request algorithm are defined by the Payment Request API specification [[!PAYMENT-REQUEST-API]].
HTML5
The terms global object,origin, queue a task, browsing context, top-level browsing context, structured clone, event handler, event handler event type, trusted event, and current settings object are defined by [[!HTML5]].
ECMA-262 6th Edition, The ECMAScript 2015 Language Specification
The term Promise is defined by [[!ECMA-262-2015]].
DOM4

DOMException and the following DOMException types from [[!DOM4]] are used:

Type Message (optional)
AbortError The operation was aborted
InvalidStateError The object is in an invalid state
SecurityError The operation is only supported in a secure context
OperationError The operation failed for an operation-specific reason.
WebIDL

The following DOMException types from [[!WEBIDL]] are used:

Type Message (optional)
NotAllowedError The request is not allowed by the user agent or the platform in the current context.
Secure Contexts
The terms secure context is defined by the Secure Contexts specification [[!POWERFUL-FEATURES]].
URL
The URL concept and URL parser are defined in [[!WHATWG-URL]].
Fetch
The terms Fetch, Request, Request Body, Request Method, Header List, Response, Context and Network Error are defined in [[!FETCH]].
Service Workers
The terms service worker service worker registration, active worker, installing worker, waiting worker, handle functional event, extend lifetime promises, and scope URL are defined in [[SERVICE-WORKERS]].

Payment App Model and Design Considerations

This section (which may be temporary) intends to help build shared understanding of the capabilities and limitations of the specified model.

General Considerations

Decoupling and Trust

Registration and Unregistration

Payment App Identification

Payment App Matching

User Experience

Payment App Invocation and Response

Network Considerations

Definitions

Updates needed for payment method option definition.

Payment App Implementation Technology

user agent-based payment app
a payment app that runs in a user agent. User agent-based payment apps may elect to display a user interface, or to operate without any user interaction. This decision is made at runtime, and may vary based on criteria of the app's choosing (such as how long it has been since the user last authenticated themselves).
native payment app
a payment app built with the operating system default technology stack that uses non-Web technologies.
ignored payment app
Need a definition for ignored payment app
payment app identifier
A unique identifier for a payment app (e.g., from a payment method manifest file). This specification defines these identifiers as to be service worker scope URLs. As such, they are not expected to be dereferenced.
payment app window
A service worker WindowClient used by user agent-based payment apps to interact with the user when doing so is necessary to complete the payment transaction.

The Web Payments Working Group intends for this specification to apply to any payment app that may be invoked by the user agent, whatever technologies have been used to implement the payment app.

Payment App Registration States

registered payment app
a payment app that is "known" to the user agent for the purposes of the interactions described in this document.
This specification defines a registration mechanism. Other registration mechanisms might co-exist with this one (e.g., on some platforms there may be a way to register a payment app directly with the operating system).
unregistered payment app
a payment app that is not known to the user agent, either because it has never been registered, or because it has been unregistered.
enabled payment app
A registered payment app with at least one enabled payment method.

Payment App Selection States

matching payment app
An enabled payment app that:
recommended payment app
a payment app suggested by the payee that may be used to handle a specific payment request.

The Working Group has not yet agreed that the system should support recommended payment apps. Inclusion might involve small changes to payment request API. The group has also discussed the idea of user agent-recommended payment apps, for example, when the user agent is aware of an app for a proprietary payment method.

displayed payment app
A matching payment app or recommended payment app with at least one selectable payment option (i.e. presented by the user agent for user selection).
selected payment app
the payment app whose option has been selected by the user to make a payment, but not yet invoked.
invoked payment app
the selected payment app that the user agent has invoked (executed) and passed payment app input data.

Payment Options

We need a clearer introduction to the concept of a payment option, and how it relates to payment apps.

available payment option
a payment option from a registered payment app available for selection, corresponding to at least one enabled payment method.
matching payment option
an available payment option that has at least one enabled payment method accepted by the payee, or a recommended payment app with at least one supported payment method accepted by the payee.
selectable payment option
a matching payment option for which information has been displayed by the user agent to facilitate user selection, but that has not yet been selected. Note: Information about selectable payment apps may be displayed in a variety of modalities, including visual and aural.
selected payment option
the payment option selected by the user to handle the payment request.

Payment Method Support

supported payment method
a payment method that a payment app has been designed to support. This payment method may or may not currently be enabled. A payment app MAY support more than one payment method.
unsupported payment method
a payment method that cannot be enabled by a payment app. Updates to a payment app may cause an unsupported payment method to become supported, or vice-versa.
enabled payment method
a supported payment method that a registered payment app is able to handle. The payment app must have at least one available payment option with the corresponding enabled payment method.

The difference between supported and enabled payment methods is one of design-time vs runtime consideration. A payment app supports all the payment methods it was designed to support; however at runtime only a subset may be enabled due to configuration or other runtime requirements that may not have been met for all supported payment methods.

Payment App Invocation and Response Data

payment app request data
data provided to the invoked payment app by the user agent to initiate a payment request. This data is a subset of data input to the Payment Request API.

The data passed between the user agent and the payment app will be serialized as JSON data.

payment app response data
data returned by an invoked payment app to the user agent, typically after payment authorization or other action taken through the payment app. This data, which will vary according to payment method, is then returned to the payee via the Payment Request API as part of the payment response.

Overview of Service-Worker-Based Approach

In this specification we use service workers to connect user agents with user agent-based payment apps. We do so for several reasons:

The use of service workers restricts user agent-based payment apps so that they must run only in secure contexts. The introduction of this restriction is deliberate, due to the sensitivity of the role that payment apps play.

Here is the flow envisioned by this document:

  1. Through registration, a service worker is created and associated with payment methods (and associated metadata).
  2. When the payment request API is called, the user agent displays a list of registered service workers associated with matching payment methods (along with any other payment apps that may be available to the user agent).
  3. When the user selects a user agent-based payment app, the corresponding service worker is activated, and it receives a PaymentRequestEvent.
  4. Once active, the payment app performs whatever steps are necessary to authenticate the user, process the payment, and return payment information to the payee. If interaction with the user is necessary, the payment app can open a payment app window for that purpose.
  5. Finally, once the payment app is finished with its processing, it resolves a Promise passed to it in the event. This causes the Promise<PaymentResponse> returned from PaymentRequest.show() to resolve.

Payment App Registration

Extensions to the ServiceWorkerRegistration interface

The Service Worker specification defines a ServiceWorkerRegistration interface [[!SERVICE-WORKERS]], which this specification extends.

        partial interface ServiceWorkerRegistration {
          readonly attribute PaymentAppManager paymentAppManager;
        };
      

PaymentAppManager interface

      interface PaymentAppManager {
        Promise<void> setManifest(PaymentAppManifest manifest);
        Promise<PaymentAppManifest> getManifest ();
      };
      

PaymentAppManager.setManifest()

The setManifest method is used to enable a service worker to process payment requests, and to set the properties associated with the payment app.

The following algorithm provides an extension point: other specifications that add new members to the manifest are encouraged to hook themselves into this specification at this point in the algorithm.

The setManifest method, when invoked, MUST run the following steps or their equivalent:

  1. Let promise be a new Promise.
  2. Return promise and asynchronously perform the remaining steps.
  3. If the current settings object is not a secure context, reject promise with a DOMException whose name is "SecurityError" and terminate these steps.
  4. Extension point: if the user agent has custom steps to invoke when registering payment apps, execute these steps, possibly rejecting promise with a DOMException whose name is "OperationError" and terminate these steps.
  5. Let manifest be the value of the manifest argument.
  6. Let registration be the PaymentAppManager's associated service worker registration.
  7. If registration has no active worker, run the following substeps:
    1. If registration has no installing worker and no waiting worker, reject promise with a DOMException whose name is "InvalidStateError" and terminate these steps.
    2. Wait for the installing worker or waiting worker of registration to become its active worker.
    3. If registration fails to activate either worker, reject promise with a DOMException whose name is "InvalidStateError" and terminate these steps.
    4. Once registration has an active worker, proceed with the steps below.
  8. Let paymentMethods be a list of URLs from manifest section on supported payment methods. Ensure that the payment methods either allow any payment app to use their name indiscriminately or specifically allow this payment app. Otherwise, reject with a DOMException whose name is "NotAllowedError" and terminate these steps.
  9. Ask the user whether they allow the payment app to be registered to handle the indicated payment methods (unless a prearranged trust relationship applies or the user has already granted or denied permission explicitly for this payment app).
  10. If permission is not granted, reject promise with a DOMException whose name is "NotAllowedError" and terminate these steps.
  11. Register the payment app with the user agent for future use, associating manifest's label and icon set with the payment app for user reference.
  12. For each PaymentAppOption present in the options field of the manifest:
    1. Add a new payment option to the payment app's registration, associating it with the PaymentAppOption label and icon fields.
    2. For each payment method indicated in the PaymentAppOption's enabledMethods field, associate the payment option and the payment app with the payment method for future use.
  13. Resolve promise with undefined.

PaymentAppManager.getManifest()

The getManifest method is used to retrieve the properties associated with a registered payment app.

The getManifest method, when invoked, MUST run the following steps or their equivalent:

  1. Let promise be a new Promise.
  2. Return promise and asynchronously perform the remaining steps.
  3. If the current settings object is not a secure context, reject promise with a DOMException whose name is "SecurityError" and terminate these steps.
  4. If there is no PaymentAppManifest associated with the Service Worker, reject promise with a DOMException whose name is "AbortError" and terminate these steps.
  5. Retrieve the PaymentAppManifest associated with the Service Worker.
  6. Let manifest be the retrieved PaymentAppManifest.
  7. Resolve promise with manifest.

PaymentAppManifest interface

      dictionary PaymentAppManifest {
        DOMString label;
        DOMString? icon;
        sequence<PaymentAppOption> options;
      };
      
label member
The label member is a string that represents the label for this payment app as it is usually displayed to the user.
icon member
The iconmember defines an icon for this payment app as it is usually displayed to the user.
Need to define how an icon would be represented in this data. Url? Data URL? Size options? Web App Manifest may be used for inspiration.
options member
The options member lists the payment method identifiers of the payment methods enabled by this option.

Options are an extra layer of abstraction, because they allow flattening of payment apps. The flattening may result in unique UX challenges. For example, if two payment apps both have "Visa ending in ***4756" payment option, then users may be confused when they see two such labels in UI. One solution is to prepend the payment app name, e.g., "ExampleApp Visa ending in ***4756". However, when only one app is installed, the text "ExampleApp" is redundant.

It may be simpler for implementers to remove payment options from this spec. A medium level of complexity is to specify payment options, but give user agents choice of whether payment options are supported.

PaymentAppOption dictionary

      dictionary PaymentAppOption {
        DOMString label;
        DOMString? icon;
        DOMString id;
        sequence<DOMString> enabledMethods;
      };
      
label member
The label member is a string that represents the label for this option as it is usually displayed to the user when selecting a payment app.
icon member
Need to define how an icon would be represented in this data. Url? Data URL? Size options? Web App Manifest may be used for inspiration.
id member
The id member is an identifier, unique within the PaymentAppManifest, that will be passed to the payment app to indicate which PaymentAppOption the user selected.
enabledMethods member
The enabledMethods member lists the payment method identifiers of the payment methods enabled by this option.

Payment App Manifest Location

Aside from ServiceWorker registration, it's useful for user agents to download the payment app manifest from a well defined location. This allows for merchants to recommend payment apps via the URL of the payment app.

How to map payment app URL to the location of the manifest file? For example, how to map https://bobpay.com to https://bobpay.com/payment-manifest.json?

Registration Example

The following example shows how to register a user agent-based payment app:

         navigator.serviceWorker.register('/exampleapp.js')
         .then(function(registration) {
           return registration.paymentAppManager.setManifest({
             label: "ExampleApp",
             icon: "...",
             options: [
               {
                 label: "Visa ending ****4756",
                 icon: "...",
                 id: "dc2de27a-ca5e-4fbd-883e-b6ded6c69d4f",
                 enabledMethods: ["basic-card#visa"]
               },
               {
                 label: "My Bob Pay Account: john@example.com",
                 icon: "...",
                 id: "c8126178-3bba-4d09-8f00-0771bcfd3b11",
                 enabledMethods: ["https://bobpay.com/"]
               },
               {
                 label: "Add new credit/debit card to ExampleApp",
                 icon: "...",
                 id: "new-card",
                 enabledMethods: [
                   "basic-card#visa",
                   "basic-card#mastercard",
                   "basic-card#amex"
               }
             ]
           });
         }).then(function() {
           console.log("Installed payment app from /paymentapp.js"); // Success!
         }).catch(function(error) {
           console.log(error);
         });
     

The Editors will update the payment method identifier syntax in this and other examples to align with [[!METHOD-IDENTIFIERS]], once a final format has been agreed upon.

Native App Registration

Information required for payment apps should be present in the payment app manifest under an extension point. For example, information for Android native payment apps may live under "android" section of the app manifest. This specification does not define the contents of native app descriptions. This is defined elsewhere.

What else, if anything, should we say about registering native payment apps?

Native payment apps on some platforms (e.g., on Android) can claim ownership of their origins. To verify origin ownership, user agents need to perform extra steps that are not defined in this specification.

Payment App Matching

We anticipate that [[!METHOD-IDENTIFIERS]] will define the PMI matching algorithm. This specification will explain how to invoke that algorithm using data available from the Payment Request API input and payment method information aggregated from:

Payment App Selection

Selectable App Information Display

After matching the user agent will have a list of payment options that the user can select to handle the payment request. How will these be ordered when they are displayed to the user, where do recommended apps fit in to the order and how do we treat apps that are both registered and recommended?

What information is needed by the user agent to display selectable apps/options? This needs to be captured during registration.

The output of the payment method matching algorithm will be a list of matching payment options from registered payment apps and a list of recommended payment apps. The user agent will present this list of options to the user so they can select how they want to handle the payment request.

We have identified a number of user experiences that we would like to harmonize. Just a few examples here:

  1. User has no registered payment apps.
  2. User has apps with supported but no enabled payment methods.
  3. User has apps with supported and enabled payment methods.
  4. Merchant wishes to recommend a payment app to the user.
  5. User agent wishes to recommend a payment app that supports a payment method for which the user does not currently have a supporting payment app.

Examples of Ordering of Selectable Payment Apps

The following are examples of user agent display behavior.

  • Display a user-configured preferred payment app at the top of a list of matching payment apps.
  • Display a payee-recommended app that the user has also registered at the top of a list.
  • Enable the user to set a default payment app for a Web site (e.g., the payment app distributed by that retailer), and display that payment at the top of a list for that site.
  • Based on how frequently the user has selected a payment app, the user agent can automatically display that one closer to the top of a list.
  • If the user initiates a purchase on a site with the same origin as that associated with a payment app, display that app at the top of a list.

Selection by the User

Payment App Invocation, Display and Response

Once the user has selected a payment option, the user agent is responsible for preparing payment app request data, invoking the payment app, providing the request data to the payment app, and returning the payment app response through the Payment Request API.

Payment App Request Data

The payment app request data is conveyed using the following dictionary:
      dictionary PaymentAppRequestData {
        DOMString origin;
        sequence<PaymentMethodData> methodData;
        PaymentItem total;
        sequence<PaymentDetailsModifier> modifiers;
        DOMString optionId;
      };
    
origin attribute
This attribute a string that indicates the origin of the payee web page. It MUST be formatted according to the "Unicode Serialization of an Origin" algorithm defined in section 6.1 of [[!RFC6454]].
methodData attribute
This attribute contains PaymentMethodData dictionaries containing the payment method identifiers for the payment methods that the web site accepts and any associated payment method specific data. It is populated from the PaymentRequest using the Method Data Population Algorithm defined below.
total attribute
This attribute indicates the total amount being requested for payment. It is initialized with a structured clone of the total field of the PaymentDetails provided when the corresponding PaymentRequest object was instantiated.
modifiers attribute
This sequence of PaymentDetailsModifier 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 PaymentRequest using the Modifiers Population Algorithm defined below.
optionId attribute
This attribute indicates which PaymentAppOption the user selected. It corresponds to the id field provided during payment app registration.

Method Data Population Algorithm

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

  1. Set registeredMethods to an empty set.
  2. For each PaymentAppOption option in the payment app's PaymentAppManifest, add all entries in option.enabledMethods to registeredMethods.
  3. Create a new empty Sequence.
  4. Set dataList to the newly created Sequence.
  5. For each item in PaymentRequest@[[\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.supportedMethods and registeredMethods.
    3. If commonMethods is empty, skip the remaining substeps and move on to the next item (if any).
    4. Create a new PaymentMethodData object.
    5. Set outData to the newly created PaymentMethodData.
    6. Set outData.supportedMethods to a list containing the members of commonMethods.
    7. Set outData.data to a structured clone of inData.data.
    8. Append outData to dataList.
  6. Set methodData to dataList.

Modifiers Population Algorithm

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

  1. Set registeredMethods to an empty set.
  2. For each PaymentAppOption option in the payment app's PaymentAppManifest, add all entries in option.enabledMethods to registeredMethods.
  3. Create a new empty Sequence.
  4. Set modifierList to the newly created Sequence.
  5. For each item in PaymentRequest@[[\paymentDetails]].modifiers 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.supportedMethods and registeredMethods.
    3. If commonMethods is empty, skip the remaining substeps and move on to the next item (if any).
    4. Create a new PaymentDetailsModifier object.
    5. Set outModifier to the newly created PaymentDetailsModifier.
    6. Set outModifier.supportedMethods to a list containing the members of commonMethods.
    7. Set outModifier.total to a structured clone of inModifier.total.
    8. Set outModifier.additionalDisplayItems to a structured clone of inModifier.additionalDisplayItems.
    9. Append outModifier to modifierList.
  6. Set modifiers to modifierList.

Payment App Invocation

Payment apps are invoked when a payee requests a payment by calling PaymentRequest.show() and the user selects a payment app (or has one implicitly selected by previously established user preferences). If the user selects a user agent-based payment app to service the request, the service worker corresponding to that application receives an event with the PaymentAppRequestData containing information about the payment being requested. The event also contains a function that allows the payment app to provide a payment response back to the payee. This process is formally described in the following sections.

Extension to ServiceWorkerGlobalScope

The Service Worker specification defines a ServiceWorkerGlobalScope interface [[!SERVICE-WORKERS]], which this specification extends.

        partial interface ServiceWorkerGlobalScope {
          attribute EventHandler onpaymentrequest;
        };
      
onpaymentrequest attribute
The onpaymentrequest attribute is an event handler whose corresponding event handler event type is paymentrequest.

The PaymentRequestEvent interface represents a received payment request.

The paymentrequest Event

The PaymentRequestEvent represents a received payment request.

      [Exposed=ServiceWorker]
      interface PaymentRequestEvent : ExtendableEvent {
        readonly attribute PaymentAppRequestData data;
        void respondWith((Promise<PaymentResponse>
        or PaymentResponse) r);
      };
      
data attribute
This attribute contains the payment app request data associated with this payment request.
respondWith method
This method is used by the payment app to provide a PaymentResponse when the payment successfully completes.

Upon receiving a payment request by way of PaymentRequest.show() and subsequent user selection of a user agent-based payment app, the user agent MUST run the following steps or their equivalent:

  1. Let registration be the service worker registration corresponding to the user agent-based payment app selected by the user.
  2. If registration is not found, reject the Promise that was created by PaymentRequest.show() with a DOMException whose value "InvalidStateError" and terminate these steps.
  3. Invoke the Handle Functional Event algorithm with a service worker registration of registration and callbackSteps set to the following steps:
    1. Set global to the global object that was provided as an argument.
    2. Create a trusted event, e, that uses the PaymentRequestEvent interface, with the event type paymentrequest, which does not bubble, cannot be canceled, and has no default action.
    3. Set the data attribute of e to a new PaymentAppRequestData instance, populated as described in .
    4. Dispatch e to global.
    5. Wait for all of the promises in the extend lifetime promises of e to resolve.
    6. If the payment app has not provided a payment app response as described in , reject the Promise that was created by PaymentRequest.show() with a DOMException whose value "OperationError".

Payment App Display

Payment Apps that require user input can open a payment window using the clients.openWindow() method defined in [[!SERVICE-WORKERS]]. Absent user preferences that override such behavior, user interaction is required during payment requests, in the form of payment app selection. As a consequence, the user agent MUST treat a paymentrequest event as user interaction for the purposes of determining whether the service worker is allowed to open a window.

The actual rendering of a payment app window is a user agent implementation detail. While opening an entirely new window is possible, it is more likely that the contents will be rendered in a way that makes it more obvious that the interactions pertain to the payment transaction. This is an area for potential user agent experimentation and differentiation. The opening of a payment app window versus other types of windows can be distinguished based on the event type the user agent is using to grant permission to open a window.

The remainder of this section is a non-normative explanation of how the service worker WindowClient class can be used to interact with users.

Upon calling clients.openWindow(), the payment app receives a Promise which resolves to a WindowClient. For the purposes of this discussion, we will refer to this WindowClient as client. The payment app can use the client.postMessage() method to send messages to the payment app window.

When a payment app window receives the message event from the payment app, this event will contain a source attribute which indicates the payment app's service worker. The payment app window can then call source.postMessage() to send a response to the payment app. Once the payment app window has complete its interaction with the user, it closes the window and uses this postMessage() call to return information to the payment app.

In order for this approach to work, we have to treat a paymentrequest as permission to open a popup, which is a formal property relied up on by [[!SERVICE-WORKERS]]. We need to be careful that this does not become an end-run around exiting pop-up protections.

Do we want to define a new FrameType for payment app windows? This requires input from someone with detailed knowledge of service worker design.

Payment App Response

The user agent receives a successful response from the payment app through resolution of the Promise provided to the respondWith function of the corresponding PaymentRequestEvent dictionary. The application is expected to resolve the Promise with a PaymentResponse dictionary instance containing the payment response information.

When this Promise is resolved, the user agent MUST run the user accepts the payment request algorithm as defined in [[!PAYMENT-REQUEST-API]], replacing steps 6 and 7 with these steps or their equivalent:

  1. Set appResponse to the PaymentResponse used to resolve the PaymentRequestEvent.respondWith Promise.
  2. If appResponse.methodName is not present or not set to one of the values from PaymentRequestEvent.data, reject the Promise created by PaymentRequest.show() with DOMException whose value "InvalidStateError" and terminate these steps.
  3. Create a structured clone of appResponse.methodName and assign it to response.methodName.
  4. If appResponse.details is not present, reject the Promise created by PaymentRequest.show() with a DOMException whose value is "InvalidStateError" and terminate these steps.
  5. Create a structured clone of appResponse.details and assign it to response.details.

The user agent receives a failure response from the payment app through rejection of the Promise. The user agent MUST use the rejection reason to reject the Promise that was created by PaymentRequest.show().

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

      paymentRequestEvent.respondWith(new Promise(function(accept,reject) {
        /* ... processing may occur here ... */
        accept({
          methodName: "basic-card#visa",
          details: {
            card_number :  "1232343451234",
            expiry_month : "12",
            expiry_year :  "2020",
            cvv :          "123"
           }
        });
      });
    

Some payment methods might require a back channel to guarantee payment response delivery (especially push payment methods). Should it be part of the generic portion of paymentRequest and paymentResponse? [Ed Note: the "complete()" attribute of the "PaymentResponse" interface would serve this purpose quite cleanly.]

Example using HTTP POST

This example codes shows how to use this API via a scheme in which a POST is sent to a URL with the payment request as a body. The response is allowed to be either application/json (which is inferred to contain a payment response), or text/html (which contains content to be rendered to the user).

      var contentType;
      var paymentPromise;
      /* Handle payment request from a payee */
      self.addEventListener('paymentrequest', function(e) {
        paymentPromise = new Promise(function(accept, reject) {
          fetch("https://www.example.com/bobpay/process",
            { method: "POST",  body: JSON.stringify(e.data) })
          .then(function(response) {
            contentType = response.headers.get("content-type");
            if (!contentType) {
              throw new Error("No content type header");
            }
            return response.text();
          }).then(function(body) {
            if(contentType.indexOf("application/json") !== -1) {
              /* Respond to the payment request with the received body */
              accept(JSON.parse(body));
            } else if (contentType.indexOf("text/html") !== -1) { {
              /* Open a new payment window and populate it with the
                 document returned from the response */
              var url = "data:text/html;base64," + btoa(body);
              clients.openWindow(url).then(function(windowClient) {
                windowClient.postMessage(e.data);
              });
            } else {
              throw new Error("Unexpected value in content type header");
            }
          }).catch(function(err) {
            reject(err);
          });
        e.respondWith(paymentPromise);
      });

      /* Handle payment response from a payment app window */
      self.addEventListener('message', function(e) {
        if (e.data.hasOwnProperty('name')) {
          paymentPromise.reject(e.data);
        } else {
          paymentPromise.resolve(e.data);
        }
      });
    

Using the simple scheme described above, a trivial HTML page that is loaded into the payment app window to implement the basic card scheme might look like the following:

<html> <body> <form id="form">
<table>
  <tr><th>Card Number:</th><td><input name="card_number"></td></tr>
  <tr><th>Expiration Month:</th><td><input name="expiry_month"></td></tr>
  <tr><th>Expiration Year:</th><td><input name="expiry_year"></td></tr>
  <tr><th>CVV:</th><td><input name="cvv"></td></tr>
  <tr><th></th><td><input type="submit" value="Pay"></td></tr>
</table>
</form>

<script>
window.addEventListener("message", function(e) {
  var form = document.getElementById("form");
  /* Note: message sent from payment app is available in e.data */
  form.onsubmit = function() {
    var details = {};
    ["card_number","expiry_month","expiry_year","cvv"].forEach(function(field) {
      details[field] = form.elements[field].value;
    });
    e.source.postMessage({
      methodName: "basic-card#visa",
      details: details
    });
    window.close();
  }
});
</script> </body> </html>
    

Security and Privacy Considerations

Design Considerations

Secure Communications

Payment App Authenticity

Data Validation

Private Browsing Mode