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 defines capabilities that enable Web applications to handle payment requests.

We have changed the title of this specification but left the identifier as-is. We are likely to want to assign it a new URL prior to FPWD.

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 "shopping cart abandonment" and make it easier to deploy 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 E-Commerce Web sites and applications.

A payment app is a Web application that manages payment requests on behalf of the user by supporting one or more payment methods. To enable a Web application to handle payment requests, this specification defines:

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

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 Handler 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
NotFoundError The object can not be found here.
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]].

Overview of Handling Payment Requests

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 payment handler from that origin. The user agent is not required to prompt the user to grant permission to the origin for each new supported payment method. A origin's capabilities may thus evolve without requiring additional user consent.
  2. To handle payments, an origin has at least one and possibly many service worker registrations. A service worker registration has zero or one payment handler.
  3. Registration associates with each payment handler:
    • A list of supported payment methods.
    • [Optionally] the conditions under which the handler supports a given payment method; these "capabilities" play a role in matching computations.
    • Information for organizing the display and grouping of Instruments supported by the payment handler.
  4. When the merchant calls Payment Request API (e.g., when the user pushes a button on a checkout page), the user agent computes a list of matching payment handlers, comparing the payment methods accepted by the user with those supported by registered payment handlers. For payment methods that support additional filtering, merchant and payment handler capabilities are compared as part of determining whether there is a match.
  5. The user agent displays matching payment handlers, displaying and grouping Instruments according to information (labels and icons) provided at registration or otherwise available from the Web app.
  6. When the user selects an Instrument, the user agent fires the paymentrequest event in the service worker whose registration included the payment handler that provided that Instrument. The paymentrequest event includes some information from the PaymentRequest (defined in [[!PAYMENT-REQUEST-API]]) as well as additional information (e.g., origin and selected Instrument).
  7. Once activated, the payment handler 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 handler can open a window for that purpose.
  8. The user agent receives a response asynchronously once the user has authorized payment. The response becomes the PaymentResponse (of [[!PAYMENT-REQUEST-API]]).

This specification does not address activities outside this flow, including:

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

Payment Handler 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 PaymentManager paymentManager;
        };
      

PaymentManager interface

      interface PaymentManager {
        attribute PaymentInstruments instruments;
        attribute PaymentWallets wallets;
      };
      
instruments attribute
This attribute allows manipulation of payment instruments associated with a payment handler. To be presented to the user as part of the payment request flow, payment handlers must have at least one registered payment Instrument, and that Instrument needs to match the payment methods and required capabilities specified by the payment request.
wallets attribute
This attribute allows payment handlers to group payment instruments together and provide a name and icon for such a group (e.g., to group together "business account" payment instruments separately from "personal account" payment instruments). The use of this grouping mechanism by payment handlers is completely optional. If payment handlers use this grouping mechanism, then matching payment instruments that do not appear in any groups should still be presented to users by the browser for selection.

PaymentInstruments interface

      interface PaymentInstruments {
          Promise<boolean>              delete(DOMString instrumentKey);
          Promise<PaymentInstrument> get(DOMString instrumentKey);
          Promise<sequence<DOMString>>  keys();
          Promise<boolean>              has(DOMString instrumentKey);
          Promise<void>                 set(DOMString instrumentKey,
                                              PaymentInstrument details);
      };
      

The PaymentInstruments interface represents a collection of payment instruments, each uniquely identified by an instrumentKey. The instrumentKey identifier will be passed to the payment handler to indicate the PaymentInstrument selected by the user.

delete method
When called, this method executes the following steps:
  1. Let p be a new promise.
  2. Run the following steps in parallel:
    1. If the collection contains a PaymentInstrument with a matching instrumentKey, remove it from the collection and resolve p with true.
    2. Otherwise, resolve p with false.
  3. Return p
get method
When called, this method executes the following steps:
  1. Let p be a new promise.
  2. Run the following steps in parallel:
    1. If the collection contains a PaymentInstrument with a matching instrumentKey, resolve p with that PaymentInstrument.
    2. Otherwise, reject p with a DOMException whose value is "NotFoundError".
  3. Return p
keys method
When called, this method executes the following steps:
  1. Let p be a new promise.
  2. Run the following steps in parallel:
    1. Resolve p with a sequence that contains all the instrumentKeys for the PaymentInstruments contained in the collection.
  3. Return p
has method
When called, this method executes the following steps:
  1. Let p be a new promise.
  2. Run the following steps in parallel:
    1. If the collection contains a PaymentInstrument with a matching instrumentKey, resolve p with true.
    2. Otherwise, resolve p with false.
  3. Return p
