Copyright © 2019 W3C® (MIT, ERCIM, Keio, Beihang). W3C liability, trademark and permissive document license rules apply.
This specification defines capabilities that enable Web applications to handle requests for payment.
This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at https://www.w3.org/TR/.
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.
This document was published by the Web Payments Working Group as a Working Draft. This document is intended to become a W3C Recommendation.
GitHub Issues are preferred for discussion of this specification.
Publication as a Working Draft does not imply endorsement by the W3C Membership. This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.
This document was produced by a group operating under the W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.
This document is governed by the 1 March 2019 W3C Process Document.
This section is non-normative.
This specification defines a number of new features to allow web applications to handle requests for payments on behalf of users:
PaymentRequestEvent). A
        payment handler is an event handler for the
        PaymentRequestEvent.
        PaymentManager) to manage the definition, display, and user
        selection of PaymentInstruments.
        PaymentRequestEvent.
        This specification does not address how software built with operating-system specific mechanisms (i.e., "native apps") handle payment requests.
In this document we envision the following flow:
PaymentManager is used to set a list of payment instruments. Each
          payment instrument provides data
          to the user agent to improve the user experience of selecting payment
          credentials:
          method and
            optional capabilities inform the user
            agent decision whether to display this instrument as a candidate
            for payment.
            name
            and icon. These provide
            hints about payment credentials that the user agent will return in
            the PaymentHandlerResponse if the user selects this
            instrument.
            CanMakePaymentEvent is used as part of
        determining whether there is a match.
        instruments of
        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.
        PaymentRequestEvent (cf. the user interaction
        task source) in the service worker whose PaymentManager the
        instrument was registered with. The PaymentRequestEvent includes
        some information from the PaymentRequest (defined in
        [payment-request]) as well as additional information (e.g., origin
        and selected instrument).
        An origin may implement a payment app with more than one service worker and therefore multiple payment handlers may be registered per origin. The handler that is invoked is determined by the selection made by the user of a payment instrument. The service worker which stored the payment instrument with its PaymentManager is the one that will be invoked.
This section is non-normative.
A payment handler is a Web application that can handle a request for payment on behalf of the user.
The logic of a payment handler is driven by the payment methods that it supports. Some payment methods, such as basic-card expect little to no processing by the 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 payment handler initiate processing of the payment. In such cases the 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 payment handler accepting the PaymentRequestEvent
          and the payment handler returning a response. All of these activities
          which may be required to configure the payment handler and handle the
          payment request, are left to the implementation of the payment
          handler, including:
        
Thus, an origin will rely on many other Web technologies defined elsewhere for lifecycle management, security, user authentication, user interaction, and so on.
This section is non-normative.
 
          PaymentRequestEvents. PaymentManagers
            manage the definition, display, and user selection of
            PaymentInstruments. A PaymentInstrument supports one
            or more payment methods.
          This section is non-normative.
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.
 
          
        One registers a payment handler with the user agent when assigning the
        first PaymentInstrument to it through the set() method.
      
ServiceWorkerRegistration interface
        
          This specification extends the ServiceWorkerRegistration
          interface with the addition of a paymentManager attribute.
        
partial interface ServiceWorkerRegistration {
  [SameObject] readonly attribute PaymentManager paymentManager;
};
        
          The paymentManager attribute exposes payment handler
          functionality in the service worker.
        
PaymentManager interface
        [SecureContext, Exposed=(Window,Worker)]
interface PaymentManager {
  [SameObject] readonly attribute PaymentInstruments instruments;
  attribute DOMString userHint;
};
        
          The PaymentManager is used by payment handlers to
          manage their associated instruments and supported payment methods.
        
instruments attribute
          This attribute allows manipulation of payment instruments associated with a service worker (and therefore its payment handler). To be a candidate payment handler, a handler must have at least one registered payment instrument to present to the user. That instrument needs to match the payment methods and required capabilities specified by the payment request.
userHint attribute
          When displaying 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 payment handler. When a agent displays all payment instruments available through a payment handler, it may cause confusion to display the additional hint.
PaymentInstruments interface
        [SecureContext, Exposed=(Window,Worker)]