set method
When called, this method executes the following steps:
  1. Let p be a new promise.
  2. Run the following steps in parallel:
    1. If the collection contains a PaymentInstrument with a matching instrumentKey, replace it with the PaymentInstrument in details.
    2. Otherwise, PaymentInstrument insert the PaymentInstrument in details as a new member of the collection and associate it with the key instrumentKey.
    3. Resolve p.
  3. Return p
        return paymentManager.instruments.keys().then((keys) => {
          Promise.all(keys.map(paymentManager.instruments.delete(key)))
        });
      

PaymentInstrument dictionary

      dictionary PaymentInstrument {
        required DOMString name;
        sequence<ImageObjects> icons;
        sequence<DOMString> enabledMethods;
        object capabilities;
      };
      
name member
The name member is a string that represents the label for this payment Instrument as it is usually displayed to the user.
icons member
The icons member is an array of image objects that can serve as iconic representations of the payment Instrument when presented to the user for selection.
enabledMethods member
The enabledMethods member lists the payment method identifiers of the payment methods enabled by this Instrument.
capabilities member
The capabilities member contains a list of payment-method-specific capabilities that this payment handler is capable of supporting for this Instrument. For example, for the basic-card payment method, this object will consist of an object with two fields: one for supportedNetworks, and another for supportedTypes.

PaymentWallets interface

      interface PaymentWallets {
          Promise<boolean>              delete(DOMString walletKey);
          Promise<WalletDetails> get(DOMString walletKey);
          Promise<sequence<DOMString>>  keys();
          Promise<boolean>              has(DOMString walletKey);
          Promise<void>                 set(DOMString walletKey,
                                              WalletDetails details);
      };
      

Where it appears, The walletKey parameter is a unique identifier for the wallet.

delete method
When called, this method executes the following steps:
  1. Let p be a new promise.
  2. Run the following steps in parallel:
    1. If the collection contains a WalletDetails with a matching walletKey, remove it from the collection and resolve p with true.
    2. Otherwise, resolve p with false.
  3. Return p
get method
When called, this method executes the following steps:
  1. Let p be a new promise.
  2. Run the following steps in parallel:
    1. If the collection contains a WalletDetails with a matching walletKey, resolve p with that WalletDetails.
    2. Otherwise, reject p with a DOMException whose value is "NotFoundError".
  3. Return p
keys method
When called, this method executes the following steps:
  1. Let p be a new promise.
  2. Run the following steps in parallel:
    1. Resolve p with a sequence that contains all the walletKeys for the WalletDetailss contained in the collection.
  3. Return p
has method
When called, this method executes the following steps:
  1. Let p be a new promise.
  2. Run the following steps in parallel:
    1. If the collection contains a WalletDetails with a matching walletKey, resolve p with true.
    2. Otherwise, resolve p with false.
  3. Return p
set method
When called, this method executes the following steps:
  1. Let p be a new promise.
  2. Run the following steps in parallel:
    1. If the collection contains a WalletDetails with a matching walletKey, replace it with the WalletDetails in details.
    2. Otherwise, WalletDetails insert the WalletDetails in details as a new member of the collection and associate it with the key walletKey.
    3. Resolve p.
  3. Return p

WalletDetails dictionary

      dictionary WalletDetails {
          required DOMString name;
          sequence<ImageObject> icons;
          required sequence<DOMString> instrumentKeys;
      };
      
name member
The name member is a string that represents the label for this wallet as it is usually displayed to the user.
icons member
The icons member is an array of image objects that can serve as iconic representations of the wallet when presented to the user for selection.
instrumentKeys member
The instrumentKeys member is a list of instrumentKeys from PaymentManager.instruments, indicating which PaymentInstrument objects are associated with this Wallet, and should be displayed as being "contained in" the wallet. While it is not generally good practice, there is no restriction that prevents a PaymentInstrument from appearing in more than one Wallet.

Registration Example

The following example shows how to register a payment handler:

Issue 94. The means for code requesting permission to handle payments is not yet defined. The code below is based on one potential model (a requestPermission() method on the PaymentManager), but this is likely to change.

        window.addEventListerner("DOMContentLoaded", async() => {
          const { registration } =
            await navigator.serviceWorker.register('/sw.js');
          if (!paymentManager) {
            return; // not supported, so bail out.
          }
          const state =
            await navigator.permissions.query({ name: "paymenthandler" });

          switch (state) {
            case "denied":
              return;
            case "prompt":
              // Note -- it's not clear how this should work yet; see Issue 94.
              const result = await registration.paymentManager.requestPermission();
              if (result === "denied") {
                return;
              }
              break;
          }
          // Excellent, we got it! Let's now set up the user's cards.
          await addInstruments(registration);
        }, { once: true });

        function addInstruments(registration) {
          const instrumentPromises = [
            registration.paymentManager.instruments.set(
              "dc2de27a-ca5e-4fbd-883e-b6ded6c69d4f",
              {
                name: "Visa ending ****4756",
                enabledMethods: ["basic-card"],
                capabilities: {
                  supportedNetworks: ['visa'],
                  supportedTypes: ['credit']
                }
              }),

            registration.paymentManager.instruments.set(
              "c8126178-3bba-4d09-8f00-0771bcfd3b11",
              {
                name: "My Bob Pay Account: john@example.com",
                enabledMethods: ["https://bobpay.com/"]
              }),

            registration.paymentManager.instruments.set(
              "new-card",
              {
                name: "Add new credit/debit card to ExampleApp",
                enabledMethods: ["basic-card"],
                capabilities: {
                  supportedNetworks:
                    ['visa','mastercard','amex','discover'],
                  supportedTypes: ['credit','debit','prepaid']
                }
              }),
            ];

            return Promise.all(instrumentPromises).then(() => {
              registration.paymentManager.wallets.set(
                "12a1b7e5-16c0-4c09-a312-9b191d08517b",
                {
                  name: "Acme Bank Personal Accounts",
                  icons: [
                           { src: "icon/lowres.webp",
                             sizes: "48x48",
                             type: "image/webp"
                           },
                           { src: "icon/lowres",
                             sizes: "48x48"
                           }
                         ],
                  instrumentKeys: [
                      "dc2de27a-ca5e-4fbd-883e-b6ded6c69d4f",
                      "c8126178-3bba-4d09-8f00-0771bcfd3b11",
                      "new-card"
                    ]
                });
             });
          };
     

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.

Origin and Instrument Display for Selection

After applying the matching algorithm defined in Payment Request API, the user agent displays a list of matching origins for the user to make a selection. This specification includes a limited number of display requirements; most user experience details are left to user agents.

Ordering of Payment Handlers

The following are examples of payment handler ordering:

Display of Instruments

The user agent MUST enable the user to select any displayed Instrument.

Issue 98. There has been pushback to always requiring display of instruments (e.g., on a mobile devices). User agents can incrementally show instruments. Or user agents can return an empty Instrument ID and it becomes the payment app's responsibility to display instruments to the user.

Grouping of Instruments

At times, the same origin may wish to group instruments with greater flexibility and granularity than merely "by origin." These use cases include:

A Wallet is a grouping of Instruments for display purposes.

To enable developers to build payment apps in a variety of ways, we decouple the registration (and subsequent display) of Instruments from how payment handlers respond to paymentrequest events. However, the user agent is responsible for communicating the user's selection in the event.

Selection of Instruments

Users agents may wish to enable the user to select individual displayed Instruments. The payment handler would receive information about the selected Instrument and could take action, potentially eliminating an extra click (first open the payment app then select the Instrument).

Issue 98. Should we require that, if displayed, individual Instruments must be selectable? Or should we allow flexibility that Instruments may be displayed, but selecting any one invokes all registered payment handlers? One idea that has been suggested: the user agent (e.g., on a mobile device) could first display the app-level icon/logo. Upon selection, the user agent could display the Instruments in a submenu.

Payment Handler Invocation, Display and Response

Once the user has selected an Instrument, the user agent fires a paymentrequest event with a Payment App Request, and uses the subsequent Payment App Response to create a PaymentReponse for [[!PAYMENT-REQUEST-API]].

PaymentAppRequest interface

The payment app request is conveyed using the following interface:
      interface PaymentAppRequest {
        readonly attribute DOMString origin;
        readonly attribute DOMString id;
        readonly attribute FrozenArray<PaymentMethodData> methodData;
        readonly attribute PaymentItem total;
        readonly attribute FrozenArray<PaymentDetailsModifier> modifiers;
        readonly attribute DOMString instrumentId;
      };
    
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]].
id attribute
When getting, the id attribute returns this the [[\details]].id from the PaymentRequest that corresponds to this PaymentAppRequest.
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.
displayItems
The sequence of line items optionally provided by the payee. It is initialized with a structured clone of the displayItems 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.
instrumentId attribute
This attribute indicates the PaymentInstrument selected by the user. It corresponds to the id field provided during 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 PaymentInstrument instrument in the payment handler's PaymentManager.instruments, add all entries in instrument.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 PaymentInstrument instrument in the payment handler's PaymentManager.instruments, add all entries in instrument.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.