interface PaymentInstruments {
    Promise<boolean>           delete(DOMString instrumentKey);
    Promise<any> get(DOMString instrumentKey);
    Promise<sequence<DOMString>>  keys();
    Promise<boolean>           has(DOMString instrumentKey);
    Promise<void>              set(DOMString instrumentKey, PaymentInstrument details);
    Promise<void>           clear();
};
        
          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, if any.
        
delete() method
          When called, this method executes the following steps:
PaymentInstrument with a
            matching instrumentKey, remove it from the collection
            and resolve p with true.
            get() method
          When called, this method executes the following steps:
PaymentInstrument with a
            matching instrumentKey, resolve p with that
            PaymentInstrument.
            undefined.
            keys() method
          When called, this method executes the following steps:
PaymentInstruments
            contained in the collection, in original insertion order.
            has() method
          When called, this method executes the following steps:
PaymentInstrument with a
            matching instrumentKey, resolve p with
            true.
            set() method
          When called, this method executes the following steps:
PaymentInstrument's
            associated service worker registration.
            InvalidStateErrorNotAllowedError.
            icons member of
            details is present, then:
              
            icons member of
            details is present, then for each icon in
            details.icons:
              PaymentInstrument with a
            matching instrumentKey, replace it with the
            PaymentInstrument in details.
            PaymentInstrument in
            details as a new member of the collection and associate
            it with the key instrumentKey.
            clear() method
          When called, this method executes the following steps:
PaymentInstruments from the collection and
            resolve p.
            PaymentInstrument dictionary
          dictionary PaymentInstrument {
  required DOMString name;
  sequence<ImageObject> icons;
  DOMString method;
  object capabilities;
};
          name member
            name member is a string that represents the label for
              this PaymentInstrument as it is usually displayed to the
              user.
            icons member
            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.
            method member
            method member is the payment method identifier
              of the payment method supported by this instrument.
            capabilities member
            capabilities member is 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.
            ImageObject dictionary
          dictionary ImageObject {
    required USVString src;
    DOMString sizes;
    DOMString type;
};
          src member
            src member is used to specify the ImageObject's
              source. It is a URL from which the user agent can fetch the
              image’s data.
            sizes member
            sizes member is used to specify the
              ImageObject's sizes. It follows the spec of sizes member
              in HTML link element,
              which is a string consisting of an unordered
              set of unique space-separated tokens which are ASCII case-insensitive that
              represents the dimensions of an image. Each keyword is either an
              ASCII
              case-insensitive match for the string "any", or a value that
              consists of two valid non-negative integers that do not have a
              leading U+0030 DIGIT ZERO (0) character and that are separated by
              a single U+0078 LATIN SMALL LETTER X or U+0058 LATIN CAPITAL
              LETTER X character. The keywords represent icon sizes in raw
              pixels (as opposed to CSS pixels). When multiple image objects
              are available, a user agent MAY use the value to decide which
              icon is most suitable for a display context (and ignore any that
              are inappropriate). The parsing steps for the sizes member
              MUST follow the parsing
              steps for HTML link element sizes attribute.
            type member
            type member is used to specify the
              ImageObject's MIME type. It is a hint as to the media type
              of the image. The purpose of this member is to allow a user agent
              to ignore images of media types it does not support.
            When this algorithm with inputImages parameter is invoked, the user agent must run the following steps:
              ImageObject.
            type
                is not a valid MIME type string or
                the value of type is not a supported media format, then return
                an empty Sequence of ImageObject.
                sizes is not a valid value, then return an empty
                Sequence of ImageObject.
                src with the
                context object's
                relevant settings
                object's API base
                URL.
                ImageObject.
                ImageObject.
                src
                to url.
                
            According to the step 2.3, it is also possible to use the relative
            url for image.src. The
            following examples illustrate how relative URL resolution works in
            different execution contexts.
          
<-- In this example, code is located in https://www.example.com/bobpay/index.html -->
<script>
const instrumentKey = "c8126178-3bba-4d09-8f00-0771bcfd3b11";
navigator.serviceWorker.register("/register/sw.js");
const registration = await navigator.serviceWorker.ready;
await registration.paymentManager.paymentInstruments.set({
  instrumentKey,
  {
    name: "My Bob Pay Account: john@example.com",
    method: "https://bobpay.com",
    icons: [{
      src: "icon/lowres.webp",
      sizes: "48x48",
      type: "image/webp"
    }]
  });
const storedInstrument =
  await registration.paymentManager.paymentInstruments.get(instrumentKey);
// storedInstrument.icons[0].src == "https://www.example.com/bobpay/icon/lowres.webp";
</script>// In this example, code is located in https://www.example.com/register/sw.js
const instrumentKey = "c8126178-3bba-4d09-8f00-0771bcfd3b11";
await self.registration.paymentManager.paymentInstruments.set({
  instrumentKey,
  {
    name: "My Bob Pay Account: john@example.com",
    method: "https://bobpay.com",
    icons: [{
      src: "../bobpay/icon/lowres.webp",
      sizes: "48x48",
      type: "image/webp"
    }]
  });
const storedInstrument =
  await registration.paymentManager.paymentInstruments.get(instrumentKey);
// storedInstrument.icons[0].src == "https://www.example.com/bobpay/icon/lowres.webp";This section is non-normative.
The following example shows how to register a payment handler:
button.addEventListener("click", async() => {
  if (!window.PaymentManager) {
    return; // not supported, so bail out.
  }
  navigator.serviceWorker.register("/sw.js");
  const registration = await navigator.serviceWorker.ready;
  // Excellent, we got it! Let's now set up the user's cards.
  await addInstruments(registration);
}, { once: true });
function addInstruments(registration) {
  return Promise.all([
    registration.paymentManager.instruments.set(
      "dc2de27a-ca5e-4fbd-883e-b6ded6c69d4f",
      {
        name: "Visa ending ****4756",
        method: "basic-card",
        capabilities: {
          supportedNetworks: ["visa"],
          supportedTypes: ["credit"]
        }
      }),
    registration.paymentManager.instruments.set(
      "c8126178-3bba-4d09-8f00-0771bcfd3b11",
      {
        name: "My Bob Pay Account: john@example.com",
        method: "https://bobpay.com"
      }),
    registration.paymentManager.instruments.set(
      "new-card",
      {
        name: "Add new credit/debit card to ExampleApp",
        method: "basic-card",
        capabilities: {
          supportedNetworks:
            ["visa", "mastercard", "amex", "discover"],
          supportedTypes: ["credit", "debit", "prepaid"]
        }
      }),
    ]);
  };
        If the payment handler supports CanMakePaymentEvent, the
        user agent may use it to help with filtering of the available
        payment handlers.
      
        Implementations may impose a timeout for developers to respond to the
        CanMakePaymentEvent. If the timeout expires, then the
        implementation will behave as if respondWith() was called with
        false.
      
ServiceWorkerGlobalScope
        
          This specification extends the ServiceWorkerGlobalScope
          interface.
        
partial interface ServiceWorkerGlobalScope {
  attribute EventHandler oncanmakepayment;
};
        oncanmakepayment attribute
          
            The oncanmakepayment attribute is an event handler
            whose corresponding event handler event type is
            canmakepayment.
          
CanMakePaymentEvent
        
          The CanMakePaymentEvent is used to check whether the payment
          handler is able to respond to a payment request.
        
[Exposed=ServiceWorker]
interface CanMakePaymentEvent : ExtendableEvent {
  constructor(DOMString type, CanMakePaymentEventInit eventInitDict);
  readonly attribute USVString topOrigin;
  readonly attribute USVString paymentRequestOrigin;
  readonly attribute FrozenArray<PaymentMethodData> methodData;
  void respondWith(Promise<boolean> canMakePaymentResponse);
};
        
          The topOrigin, paymentRequestOrigin,
          methodData, and modifiers members share their
          definitions with those defined for PaymentRequestEvent.
        
respondWith() method
          This method is used by the payment handler to indicate whether it can respond to a payment request.
CanMakePaymentEventInit dictionary
          dictionary CanMakePaymentEventInit : ExtendableEventInit {
  USVString topOrigin;
  USVString paymentRequestOrigin;
  sequence<PaymentMethodData> methodData;
};
          
            The topOrigin, paymentRequestOrigin, and
            methodData members share their definitions with those
            defined for PaymentRequestEvent.
          
Upon receiving a PaymentRequest, the user agent MUST run the following steps:
CanMakePaymentEvent (e.g., in private browsing mode),
          terminate these steps.
          ServiceWorkerRegistration.
          
              Fire Functional Event "canmakepayment" using
              CanMakePaymentEvent on registration with the
              following properties:
            
topOrigin
              paymentRequestOrigin
              methodData
              CanMakePaymentEvent
        This section is non-normative.
          This example shows how to write a service worker that listens to the
          CanMakePaymentEvent. When a CanMakePaymentEvent is
          received, the service worker always returns true.
        
self.addEventListener("canmakepayment", function(e) {
  e.respondWith(true);
});
          Given a PaymentMethodData and a PaymentInstrument that
          match on payment method identifier, this algorithm returns
          true if this instrument can be used for payment:
        
PaymentInstrument.
          ServiceWorkerRegistration scope URL of the payment handler
          with this instrument.
          "*" string supported origins in
          paymentMethodManifest, filter based on capabilities:
            false.
                  true.
              CanMakePaymentEvent
          in the payment handler and return the result.
          CanMakePaymentEvent in the payment handler and return the
          result.
          false.
          This section is non-normative.
Example of how a payment handler should provide the list of all its active cards to the browser.
await navigator.serviceWorker.register("/pw/app.js");
const registration = await navigator.serviceWorker.ready;
registration.paymentManager.userHint = "(Visa ****1111)";
await registration.paymentManager.instruments.set(
  "12345",
  {
    name: "Visa ****1111",
    icons: [{
      src: "/pay/visa.png",
      sizes: "32x32",
      type: "image/png",
    }],
    method: "basic-card",
    capabilities: {
      supportedNetworks: ["visa"],
      supportedTypes: ["credit"],
    },
  });
            In this case, new PaymentRequest([{supportedMethods:
            "basic-card"}], shoppingCart).canMakePayment() should return
            true because there's an active card in the payment
            handler. Note that new PaymentRequest([{supportedMethods:
            "basic-card", data: {supportedTypes: ["debit"]}}],
            shoppingCart).canMakePayment() would return
            false because of mismatch in
            supportedTypes in this example.
          
        Once the user has selected an Instrument, the user agent fires a
        PaymentRequestEvent and uses the subsequent
        PaymentHandlerResponse to create a PaymentReponse 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 Payment Handler interface. The event will have a respondWith method that takes a boolean parameter indicating if the paymentRequest has been successfully aborted.
ServiceWorkerGlobalScope
        
          This specification extends the ServiceWorkerGlobalScope
          interface.
        
partial interface ServiceWorkerGlobalScope {
  attribute EventHandler onpaymentrequest;
};
        onpaymentrequest attribute
          
            The onpaymentrequest attribute is an event handler
            whose corresponding event handler event type is
            PaymentRequestEvent.
          
PaymentMethodChangeResponse
        
          The PaymentMethodChangeResponse contains the updated
          total (optionally with modifiers) and possible errors resulting from
          user selection of a payment method within a payment handler.
        
dictionary PaymentMethodChangeResponse {
  DOMString error;
  PaymentCurrencyAmount total;
  FrozenArray<PaymentDetailsModifier> modifiers;
  object paymentMethodErrors;
};
        error member
          A human readable string that explains why the payment method cannot be used.
total member
          Updated total based on the changed payment method. The total can change, for example, because the billing address of the payment method selected by the user changes the Value Added Tax (VAT).
modifiers member
          Updated modifiers based on the changed payment method. For example, if the overall total has increased by €1.00 based on the billing address, then the totals specified in each of the modifiers should also increase by €1.00.
paymentMethodErrors member
          Validation errors for the payment method, if any.
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 PaymentRequest to the Payment Handler.
[Exposed=ServiceWorker]
interface PaymentRequestEvent : ExtendableEvent {
  constructor(DOMString type, 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 DOMString instrumentKey;
  readonly attribute boolean requestBillingAddress;
  Promise<WindowClient?> openWindow(USVString url);
  Promise<PaymentMethodChangeResponse?> changePaymentMethod(DOMString methodName, optional object? methodDetails = null);
  void respondWith(Promise<PaymentHandlerResponse> handlerResponsePromise);
};
        topOrigin attribute
          Returns a string that indicates the origin of the top level payee web page. This attribute is initialized by Handling a PaymentRequestEvent.
paymentRequestOrigin attribute
          
            Returns a string that indicates the origin where a
            PaymentRequest was initialized. When a PaymentRequest
            is initialized in the topOrigin, the attributes have the
            same value, otherwise the attributes have different values. For
            example, when a PaymentRequest is initialized within an
            iframe from an origin other than topOrigin, the value of
            this attribute is the origin of the iframe. This attribute is
            initialized by Handling a PaymentRequestEvent.
          
paymentRequestId attribute
          
            When getting, the paymentRequestId attribute returns the
            [[details]].id from the PaymentRequest that
            corresponds to this PaymentRequestEvent.
          
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 MethodData Population Algorithm defined below.
total attribute
          
            This attribute indicates the total amount being requested for
            payment. It is of type PaymentCurrencyAmount dictionary as
            defined in [payment-request], and initialized with a
            structured clone of the total field of the
            PaymentDetailsInit 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.
instrumentKey attribute
          
            This attribute indicates the PaymentInstrument selected by
            the user. It corresponds to the instrumentKey provided to the
            PaymentManager.instruments interface during registration. An
            empty string means that the user did not choose a specific
            PaymentInstrument.
          
requestBillingAddress attribute
          The value of PaymentOptions.requestBillingAddress in the PaymentRequest.
openWindow() method
          This method is used by the payment handler to show a window to the user. When called, it runs the open window algorithm.
changePaymentMethod()
            method
          This method is used by the payment handler to get updated total given such payment method details as the billing address. When called, it runs the change payment method algorithm.
respondWith() method
          
            This method is used by the payment handler to provide a
            PaymentHandlerResponse when the payment successfully
            completes. When called, it runs the Respond to PaymentRequest
            Algorithm 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;
  DOMString instrumentKey;
};
          
            The topOrigin, paymentRequestOrigin,
            paymentRequestId, methodData,
            total, modifiers, and
            instrumentKey members share their definitions with those
            defined for PaymentRequestEvent
          
            To initialize the value of the methodData, the user agent
            MUST perform the following steps or their equivalent:
          
PaymentInstrument instrument in the
            payment handler's PaymentManager.instruments,
              add the value of instrument.method to
              registeredMethods.
            methodData to dataList.
            
            To initialize the value of the modifiers, the user agent
            MUST perform the following steps or their equivalent:
          
PaymentInstrument instrument in the
            payment handler's PaymentManager.instruments,
              add the value of instrument.method to
              registeredMethods.
            modifiers
            in the corresponding payment request, perform the following steps:
              total to a structured
                clone of inModifier.total.
                modifiers to modifierList.
            
          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 payment handler is currently showing a window to the user. Otherwise, it is null. | 
| [[fetchedImage]] | undefined | This value is a result of steps to fetch an image resource or a fallback image provided by the user agent. | 
| [[respondWithCalled]] | false | YAHO | 
Upon receiving a PaymentRequest by way of PaymentRequest.show() and subsequent user selection of a payment instrument, the user agent MUST run the following steps:
ServiceWorkerRegistration corresponding to the
          PaymentInstrument selected by the user.
          InvalidStateError" DOMException and terminate these
          steps.
          
              Fire Functional Event "paymentrequest" using
              PaymentRequestEvent on registration with the
              following properties:
            
topOrigin
              paymentRequestOrigin
              methodData
              total
              paymentRequestId
              instrumentKey
              PaymentInstrument, or the empty string if none was
                selected.
              Then run the following steps in parallel, with dispatchedEvent:
PaymentHandlerResponse, reject the Promise that was
              created by PaymentRequest.show() with an
              "OperationError" DOMException.
              An invoked payment handler may or may not need to display information about itself or request user input. Some examples of potential payment handler display include:
A payment handler 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
        PaymentRequest. A single payment handler SHOULD NOT be
        allowed to open more than one client window using this method.
      
This algorithm resembles the Open Window Algorithm in the Service Workers specification.
Should we refer to the Service Workers specification instead of copying their steps?
PaymentRequestEvent.
          isTrusted attribute is false, return
          a Promise rejected with a "InvalidStateError"
          DOMException.
          PaymentRequestEvent.
          about:blank, return a
          Promise rejected with a TypeError.
          NotAllowedError" DOMException.
          InvalidStateError" DOMException and abort these
              steps.
              PaymentRequestEvent
        This section is non-normative.
          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.
        
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);
      }
    });
    e.openWindow("https://www.example.com/bobpay/pay")
    .then(function(windowClient) {
      windowClient.postMessage(e.data);
    })
    .catch(function(err) {
      reject(err);
    });
  }));
});The Web Payments Working Group plans to revisit these two examples.
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:
<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/payment-handler/#paymenthandlerresponse-dictionary */
    var paymentAppResponse = {
      methodName: "basic-card",
      details: details
    };
    e.source.postMessage(paymentAppResponse);
    window.close();
  }
});
</script>PaymentHandlerResponse dictionary
        dictionary PaymentHandlerResponse {
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 interface.
            The application is expected to resolve the Promise with a
            PaymentHandlerResponse 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 are left to implementers. Acceptable behaviors include, but are not limited to:
When this algorithm is invoked with methodName and methodDetails parameters, the user agent MUST run the following steps:
null.
          InvalidStateError" DOMException.
          PaymentMethodChangeResponse from
          the detailsPromise in
          event.updateWith(detailsPromise).
          When this algorithm is invoked with event and handlerResponsePromise parameters, the user agent MUST run the following steps:
isTrusted is false, then
          throw an "InvalidStateError" DOMException and abort
          these steps.
          InvalidStateError" DOMException and
          abort these steps.
          InvalidStateError" DOMException and abort these
          steps.
          PaymentHandlerResponse
              dictionary. If this throws an exception, run the
              payment app failure algorithm and terminate these steps.
              methodName is not present
              or not set to one of the values from
                event.methodData,
                run the payment app failure algorithm and terminate
                these steps.
              details is not present or
              not JSON-serializable, run the payment app failure
              algorithm and terminate these steps.
              methodName. Rethrow any
              exceptions.
              details. Rethrow any
                exceptions.
              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] defines an ID that parties in the ecosystem (including payment app providers and payees) can use for reconciliation after network or other failures.