Invocation

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 PaymentAppRequest appRequest;
        void respondWith(Promise<PaymentAppResponse>appResponse);
      };
      
appRequest attribute
This attribute contains the payment app request associated with this payment request.
respondWith method
This method is used by the payment handler to provide a PaymentAppResponse when the payment successfully completes.

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

  1. Let registration be the service worker registration corresponding to the payment handler 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 appRequest attribute of e to a new PaymentAppRequest 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 handler 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 Handler Windows

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

See issue 97 for discussion about opening window in a way that is consistent with payment flow and not confusing to the user. For example, there is consensus that in a desktop environment, a payment handler should not open a window in a new browser tab, as this is too dissociated from the checkout context.

User agents SHOULD display the origin of a running payment handler to the user.

PaymentAppResponse dictionary

The payment app response is conveyed using the following dictionary:
      dictionary PaymentAppResponse {
        DOMString methodName;
        object details;
      };
    
methodName attribute
The payment method identifier for the payment method that the user selected to fulfil the transaction.
details attribute
A JSON-serializable object that provides a payment method specific message used by the merchant to process the transaction and determine successful fund transfer.

The user agent receives a successful response from the payment handler 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 PaymentAppResponse instance containing the payment response. In case of user cancellation or error, the application may signal failure by rejecting the Promise.

If the Promise is rejected, the user agent MUST run the payment app failure algorithm. The exact details of this algorithm is left for user agent implementers to decide on. Acceptable behaviors include, but are not limited to:

  • Letting the user try again, with the same payment handler or with a different one.
  • Rejecting the Promise that was created by PaymentRequest.show().

If this Promise is successfully 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 PaymentAppResponse instance used to resolve the PaymentRequestEvent.respondWith Promise.
  2. If appResponse.methodName is not present or not set to one of the values from PaymentRequestEvent.appRequest, run the payment app failure algorithm 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, run the payment app failure algorithm and terminate these steps.
  5. Create a structured clone of appResponse.details and assign it to response.details.

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",
          details: {
            cardHolderName:   "John Smith",
            cardNumber:       "1232343451234",
            expiryMonth:      "12",
            expiryYear :      "2020",
            cardSecurityCode: "123"
           }
        });
      });
    

[[!PAYMENT-REQUEST-API]] defines a paymentRequestID that parties in the ecosystem (including payment app providers and payees) may use for reconciliation after network or other failures.

Example of handling the paymentrequest event

This example shows how to write a service worker that listens to the paymentrequest event. When a payment request event is received, the service worker opens a window in order to interact with the user.

Per issue 97, we expect not to use clients.OpenWindow() and instead await a proposal for a new openClientWindow method on the PaymentRequestEvent. We will need to update these examples.

      self.addEventListener('paymentrequest', function(e) {
        e.respondWith(new Promise(function(resolve, reject) {
          self.addEventListener('message', listener = function(e) {
            self.removeEventListener('message', listener);
            if (e.data.hasOwnProperty('name')) {
              reject(e.data);
            } else {
              resolve(e.data);
            }
          });

          // Note -- this will probably chage to e.openClientWindow(...)
          clients.openWindow("https://www.example.com/bobpay/pay")
          .then(function(windowClient) {
            windowClient.postMessage(e.data);
          })
          .catch(function(err) {
            reject(err);
          });
        }));
      });
    

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

<html> <body> <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>
window.addEventListener("message", function(e) {
  var form = document.getElementById("form");
  /* Note: message sent from payment app is available in e.data */
  form.onsubmit = function() {
    /* See https://w3c.github.io/webpayments-methods-card/#basiccardresponse */
    var basicCardResponse = {};
    [ "cardholderName", "cardNumber","expiryMonth","expiryYear","cardSecurityCode"]
    .forEach(function(field) {
      basicCardResponse[field] = form.elements[field].value;
    });

    /* See https://w3c.github.io/webpayments-payment-apps-api/#sec-app-response */
    var paymentAppResponse = {
      methodName: "basic-card",
      details: details
    };

    e.source.postMessage(paymentAppResponse);
    window.close();
  }
});
</script> </body> </html>
    

Security and Privacy Considerations

Information about the User Environment

User Consent before Payment

Secure Communications

Payment App Authenticity

The Web Payments Working Group is also discussing Payment App authenticity; see the (draft) Payment Method Manifest.

Data Validation

Private Browsing Mode