CanMakePaymentEvent will fire in registered
          payment handlers from a finite number of origins: the origins of the
          payment method manifests and their supported origins. This
          means that a registered payment handler will know that a user has
          visited a website before the user has selected that payment handler
          to complete a transaction. This behavior is similar to the status quo
          where a merchant embeds a third-party iframe in a checkout page.
          However, because user agents enable users to disable the
          CanMakePaymentEvent and users can choose to uninstall payment
          handlers, this approach improves upon the iframe status quo.
          CanMakePaymentEvent.
          set() is first called. The user agent might
          prompt the user as a result of set(), or might not if consent
          has been established previously through manual configuration by the
          user or usage patterns.
          set() promise for security
          reasons (e.g., due to an invalid SSL certificate) and SHOULD notify
          the user when this happens.
          CanMakePaymentEvent event should not be fired in
          private browsing mode. The user agent should behave as if
            respondWith()
            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 payment handler, that entity may be
            able to deduce that the user may be in private browsing mode.
          This section is non-normative.
When ordering payment handlers and payment instruments, 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 payment handler or instrument display order for an origin, or for all origins.
User experience details are left to implementers.
This specification relies on several other underlying specifications.
TypeError,
          and JSON.stringify are
          defined by [ECMASCRIPT].
        isTrusted attribute, and
          stop immediate
          propagation flag are defined in [DOM].
        When this specification says to throw an error, the user agent must throw an error as described in [WEBIDL]. When this occurs in a sub-algorithm, this results in termination of execution of the sub-algorithm and all ancestor algorithms until one is reached that explicitly describes procedures for catching exceptions.
The algorithm for converting an ECMAScript value to a dictionary is defined by [WEBIDL].
DOMException and the following DOMException types from [WEBIDL] are used:
ServiceWorkerRegistration,
          ServiceWorkerGlobalScope,
          fire functional
          event, extend lifetime
          promises,pending promises
          count, containing
          service worker registration, uninstalling flag,
          Try Clear
          Registration, Try Activate, and
          scope URL are
          defined in [SERVICE-WORKERS].
        As well as sections marked as non-normative, all authoring guidelines, diagrams, examples, and notes in this specification are non-normative. Everything else in this specification is normative.
The key words MAY, MUST, SHOULD, and SHOULD NOT in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.
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.
      
partial interfaceServiceWorkerRegistration{ [SameObject] readonly attributePaymentManagerpaymentManager; }; [SecureContext, Exposed=(Window,Worker)] interfacePaymentManager{ [SameObject] readonly attributePaymentInstrumentsinstruments; attribute DOMStringuserHint; }; [SecureContext, Exposed=(Window,Worker)] interfacePaymentInstruments{ Promise<boolean>delete(DOMString instrumentKey); Promise<any>get(DOMString instrumentKey); Promise<sequence<DOMString>>keys(); Promise<boolean>has(DOMString instrumentKey); Promise<void>set(DOMString instrumentKey,PaymentInstrumentdetails); Promise<void>clear(); }; dictionaryPaymentInstrument{ required DOMStringname; sequence<ImageObject>icons; DOMStringmethod; objectcapabilities; }; dictionaryImageObject{ required USVStringsrc; DOMStringsizes; DOMStringtype; }; partial interfaceServiceWorkerGlobalScope{ attribute EventHandleroncanmakepayment; }; [Exposed=ServiceWorker] interfaceCanMakePaymentEvent: ExtendableEvent {constructor(DOMString type,CanMakePaymentEventIniteventInitDict); readonly attribute USVStringtopOrigin; readonly attribute USVStringpaymentRequestOrigin; readonly attribute FrozenArray<PaymentMethodData>methodData; voidrespondWith(Promise<boolean> canMakePaymentResponse); }; dictionaryCanMakePaymentEventInit: ExtendableEventInit { USVStringtopOrigin; USVStringpaymentRequestOrigin; sequence<PaymentMethodData>methodData; }; partial interfaceServiceWorkerGlobalScope{ attribute EventHandleronpaymentrequest; }; dictionaryPaymentMethodChangeResponse{ DOMStringerror; PaymentCurrencyAmounttotal; FrozenArray<PaymentDetailsModifier>modifiers; objectpaymentMethodErrors; }; [Exposed=ServiceWorker] interfacePaymentRequestEvent: ExtendableEvent {constructor(DOMString type,PaymentRequestEventIniteventInitDict); readonly attribute USVStringtopOrigin; readonly attribute USVStringpaymentRequestOrigin; readonly attribute DOMStringpaymentRequestId; readonly attribute FrozenArray<PaymentMethodData>methodData; readonly attribute objecttotal; readonly attribute FrozenArray<PaymentDetailsModifier>modifiers; readonly attribute DOMStringinstrumentKey; readonly attribute booleanrequestBillingAddress; Promise<WindowClient?>openWindow(USVString url); Promise<PaymentMethodChangeResponse?>changePaymentMethod(DOMString methodName, optional object? methodDetails = null); voidrespondWith(Promise<PaymentHandlerResponse> handlerResponsePromise); }; dictionaryPaymentRequestEventInit: ExtendableEventInit { USVStringtopOrigin; USVStringpaymentRequestOrigin; DOMStringpaymentRequestId; sequence<PaymentMethodData>methodData; PaymentCurrencyAmounttotal; sequence<PaymentDetailsModifier>modifiers; DOMStringinstrumentKey; }; dictionaryPaymentHandlerResponse{ DOMStringmethodName; objectdetails; };