Payment Request API

This specification standardizes an API to allow merchants (i.e. web sites selling physical or digital goods) to utilize one or more payment methods with minimal integration. User agents (e.g., browsers) facilitate the payment flow between merchant and user.

The working group maintains a list of all bug reports that the group has not yet addressed. Pull requests with proposed specification text for outstanding issues are strongly encouraged.

If you wish to make comments regarding this document, please raise them as GitHub issues. Only send comments by email if you are unable to raise issues on GitHub (see links below). All comments are welcome.

The working group will demonstrate implementation experience by producing an implementation report. The report will show two or more independent implementations passing each mandatory test in the test suite (i.e., each test corresponds to a MUST requirement of the specification).

There has been no change in dependencies on other workings groups during the development of this specification.

Features at risk

As this specification enters the Candidate Recommendation phase of the W3C standardization process, the working group has identified the following feature(s) as being "at risk" of being removed from the specification. The working group seeks input from implementers, developers, and the general public on whether these features should remain in the specification. If no compelling use cases are received, or if there is limited interest from implementers, these features will be removed from the specification before proceeding along the W3C Recommendation track.

Introduction

This specification describes an API that allows user agents (e.g., browsers) to act as an intermediary between three parties in a transaction:

The details of how to fulfill a payment request for a given payment method is an implementation detail of a payment handler. Concretely, each payment handler defines:

Steps to check if a payment can be made:
How a payment handler determines whether it, or the user, can potentially "make a payment" is also an implementation detail of a payment handler. For an example, see the can make payment algorithm of [[?payment-method-basic-card]].
Steps to respond to a payment request:
Steps that return an object or dictionary that a merchant uses to process or validate the transaction. The structure of this object is specific to each payment method. For an example of such an object, see the BasicCardResponse dictionary of [[?payment-method-basic-card]].
Steps for when a user changes payment method (optional)
Steps that describe how to handle the user changing payment method or monetary instrument (e.g., from a debit card to a credit card) that results in a dictionary or object or null.

This API also enables web sites to take advantage of more secure payment schemes (e.g., tokenization and system-level authentication) that are not possible with standard JavaScript libraries. This has the potential to reduce liability for the merchant and helps protect sensitive user information.

Goals

Out of scope

  • Create a new payment method
  • Integrate directly with payment processors

Examples of usage

In order to use the API, the developer needs to provide and keep track of a number of key pieces of information. These bits of information are passed to the PaymentRequest constructor as arguments, and subsequently used to update the payment request being displayed to the user. Namely, these bits of information are:

Once a PaymentRequest is constructed, it's presented to the end user via the show() method. The show() returns a promise that, once the user confirms request for payment, results in a PaymentResponse.

The methodData argument

The methodData sequence contains PaymentMethodData dictionaries containing the payment method identifiers for the payment methods that the web site accepts and any associated payment method specific data.

          const methodData = [
            {
              supportedMethods: "basic-card",
              data: {
                supportedNetworks: ["visa", "mastercard"],
                supportedTypes: ["debit", "credit"],
              },
            },
            {
              supportedMethods: "https://example.com/bobpay",
              data: {
                merchantIdentifier: "XXXX",
                bobPaySpecificField: true,
              },
            },
          ];
        

The details argument

The details contains information about the transaction that the user is being asked to complete, such as the line items in an order.

          const details = {
            id: "super-store-order-123-12312",
            displayItems: [
              {
                label: "Sub-total",
                amount: { currency: "USD", value: "55.00" },
              },
              {
                label: "Sales Tax",
                amount: { currency: "USD", value: "5.00" },
                type: "tax"
              },
            ],
            total: {
              label: "Total due",
              // The total is USD$65.00 here because we need to
              // add shipping (below). The selected shipping
              // costs USD$5.00.
              amount: { currency: "USD", value: "65.00" },
            },
          };
        

Shipping options

Here we see an example of how to add two shipping options to the details.

            const shippingOptions = [
              {
                id: "standard",
                label: "🚛 Ground Shipping (2 days)",
                amount: { currency: "USD", value: "5.00" },
                selected: true,
              },
              {
                id: "drone",
                label: "🚀 Drone Express (2 hours)",
                amount: { currency: "USD", value: "25.00" }
              },
            ];
            Object.assign(details, { shippingOptions });
          

Conditional modifications to payment request

Here we see how to add a processing fee for using a credit card. Notice that it requires recalculating the total.

          // Credit card incurs a $3.00 processing fee.
          const creditCardFee = {
            label: "Credit card processing fee",
            amount: { currency: "USD", value: "3.00" },
          };

          // Modifiers apply when the user chooses to pay with
          // a credit card.
          const modifiers = [
            {
              additionalDisplayItems: [creditCardFee],
              supportedMethods: "basic-card",
              total: {
                label: "Total due",
                amount: { currency: "USD", value: "68.00" },
              },
              data: {
                supportedTypes: "credit",
              },
            },
          ];
          Object.assign(details, { modifiers });
          

The options argument

The options dictionary contains information the developer needs from the user to perform the payment (e.g., the payer's name and shipping address).

          const options = {
            requestPayerEmail: false,
            requestPayerName: true,
            requestPayerPhone: false,
            requestShipping: true,
          }
        

Constructing a PaymentRequest

Having gathered all the prerequisite bits of information, we can now construct a PaymentRequest and request that the browser present it to the user:

          async function doPaymentRequest() {
            try {
              const request = new PaymentRequest(methodData, details, options);
              // See below for a detailed example of handling these events
              request.onshippingaddresschange = ev => ev.updateWith(details);
              request.onshippingoptionchange = ev => ev.updateWith(details);
              const response = await request.show();
              await validateResponse(response);
            } catch (err) {
              // AbortError, SecurityError
              console.error(err);
            }
          }
          async function validateResponse(response) {
            try {
              if (await checkAllValuesAreGood(response)) {
                await response.complete("success");
              } else {
                await response.complete("fail");
              }
            } catch (err) {
              // Something went wrong...
              await response.complete("fail");
            }
          }
          doPaymentRequest();
        

Handling events and updating the payment request

Prior to the user accepting to make payment, the site is given an opportunity to update the payment request in response to user input. This can include, for example, providing additional shipping options (or modifying their cost), removing items that cannot ship to a particular address, etc.

          const request = new PaymentRequest(methodData, details, options);
          // Async update to details
          request.onshippingaddresschange = ev => {
            ev.updateWith(checkShipping(request));
          };
          // Sync update to the total
          request.onshippingoptionchange = ev => {
            // selected shipping option
            const { shippingOption } = request;
            const newTotal = {
              currency: "USD",
              label: "Total due",
              value: calculateNewTotal(shippingOption),
            };
            ev.updateWith({ total: newTotal });
          };
          async function checkShipping(request) {
            try {
              const json = request.shippingAddress.toJSON();

              await ensureCanShipTo(json);
              const { shippingOptions, total } = await calculateShipping(json);

              return { shippingOptions, total };
            } catch (err) {
              return { error: `Sorry! we can't ship to your address.` };
            }
          }
        

Fine-grained error reporting

A developer can use the shippingAddressErrors member of the PaymentDetailsUpdate dictionary to indicate that there are validation errors with specific attributes of a PaymentAddress. The shippingAddressErrors member is a AddressErrors dictionary, whose members specifically demarcate the fields of a physical address that are erroneous while also providing helpful error messages to be displayed to the end user.

          request.onshippingaddresschange = ev => {
            ev.updateWith(validateAddress(request.shippingAddress));
          };
          function validateAddress(shippingAddress) {
            const error = "Can't ship to this address.";
            const shippingAddressErrors = {
              city: "FarmVille is not a real place.",
              postalCode: "Unknown postal code for your country.",
            };
            // Empty shippingOptions implies that we can't ship
            // to this address.
            const shippingOptions = [];
            return { error, shippingAddressErrors, shippingOptions };
          }
        

POSTing payment response back to a server

It's expected that data in a PaymentResponse will be POSTed back to a server for processing. To make this as easy as possible, PaymentResponse provides a toJSON() method that serializes the object directly into JSON. This makes it trivial to POST the resulting JSON back to a server using the Fetch API:

          async function doPaymentRequest() {
            const payRequest = new PaymentRequest(methodData, details, options);
            const payResponse = await payRequest.show();
            let result = "";
            try {
              const httpResponse = await fetch("/process-payment", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: payResponse.toJSON(),
              });
              result = httpResponse.ok ? "success" : "fail";
            } catch (err) {
              console.error(err);
              result = "fail";
            }
            await payResponse.complete(result);
          }
          doPaymentRequest();
        

PaymentRequest interface

        [Constructor(sequence<PaymentMethodData> methodData, PaymentDetailsInit details, optional PaymentOptions options),
        SecureContext, Exposed=Window]
        interface PaymentRequest : EventTarget {
          [NewObject]
          Promise<PaymentResponse> show(optional Promise<PaymentDetailsUpdate> detailsPromise);
          [NewObject]
          Promise<void> abort();
          [NewObject]
          Promise<boolean> canMakePayment();

          readonly attribute DOMString id;
          readonly attribute PaymentAddress? shippingAddress;
          readonly attribute DOMString? shippingOption;
          readonly attribute PaymentShippingType? shippingType;

          attribute EventHandler onmerchantvalidation;
          attribute EventHandler onshippingaddresschange;
          attribute EventHandler onshippingoptionchange;
          attribute EventHandler onpaymentmethodchange;
        };
      

A developer creates a PaymentRequest to make a payment request. This is typically associated with the user initiating a payment process (e.g., by activating a "Buy," "Purchase," or "Checkout" button on a web site, selecting a "Power Up" in an interactive game, or paying at a kiosk in a parking structure). The PaymentRequest allows developers to exchange information with the user agent while the user is providing input (up to the point of user approval or denial of the payment request).

The shippingAddress, shippingOption, and shippingType attributes are populated during processing if the requestShipping member is set.

Because the simultaneous display of multiple PaymentRequest user interfaces might confuse the user, this specification limits the user agent to displaying one at a time via the show() method. This is ensured by a payment request is showing boolean.

Constructor

The PaymentRequest is constructed using the supplied sequence of PaymentMethodData methodData including any payment method specific data, the PaymentDetailsInit details, and the PaymentOptions options.

The PaymentRequest(methodData, details, options) constructor MUST act as follows:

  1. If the current settings object's responsible document is not allowed to use the feature indicated by attribute name allowpaymentrequest, then throw a "SecurityError" DOMException.
  2. Let serializedMethodData be an empty list.
  3. Establish the request's id:
    1. If details.id is missing, add an id member to details and set its value to a UUID [[RFC4122]].
  4. Process payment methods:
    1. If the length of the methodData sequence is zero, then throw a TypeError, optionally informing the developer that at least one payment method is required.
    2. For each paymentMethod of methodData:
      1. Run the steps to validate a payment method identifier with paymentMethod.supportedMethods. If it returns false, then throw a RangeError exception. Optionally, inform the developer that the payment method identifier is invalid.
      2. If the data member of paymentMethod is missing, let serializedData be null. Otherwise, let serializedData be the result of JSON-serializing paymentMethod.data into a string. Rethrow any exceptions.
      3. Add the tuple (paymentMethod.supportedMethods, serializedData) to serializedMethodData.
  5. Process the total:
    1. Check and canonicalize total amount details.total.amount. Rethrow any exceptions.
  6. If the displayItems member of details is present, then for each item in details.displayItems:
    1. Check and canonicalize amount item.amount. Rethrow any exceptions.
  7. Let selectedShippingOption be null.
  8. If the requestShipping member of options is present and set to true, process shipping options:
    1. Let options be an empty sequence<PaymentShippingOption>.
    2. If the shippingOptions member of details is present, then:
      1. Let seenIDs be an empty set.
      2. For each option in details.shippingOptions:
        1. Check and canonicalize amount item.amount. Rethrow any exceptions.
        2. If seenIDs contains option.id, then throw a TypeError. Optionally, inform the developer that shipping option IDs must be unique.
        3. Otherwise, append option.id to seenIDs.
        4. If option.selected is true, then set selectedShippingOption to option.id.
    3. Set details.shippingOptions to options.
  9. Let serializedModifierData be an empty list.
  10. Process payment details modifiers:
    1. Let modifiers be an empty sequence<PaymentDetailsModifier>.
    2. If the modifiers member of details is present, then:
      1. Set modifiers to details.modifiers.
      2. For each modifier of modifiers:
        1. If the total member of modifier is present, then:
          1. Check and canonicalize total amount modifier.total.amount. Rethrow any exceptions.
        2. If the additionalDisplayItems member of modifier is present, then for each item of modifier.additionalDisplayItems:
          1. Check and canonicalize amount item.amount. Rethrow any exceptions.
        3. If the data member of modifier is missing, let serializedData be null. Otherwise, let serializedData be the result of JSON-serializing modifier.data into a string. Rethrow any exceptions.
        4. Add serializedData to serializedModifierData.
        5. Remove the data member of modifier, if it is present.
    3. Set details.modifiers to modifiers.
  11. Let request be a new PaymentRequest.
  12. Set request.[[\options]] to options.
  13. Set request.[[\state]] to "created".
  14. Set request.[[\updating]] to false.
  15. Set request.[[\details]] to details.
  16. Set request.[[\serializedModifierData]] to serializedModifierData.
  17. Set request.[[\serializedMethodData]] to serializedMethodData.
  18. Set request.[[\response]] to null.
  19. Set the value of request's shippingOption attribute to selectedShippingOption.
  20. Set the value of the shippingAddress attribute on request to null.
  21. If options.requestShipping is set to true, then set the value of the shippingType attribute on request to options.shippingType. Otherwise, set it to null.
  22. Return request.

id attribute

When getting, the id attribute returns this PaymentRequest's [[\details]].id.

show() method

The show() method is called when a developer wants to begin user interaction for the payment request. The show() method returns a Promise that will be resolved when the user accepts the payment request. Some kind of user interface will be presented to the user to facilitate the payment request after the show() method returns.

It is not possible to show multiple PaymentRequests at the same time within one user agent. If a PaymentRequest is already showing, calling show() —from any Web site— will return a promise rejected with an "AbortError" DOMException.

The show(optional detailsPromise) method MUST act as follows:

  1. If the method was not triggered by user activation, return a promise rejected with with a "SecurityError" DOMException.
  2. Let request be the context object.
  3. Let document be request's relevant global object's associated Document.
  4. If document is not fully active, then return a promise rejected with an "AbortError" DOMException.
  5. Optionally, if the user agent wishes to disallow the call to show() to protect the user, then return a promise rejected with a "SecurityError" DOMException. For example, the user agent may limit the rate at which a page can call show(), as described in the privacy considerations section.

  6. If request.[[\state]] is not "created" then return a promise rejected with an "InvalidStateError" DOMException.
  7. If the user agent's payment request is showing boolean is true, then return a promise rejected with an "AbortError" DOMException.
  8. Set request.[[\state]] to "interactive".
  9. Let acceptPromise be a new promise.
  10. Set request.[[\acceptPromise]] to acceptPromise.
  11. Optionally:

    1. Reject acceptPromise with an "AbortError" DOMException.
    2. Set request.[[\state]] to "closed".
    3. Return acceptPromise.

    This allows the user agent to act as if the user had immediately aborted the payment request, at its discretion. For example, in "private browsing" modes or similar, user agents might take advantage of this step.

  12. Set the user agent's payment request is showing boolean to true.
  13. Return acceptPromise and perform the remaining steps in parallel.
  14. Let handlers be an empty list.
  15. For each paymentMethod tuple in request.[[\serializedMethodData]]:
    1. Let identifier be the first element in the paymentMethod tuple.
    2. Let data be the result of JSON-parsing the second element in the paymentMethod tuple.
    3. If required by the specification that defines the identifier, then convert data to an IDL value of the type specified there. Otherwise, convert to object.
    4. If conversion results in an exception error:
      1. Set request.[[\state]] to "closed".
      2. Reject acceptPromise with error.
      3. Set user agent's payment request is showing boolean to false.
      4. Terminate this algorithm.
    5. Let registeredHandlers be a list of registered payment handlers for the payment method identifier.
    6. For each handler in registeredHandlers:
      1. Let canMakePayment be the result of running handler's steps to check if a payment can be made with data.
      2. If canMakePayment is true, then append handler to handlers.
  16. If handlers is empty, then:
    1. Set request.[[\state]] to "closed".
    2. Reject acceptPromise with "NotSupportedError" DOMException.
    3. Set user agent's payment request is showing boolean to false.
    4. Terminate this algorithm.
  17. Present a user interface that will allow the user to interact with the handlers. The user agent SHOULD prioritize the preference of the user when presenting payment methods. It is RECOMMENDED that the language of the user interface match the language of the body element.
  18. If detailsPromise was passed, then:
    1. Run the update a PaymentRequest's details algorithm with detailsPromise and request.
    2. Wait for the detailsPromise to settle.

      Based on how the detailsPromise settles, the update a PaymentRequest's details algorithm determines how the payment UI behaves. That is, upon rejection of the detailsPromise, the payment request aborts. Otherwise, upon fulfillment detailsPromise, the user agent re-enables the payment request UI and the payment flow can continue.

  19. For the payment handler selected by the end-user, the user agent MUST pass the converted second element in the paymentMethod tuple. Optionally, the user agent SHOULD send the appropriate data from request to the user-selected payment handler in order to guide the user through the payment process. This includes the various attributes and internal slots of request (some MAY be excluded for privacy reasons where appropriate).

    The acceptPromise will later be resolved or rejected by either the user accepts the payment request algorithm or the user aborts the payment request algorithm, which are triggered through interaction with the user interface.

    If document stops being fully active while the user interface is being shown, or no longer is by the time this step is reached, then:

    1. Close down the user interface.
    2. Set the user agent's payment request is showing boolean to false.
    3. Reject acceptPromise with an "AbortError" DOMException.

abort() method

The abort() method is called if a developer wishes to tell the user agent to abort the payment request and to tear down any user interface that might be shown. The abort() can only be called after the show() method has been called (see states) and before this instance's [[\acceptPromise]] has been resolved. For example, developers might choose to do this if the goods they are selling are only available for a limited amount of time. If the user does not accept the payment request within the allowed time period, then the request will be aborted.

A user agent might not always be able to abort a request. For example, if the user agent has delegated responsibility for the request to another app. In this situation, abort() will reject the returned Promise.

See also the algorithm when the user aborts the payment request.

The abort() method MUST act as follows:

  1. Let request be the context object.
  2. If request.[[\response]] is not null, and request.[[\response]].[[\retryPromise]] is not null, return a promise rejected with an "InvalidStateError" DOMException.
  3. If the value of request.[[\state]] is not "interactive" then return a promise rejected with an "InvalidStateError" DOMException.
  4. Let promise be a new promise.
  5. Return promise and perform the remaining steps in parallel.
  6. Try to abort the current user interaction with the payment handler and close down any remaining user interface.
  7. Queue a task on the user interaction task source to perform the following steps:
    1. If it is not possible to abort the current user interaction, then reject promise with "InvalidStateError" DOMException and abort these steps.
    2. Set request.[[\state]] to "closed".
    3. Reject the promise request.[[\acceptPromise]] with an "AbortError" DOMException.
    4. Resolve promise with undefined.

canMakePayment() method

The canMakePayment() method can be used by the developer to determine if the PaymentRequest object can be used to make a payment, before they call show(). It returns a Promise that will be fulfilled with true if the user agent supports any of the desired payment methods supplied to the PaymentRequest constructor, and false if none are supported. If the method is called too often, the user agent might instead return a promise rejected with a "NotAllowedError" DOMException, at its discretion.

The canMakePayment() method MUST act as follows:

  1. Let request be the PaymentRequest object on which the method was called.
  2. If request.[[\state]] is not "created", then return a promise rejected with an "InvalidStateError" DOMException.
  3. Optionally, at the user agent's discretion, return a promise rejected with a "NotAllowedError" DOMException.

    This allows user agents to apply heuristics to detect and prevent abuse of the canMakePayment() method for fingerprinting purposes, such as creating PaymentRequest objects with a variety of supported payment methods and calling canMakePayment() on them one after the other. For example, a user agent may restrict the number of successful calls that can be made based on the top-level browsing context or the time period in which those calls were made.

  4. Let hasHandlerPromise be a new promise.
  5. Return hasHandlerPromise, and perform the remaining steps in parallel.
  6. For each paymentMethod tuple in request.[[\serializedMethodData]]:
    1. Let identifier be the first element in the paymentMethod tuple.
    2. If there user agent has a payment handler that support handling payment requests for identifier, resolve hasHandlerPromise with true and terminate this algorithm.
  7. Resolve hasHandlerPromise with false.

shippingAddress attribute

A PaymentRequest's shippingAddress attribute is populated when the user provides a shipping address. It is null by default. When a user provides a shipping address, the shipping address changed algorithm runs.

shippingType attribute

A PaymentRequest's shippingType attribute is the type of shipping used to fulfill the transaction. Its value is either a PaymentShippingType enum value, or null if none is provided by the developer during construction (see PaymentOptions's shippingType member).

onmerchantvalidation attribute

A PaymentRequest's onmerchantvalidation attribute is an EventHandler for a MerchantValidationEvent named "merchantvalidation".

onshippingaddresschange attribute

A PaymentRequest's onshippingaddresschange attribute is an EventHandler for a PaymentRequestUpdateEvent named shippingaddresschange.

shippingOption attribute

A PaymentRequest's shippingOption attribute is populated when the user chooses a shipping option. It is null by default. When a user chooses a shipping option, the shipping option changed algorithm runs.

onshippingoptionchange attribute

A PaymentRequest's onshippingoptionchange attribute is an EventHandler for a PaymentRequestUpdateEvent named shippingoptionchange.

onpaymentmethodchange attribute

A PaymentRequest's onpaymentmethodchange attribute is an EventHandler for a PaymentMethodChangeEvent named "paymentmethodchange".

Internal Slots

Instances of PaymentRequest are created with the internal slots in the following table:

Internal Slot Description (non-normative)
[[\serializedMethodData]] The methodData supplied to the constructor, but represented as tuples containing supported methods and a string or null for data (instead of the original object form).
[[\serializedModifierData]] A list containing the serialized string form of each data member for each corresponding item in the sequence [[\details]].modifier, or null if no such member was present.
[[\details]] The current PaymentDetailsBase for the payment request initially supplied to the constructor and then updated with calls to updateWith(). Note that all data members of PaymentDetailsModifier instances contained in the modifiers member will be removed, as they are instead stored in serialized form in the [[\serializedModifierData]] internal slot.
[[\options]] The PaymentOptions supplied to the constructor.
[[\state]]

The current state of the payment request, which transitions from:

"created"
The payment request is constructed and has not been presented to the user.
"interactive"
The payment request is being presented to the user.
"closed"
The payment request completed.

The state transitions are illustrated in the figure below:

The constructor sets the initial state to "created". The show() method changes the state to "interactive". From there, the abort() method or any other error can send the state to "closed"; similarly, the user accepts the payment request algorithm and user aborts the payment request algorithm will change the state to "closed".
[[\updating]] true is there is a pending updateWith() call to update the payment request and false otherwise.
[[\acceptPromise]] The pending Promise created during show that will be resolved if the user accepts the payment request.
[[\response]] Null, or the PaymentResponse instantiated by this PaymentRequest.

PaymentMethodData dictionary

        dictionary PaymentMethodData {
          required DOMString supportedMethods;
          object data;
        };
      

A PaymentMethodData dictionary is used to indicate a set of supported payment methods and any associated payment method specific data for those methods.

supportedMethods member
A payment method identifier for a payment method that the merchant web site accepts.
data member
An object that provides optional information that might be needed by the supported payment methods. If supplied, it will be JSON-serialized.

The value of supportedMethods was changed from array to string, but the name was left as a plural to maintain compatibility with existing content on the Web.

PaymentCurrencyAmount dictionary

        dictionary PaymentCurrencyAmount {
          required DOMString currency;
          required DOMString value;
        };
      

A PaymentCurrencyAmount dictionary is used to supply monetary amounts.

currency member

A [[ISO4217]] well-formed 3-letter alphabetic code (i.e., the numeric codes are not supported). Their canonical form is upper case. However, the set of combinations of currency code for which localized currency symbols are available is implementation dependent. Where a localized currency symbol is not available, a user agent SHOULD use U+00A4 (¤) for formatting. User agents MAY format the display of the currency member to adhere to OS conventions (e.g., for localization purposes).

User agents implementing this specification enforce [[ISO4217]]'s 3-letter codes format via ECMAScript’s isWellFormedCurrencyCode abstract operation, which is invoked as part of the check and canonicalize amount algorithm. When a code does not adhere to the [[ISO4217]] defined format, a RangeError is thrown.

Current implementations will therefore allow the use of well-formed currency codes that are not part of the official [[ISO4217]] list (e.g., XBT, XRP, etc.). If the provided code is a currency that the browser knows how to display, then an implementation will generally display the appropriate currency symbol in the user interface (e.g., "USD" is shown as "$", "GBP" is "£", and the non-standard "XBT" could be shown as "Ƀ"). When a code cannot be matched, the specification recommends browsers show a scarab "¤".

Efforts are underway at ISO to account for digital currencies, which may result in an update to the [[ISO4217]] registry or an entirely new registry. The community expects this will resolve ambiguities that have crept in through the use of non-standard 3-letter codes; for example, does "BTC" refer to Bitcoin or to a future Bhutan currency? At the time of publication, it remains unclear what form this evolution will take, or even the time frame in which the work will be completed. The W3C Web Payments Working Group is liaising with ISO so that, in the future, revisions to this specification remain compatible with relevant ISO registries.

value member
A valid decimal monetary value containing a monetary amount.

The following example shows how to represent US$55.00.

        {
          "currency": "USD",
          "value": "55.00"
        }
      

Validity checkers

A JavaScript string is a valid decimal monetary value if it consists of the following code points in the given order:

  1. Optionally, a single U+002D (-), to indicate that the amount is negative.
  2. One or more code points in the range U+0030 (0) to U+0039 (9).
  3. Optionally, a single U+002E (.) followed by one or more code points in the range U+0030 (0) to U+0039 (9).
The following regular expression is an implementation of the above definition.
^-?[0-9]+(\.[0-9]+)?$

To check and canonicalize amount given a PaymentCurrencyAmount amount, run the following steps:

  1. If the result of IsWellFormedCurrencyCode(amount.currency) is false, then throw a RangeError exception, optionally informing the developer that the currency is invalid.
  2. If amount.value is not a valid decimal monetary value, throw a TypeError, optionally informing the developer that the currency is invalid.
  3. Set amount.currency to the result of ASCII uppercasing amount.currency.

To check and canonicalize total amount given a PaymentCurrencyAmount amount, run the following steps:

  1. Check and canonicalize amount amount. Rethrow any exceptions.
  2. If the first code point of amount.value is U+002D (-), then throw a TypeError optionally informing the developer that a total's value can't be a negative number.

Payment details dictionaries

PaymentDetailsBase dictionary

        dictionary PaymentDetailsBase {
          sequence<PaymentItem> displayItems;
          sequence<PaymentShippingOption> shippingOptions;
          sequence<PaymentDetailsModifier> modifiers;
        };
        
displayItems member
A sequence of PaymentItem dictionaries contains line items for the payment request that the user agent MAY display.
shippingOptions member

A sequence containing the different shipping options for the user to choose from.

If an item in the sequence has the selected member set to true, then this is the shipping option that will be used by default and shippingOption will be set to the id of this option without running the shipping option changed algorithm. If more than one item in the sequence has selected set to true, then the user agent selects the last one in the sequence.

The shippingOptions member is only used if the PaymentRequest was constructed with PaymentOptions and requestShipping set to true.

modifiers member
A sequence of PaymentDetailsModifier dictionaries that contains modifiers for particular payment method identifiers. For example, it allows you to adjust the total amount based on payment method.

PaymentDetailsInit dictionary

          dictionary PaymentDetailsInit : PaymentDetailsBase {
            DOMString id;
            required PaymentItem total;
          };
        

In addition to the members inherited from the PaymentDetailsBase dictionary, the following members are part of the PaymentDetailsInit dictionary:

id member
A free-form identifier for this payment request.
total member
A PaymentItem containing a non-negative total amount for the payment request.

PaymentDetailsUpdate dictionary

          dictionary PaymentDetailsUpdate : PaymentDetailsBase {
            DOMString error;
            PaymentItem total;
            AddressErrors shippingAddressErrors;
            PayerErrors payerErrors;
            object paymentMethodErrors;
          };
        

The PaymentDetailsUpdate dictionary is used to update the payment request using updateWith().

In addition to the members inherited from the PaymentDetailsBase dictionary, the following members are part of the PaymentDetailsUpdate dictionary:

error member
A human-readable string. When the payment request is updated using updateWith(), the PaymentDetailsUpdate can contain a message in the error member that will be displayed to the user, if the PaymentDetailsUpdate indicates that there are no valid shippingOptions (and the PaymentRequest was constructed with the requestShipping option set to true). This can be used to explain why goods cannot be shipped to the chosen shipping address, or any other reason why no shipping options are available.
total member
A PaymentItem contains the non-negative amount.

Algorithms in this specification that accept a PaymentDetailsUpdate dictionary will throw if the total.amount.value is a negative number.

shippingAddressErrors member
Represents validation errors with the shipping address that is associated with the event target.
payerErrors member
Validation errors related to the payer details.
paymentMethodErrors member

Payment method specific errors. See, for example, [[?payment-method-basic-card]]'s BasicCardErrors.

PaymentDetailsModifier dictionary

        dictionary PaymentDetailsModifier {
          required DOMString supportedMethods;
          PaymentItem total;
          sequence<PaymentItem> additionalDisplayItems;
          object data;
        };
      

The PaymentDetailsModifier dictionary provides details that modify the PaymentDetailsBase based on a payment method identifier. It contains the following members:

supportedMethods member
A payment method identifier. The members of the PaymentDetailsModifier only apply if the user selects this payment method.
total member
A PaymentItem value that overrides the total member in the PaymentDetailsInit dictionary for the payment method identifiers of the supportedMethods member.
additionalDisplayItems member
A sequence of PaymentItem dictionaries provides additional display items that are appended to the displayItems member in the PaymentDetailsBase dictionary for the payment method identifiers in the supportedMethods member. This member is commonly used to add a discount or surcharge line item indicating the reason for the different total amount for the selected payment method that the user agent MAY display.

It is the developer's responsibility to verify that the total amount is the sum of the displayItems and the additionalDisplayItems.

data member
An object that provides optional information that might be needed by the supported payment methods. If supplied, it will be JSON-serialized.

PaymentShippingType enum

        enum PaymentShippingType {
          "shipping",
          "delivery",
          "pickup"
        };
      
"shipping"
This is the default and refers to the address being collected as the destination for shipping.
"delivery"
This refers to the address being collected as being used for delivery. This is commonly faster than shipping. For example, it might be used for food delivery.
"pickup"
This refers to the address being collected as part of a service pickup. For example, this could be the address for laundry pickup.

PaymentOptions dictionary

        dictionary PaymentOptions {
          boolean requestPayerName = false;
          boolean requestPayerEmail = false;
          boolean requestPayerPhone = false;
          boolean requestShipping = false;
          PaymentShippingType shippingType = "shipping";
        };
      

The PaymentOptions dictionary is passed to the PaymentRequest constructor and provides information about the options desired for the payment request.

requestPayerName member
A boolean that indicates whether the user agent SHOULD collect and return the payer's name as part of the payment request. For example, this would be set to true to allow a merchant to make a booking in the payer's name.
requestPayerEmail member
A boolean that indicates whether the user agent SHOULD collect and return the payer's email address as part of the payment request. For example, this would be set to true to allow a merchant to email a receipt.
requestPayerPhone member
A boolean that indicates whether the user agent SHOULD collect and return the payer's phone number as part of the payment request. For example, this would be set to true to allow a merchant to phone a customer with a billing enquiry.
requestShipping member
A boolean that indicates whether the user agent SHOULD collect and return a shipping address as part of the payment request. For example, this would be set to true when physical goods need to be shipped by the merchant to the user. This would be set to false for the purchase of digital goods.
shippingType member
A PaymentShippingType enum value. Some transactions require an address for delivery but the term "shipping" isn't appropriate. For example, "pizza delivery" not "pizza shipping" and "laundry pickup" not "laundry shipping". If requestShipping is set to true, then the shippingType member can influence the way the user agent presents the user interface for gathering the shipping address.

The shippingType member only affects the user interface for the payment request.

PaymentItem dictionary

        dictionary PaymentItem {
          required DOMString label;
          required PaymentCurrencyAmount amount;
          boolean pending = false;
        };
      

A sequence of one or more PaymentItem dictionaries is included in the PaymentDetailsBase dictionary to indicate what the payment request is for and the value asked for.

label member
A human-readable description of the item. The user agent may display this to the user.
amount member
A PaymentCurrencyAmount containing the monetary amount for the item.
pending member
A boolean. When set to true it means that the amount member is not final. This is commonly used to show items such as shipping or tax amounts that depend upon selection of shipping address or shipping option. User agents MAY indicate pending fields in the user interface for the payment request.

Physical addresses

A physical address is composed of the following parts.

Country
The country corresponding to the address.
Address line
The most specific part of the address. It can include, for example, a street name, a house number, apartment number, a rural delivery route, descriptive instructions, or a post office box number.
Region
The top level administrative subdivision of the country. For example, this can be a state, a province, an oblast, or a prefecture.
City
The city/town portion of the address.
Dependent locality
The dependent locality or sublocality within a city. For example, neighborhoods, boroughs, districts, or UK dependent localities.
Postal code
The postal code or ZIP code, also known as PIN code in India.
Sorting code
The sorting code as used in, for example, France.
Organization
The organization, firm, company, or institution at the address.
Recipient
The name of the recipient or contact person at the address.
Phone number
The phone number of the recipient or contact person at the address.

PaymentAddress interface

          [SecureContext, Exposed=(Window)]
          interface PaymentAddress {
            [Default] object toJSON();
            readonly attribute DOMString city;
            readonly attribute DOMString country;
            readonly attribute DOMString dependentLocality;
            readonly attribute DOMString organization;
            readonly attribute DOMString phone;
            readonly attribute DOMString postalCode;
            readonly attribute DOMString recipient;
            readonly attribute DOMString region;
            readonly attribute DOMString regionCode;
            readonly attribute DOMString sortingCode;
            readonly attribute FrozenArray<DOMString> addressLine;
          };
        

The PaymentAddress interface represents a physical address.

Internal constructor

Currently, this constructor algorithm is only used internally by a user agent. It is not available to scripts. However, discussions are underway in the working group to make this into a public constructor.

The steps to internally construct a PaymentAddress with an optional AddressInit details are given by the following algorithm:

  1. Let address be a new instance of PaymentAddress.
  2. Set address.[[\addressLine]] to the empty frozen array, and all other internal slots to the empty string.
  3. If details was not passed, return address.
  4. If details["country"] is present and not the empty string:
    1. Set country the result of strip leading and trailing ASCII whitespace from details["country"] and performing ASCII uppercasing.
    2. If country is not a valid [[ISO3166-1]] alpha-2 code, throw a RangeError exception.
    3. Set address.[[\country]] to country.
  5. If details["regionCode"] is present and not the empty string:
    1. Let regionCode be the result of strip leading and trailing ASCII whitespace from details["regionCode"] and then ASCII uppercasing the result.
    2. Let putativeCountrySubdivisionCodeElement be the concatenation of address.[[\country]], a single U+002D (-) code point, and regionCode.
    3. If putativeCountrySubdivisionCodeElement is not a valid country subdivision code element as per [[ISO3166-2]]'s section 5.2 "Structure of country subdivision code elements" (non-normative details below), throw a RangeError exception.

      Do not implement from this note. The structure of a country subdivision code element is formally defined in [[ISO3166-2]] (section 5.2). Although the structure is not expected to change at the time of writing, implementers are expected to track updates to [[ISO3166-2]] directly from ISO.

      As [[ISO3166-2]] is not freely available to the general public, the structure of a country subdivision code element at the time of publication is as follows:

    4. Set address.[[\regionCode]] to regionCode.
    5. If details["region"] is not present:
      1. Let region be the corresponding country subdivision name for regionCode. Where [[ISO3166-2]] defines multiple country subdivision names for a regionCode, it is RECOMMENDED the user agent select one by matching on:
        1. The language of the body element.
        2. The user's preferred languages.
        3. Any other criteria the user agent deems suitable.
      2. Set details["region"] to region.
  6. Let cleanAddressLines be an empty list.
  7. If details["addressLine"] is present, then for each item in details["addressLine"]:
    1. Strip leading and trailing ASCII whitespace from item and append the result into cleanAddressLines.
  8. Set address.[[\addressLine]] to a new frozen array created from cleanAddressLines.
  9. If details["region"] is present, strip leading and trailing ASCII whitespace from details["region"] and set address.[[\region]] to the result.
  10. If details["city"] is present, strip leading and trailing ASCII whitespace from details["city"] and set address.[[\city]] to the result.
  11. If details["dependentLocality"] is present, strip leading and trailing ASCII whitespace from details["dependentLocality"] and set address.[[\dependentLocality]] to the result.
  12. If details["postalCode"] is present, strip leading and trailing ASCII whitespace from details["postalCode"] and set address.[[\postalCode]] to the result.
  13. If details["sortingCode"] is present, strip leading and trailing ASCII whitespace from details["sortingCode"] and set address.[[\sortingCode]] to the result.
  14. If details["sortingCode"] is present, strip leading and trailing ASCII whitespace from details["sortingCode"] and set address.[[\sortingCode]] to the result.
  15. If details["organization"] is present, strip leading and trailing ASCII whitespace from details["organization"] and set address.[[\organization]] to the result.
  16. If details["recipient"] is present, strip leading and trailing ASCII whitespace from details["recipient"] and set address.[[\recipient]] to the result.
  17. If details["phone"] is present, strip leading and trailing ASCII whitespace from details["phone"] and set address.[[\phone]] to the result.
  18. Return address.

toJSON() method

When called, runs [[WEBIDL]]'s default toJSON operation.

country attribute

Represents the country of the address. When getting, returns the value of the PaymentAddress's [[\country]] internal slot.

addressLine attribute

Represents the address line of the address. When getting, returns the value of the PaymentAddress's [[\addressLine]] internal slot.

region attribute

Represents the region of the address. When getting, returns the value of the PaymentAddress's [[\region]] internal slot.

regionCode attribute

Represents the region of the address as a code element of an [[ISO3166-2]] country subdivision name (e.g., "CA" for California, USA). When getting, returns the value of the PaymentAddress's [[\regionCode]] internal slot.

city attribute

Represents the city of the address. When getting, returns the value of the PaymentAddress's [[\city]] internal slot.

dependentLocality attribute

Represents the dependent locality of the address. When getting, returns the value of the PaymentAddress's [[\dependentLocality]] internal slot.

postalCode attribute

Represents the postal code of the address. When getting, returns the value of the PaymentAddress's [[\postalCode]] internal slot.

sortingCode attribute

Represents the sorting code of the address. When getting, returns the value of the PaymentAddress's [[\sortingCode]] internal slot.

organization attribute

Represents the organization of the address. When getting, returns the value of the PaymentAddress's [[\organization]] internal slot.

recipient attribute

Represents the recipient of the address. When getting, returns the value of the PaymentAddress's [[\recipient]] internal slot.

phone attribute

Represents the phone number of the address. When getting, returns the value of the PaymentAddress's [[\phone]] internal slot.

Internal slots

Internal slot Description (non-normative)
[[\country]] A country as an [[ISO3166-1]] alpha-2 code stored in its canonical uppercase form or the empty string. For example, "JP".
[[\addressLine]] A frozen array, possibly of zero length, representing an address line.
[[\region]] A region as a country subdivision name or the empty string, such as "Victoria", representing the state of Victoria in Australia.
[[\regionCode]] The empty string, or one to three code points that represent a region as the code element of an [[ISO3166-2]] country subdivision name (i.e., the characters after the hyphen in an ISO3166-2 country subdivision code element, such as "CA" for the state of California in the USA, or "11" for the Lisbon district of Portugal).
[[\city]] A city or the empty string.
[[\dependentLocality]] A dependent locality or the empty string.
[[\postalCode]] A postal code or the empty string.
[[\sortingCode]] A sorting code or the empty string.
[[\organization]] An organization or the empty string.
[[\recipient]] A recipient or the empty string.
[[\phone]] A phone number or the empty string.

AddressInit dictionary

          dictionary AddressInit {
            DOMString country;
            sequence<DOMString> addressLine;
            DOMString region;
            DOMString regionCode;
            DOMString city;
            DOMString dependentLocality;
            DOMString postalCode;
            DOMString sortingCode;
            DOMString organization;
            DOMString recipient;
            DOMString phone;
          };
        

A AddressInit is passed when constructing a PaymentAddress. Its members are as follows.

country member
An country, represented as a [[ISO3166-1]] country code.
addressLine member
An address line, represented as a sequence.
region member
A region.
regionCode member
The empty string, or one to three code points that represent a region as the code element of an [[ISO3166-2]] country subdivision name (i.e., the characters after the hyphen in an ISO3166-2 country subdivision code element, such as "CA" for the state of California in the USA, or "11" for the Lisbon district of Portugal).
city member
A city.
dependentLocality member
A dependent locality.
postalCode member
A postal code.
sortingCode member
A sorting code.
organization member
An organization.
recipient member
A recipient. Under certain circumstances, this member may contain multiline information. For example, it might contain "care of" information.
phone member
A phone number, optionally structured to adhere to [[E.164]].

AddressErrors dictionary

          dictionary AddressErrors {
            DOMString addressLine;
            DOMString city;
            DOMString country;
            DOMString dependentLocality;
            DOMString organization;
            DOMString phone;
            DOMString postalCode;
            DOMString recipient;
            DOMString region;
            DOMString regionCode;
            DOMString sortingCode;
          };
        

The members of the AddressErrors dictionary represent validation errors with specific parts of a physical address. Each dictionary member has a dual function: firstly, its presence denotes that a particular part of an address is suffering from a validation error. Secondly, the string value allows the developer to describe the validation error (and possibly how the end user can fix the error).

Developers need to be aware that users might not have the ability to fix certain parts of an address. As such, they need to be mindful to not to ask the user to fix things they might not have control over.

addressLine member
Denotes that the address line has a validation error. In the user agent's UI, this member corresponds to the input field that provided the PaymentAddress's addressLine attribute's value.
city member
Denotes that the city has a validation error. In the user agent's UI, this member corresponds to the input field that provided the PaymentAddress's city attribute's value.
country member
Denotes that the country has a validation error. In the user agent's UI, this member corresponds to the input field that provided the PaymentAddress's country attribute's value.
dependentLocality member
Denotes that the dependent locality has a validation error. In the user agent's UI, this member corresponds to the input field that provided the PaymentAddress's dependentLocality attribute's value.
organization member
Denotes that the organization has a validation error. In the user agent's UI, this member corresponds to the input field that provided the PaymentAddress's organization attribute's value.
phone member
Denotes that the phone number has a validation error. In the user agent's UI, this member corresponds to the input field that provided the PaymentAddress's phone attribute's value.
postalCode member
Denotes that the postal code has a validation error. In the user agent's UI, this member corresponds to the input field that provided the PaymentAddress's postalCode attribute's value.
recipient member
Denotes that the recipient has a validation error. In the user agent's UI, this member corresponds to the input field that provided the PaymentAddress's addressLine attribute's value.
region member
Denotes that the region has a validation error. In the user agent's UI, this member corresponds to the input field that provided the PaymentAddress's region attribute's value.
regionCode member
Denotes that the region code representation of the region has a validation error. In the user agent's UI, this member corresponds to the input field that provided the PaymentAddress's regionCode attribute's value.
sortingCode member
The sorting code has a validation error. In the user agent's UI, this member corresponds to the input field that provided the PaymentAddress's sortingCode attribute's value.

Creating a PaymentAddress from user-provided input

The steps to create a PaymentAddress from user-provided input are given by the following algorithm. The algorithm takes a list redactList, for which user input will not be gathered.

  1. Let details be an AddressInit dictionary with no members present.
  2. If "addressLine" is not in redactList, set details["addressLine"] to the result of splitting the user-provided address line into a list. If none was provided, set it to the empty list.
  3. If "country" is not in redactList, set details["country"] to the user-provided country as an upper case [[ISO3166-1]] alpha-2 code, or to the empty string if none was provided.
  4. If "phone" is not in redactList, set details["phone"] to the user-provided phone number, or to the empty string if none was provided.
  5. If "city" is not in redactList, set details["city"] to the user-provided city, or to the empty string if none was provided.
  6. If "dependentLocality" is not in redactList, set details["dependentLocality"] to the user-provided dependent locality, or to the empty string if none was provided.
  7. If "organization" is not in redactList, set details["organization"] to the user-provided recipient organization, or to the empty string if none was provided.
  8. If "postalCode" is not in redactList, set details["postalCode"] to the user-provided postal code, or to the empty string if none was provided. Optionally, redact part of details["postalCode"].

    Postal codes in certain countries can be so specific as to uniquely identify an individual. This being a privacy concern, some user agents only return the part of a postal code that they deem sufficient for a merchant to calculate shipping costs. This varies across countries and regions, and so the choice to redact part, or all, of the postal code is left to the discretion of implementers in the interest of protecting users' privacy.

  9. If "recipient" is not in redactList, set details["recipient"] to the user-provided recipient of the transaction, or to the empty string if none was provided.
  10. If "region" is not in redactList:

    In some countries (e.g., Belgium) it is uncommon for users to include a region as part of a physical address (even if all the regions of a country are part of [[ISO3166-2]]). As such, when the user agent knows that the user is inputting the address for a particular country, it might not provide a field for the user to input a region. In such cases, the user agent returns an empty string for both PaymentAddress's region and regionCode attributes - but the address can still serve its intended purpose (e.g., be valid for shipping or billing purposes).

    1. Set details["region"] to the user-provided region, or to the empty string if none was provided.
    2. If details["region"] has a corresponding country subdivision code element, set details["regionCode"] to that country subdivision code element.
  11. If "sortingCode" is not in redactList, set details["sortingCode"] to the user-provided sorting code, or to the empty string if none was provided.
  12. Internally construct a new PaymentAddress with details and return the result.

PaymentShippingOption dictionary

        dictionary PaymentShippingOption {
          required DOMString id;
          required DOMString label;
          required PaymentCurrencyAmount amount;
          boolean selected = false;
        };
      

The PaymentShippingOption dictionary has members describing a shipping option. Developers can provide the user with one or more shipping options by calling the updateWith() method in response to a change event.

id member
A string identifier used to reference this PaymentShippingOption. It MUST be unique for a given PaymentRequest.
label member
A human-readable string description of the item. The user agent SHOULD use this string to display the shipping option to the user.
amount member
A PaymentCurrencyAmount containing the monetary amount for the item.
selected member
A boolean. When true, it indicates that this is the default selected PaymentShippingOption in a sequence. User agents SHOULD display this option by default in the user interface.

PaymentComplete enum

        enum PaymentComplete {
          "fail",
          "success",
          "unknown"
        };
      
"fail"
Indicates that processing of the payment failed. The user agent MAY display UI indicating failure.
"success"
Indicates the payment was successfully processed. The user agent MAY display UI indicating success.
"unknown"
The developer did not indicate success or failure and the user agent SHOULD NOT display UI indicating success or failure.

PaymentResponse interface

        [SecureContext, Exposed=Window]
        interface PaymentResponse : EventTarget  {
          [Default] object toJSON();

          readonly attribute DOMString requestId;
          readonly attribute DOMString methodName;
          readonly attribute object details;
          readonly attribute PaymentAddress? shippingAddress;
          readonly attribute DOMString? shippingOption;
          readonly attribute DOMString? payerName;
          readonly attribute DOMString? payerEmail;
          readonly attribute DOMString? payerPhone;

          [NewObject]
          Promise<void> complete(optional PaymentComplete result = "unknown");
          [NewObject]
          Promise<void> retry(optional PaymentValidationErrors errorFields);

          attribute EventHandler onpayerdetailchange;
        };
      

A PaymentResponse is returned when a user has selected a payment method and approved a payment request.

retry() method

The retry(errorFields) method MUST act as follows:

  1. Let response be the context object.
  2. Let request be response.[[\request]].
  3. Let document be request's relevant global object's associated Document.
  4. If document is not fully active, then return a promise rejected with an "AbortError" DOMException.
  5. If response.[[\complete]] is true, return a promise rejected with an "InvalidStateError" DOMException.
  6. If response.[[\retryPromise]] is not null, return a promise rejected with an "InvalidStateError" DOMException.
  7. Set request.[[\state]] to "interactive".
  8. Let retryPromise be a new promise.
  9. Set response.[[\retryPromise]] to retryPromise.
  10. If errorFields's paymentMethod member was passed, and if required by the specification that defines response's payment method, then convert errorFields paymentMethod to an IDL value of the type specified there. Otherwise, convert to object.
  11. If conversion results in a exception error:
    1. Reject retryPromise with error.
    2. Set user agent's payment request is showing boolean to false.
    3. Return.
  12. By matching the members of errorFields to input fields in the user agent's UI, indicate to the end-user that something is wrong with the data of the payment response. For example, a user agent might draw the user's attention to the erroneous errorFields in the browser's UI and display the value of each field in a manner that helps the user fix each error. Similarly, if the error member is passed, present the error in the user agent's UI.
  13. If document stops being fully active while the user interface is being shown, or no longer is by the time this step is reached, then:
    1. Close down the user interface.
    2. Set the user agent's payment request is showing boolean to false.
    3. Reject retryPromise with an "AbortError" DOMException.
  14. Finally, when retryPromise settles, set response.[[\retryPromise]] to null.
  15. Return retryPromise.

    The retryPromise will later be resolved by the user accepts the payment request algorithm, or rejected by either the user aborts the payment request algorithm or abort the update.

PaymentValidationErrors dictionary

            dictionary PaymentValidationErrors {
              PayerErrors payer;
              AddressErrors shippingAddress;
              DOMString error;
              object paymentMethod;
            };
          
payer member
Validation errors related to the payer details.
shippingAddress member
Represents validation errors with the PaymentResponse's shippingAddress.
error member
A general description of an error with the payment from which the user can attempt to recover from by, for example, retrying a payment. A developer can optionally pass the error member on its own to give a general overview of validation issues, or it can be passed in combination with other members of the PaymentValidationErrors dictionary.
paymentMethod member
A payment method specific errors. See, for example, [[?payment-method-basic-card]]'s BasicCardErrors.

PayerErrors dictionary

          dictionary PayerErrors {
            DOMString email;
            DOMString name;
            DOMString phone;
          };
          

The PayerErrors is used to represent validation errors with one or more payer details.

Payer details are any of the payer's name, payer's phone number, and payer's email.

email member
Denotes that the payer's email suffers from a validation error. In the user agent's UI, this member corresponds to the input field that provided the PaymentResponse's payerEmail attribute's value.
name member
Denotes that the payer's name suffers from a validation error. In the user agent's UI, this member corresponds to the input field that provided the PaymentResponse's payerName attribute's value.
phone member
Denotes that the payer's phone number suffers from a validation error. In the user agent's UI, this member corresponds to the input field that provided the PaymentResponse's payerPhone attribute's value.
          const payer = {
            email: "The domain is invalid.",
            phone: "Unknown country code.",
            name: "Not in database.",
          };
          await response.retry({ payer });
          

toJSON() method

When called, runs [[WEBIDL]]'s default toJSON operation.

methodName attribute

The payment method identifier for the payment method that the user selected to fulfill the transaction.

details attribute

An object or dictionary generated by a payment method that a merchant can use to process or validate a transaction (depending on the payment method).

shippingAddress attribute

If the requestShipping member was set to true in the PaymentOptions passed to the PaymentRequest constructor, then shippingAddress will be the full and final shipping address chosen by the user.

shippingOption attribute

If the requestShipping member was set to true in the PaymentOptions passed to the PaymentRequest constructor, then shippingOption will be the id attribute of the selected shipping option.

payerName attribute

If the requestPayerName member was set to true in the PaymentOptions passed to the PaymentRequest constructor, then payerName will be the name provided by the user.

payerEmail attribute

If the requestPayerEmail member was set to true in the PaymentOptions passed to the PaymentRequest constructor, then payerEmail will be the email address chosen by the user.

payerPhone attribute

If the requestPayerPhone member was set to true in the PaymentOptions passed to the PaymentRequest constructor, then payerPhone will be the phone number chosen by the user.

requestId attribute

The corresponding payment request id that spawned this payment response.

complete() method

The complete() method is called after the user has accepted the payment request and the [[\acceptPromise]] has been resolved. Calling the complete() method tells the user agent that the payment interaction is over (and SHOULD cause any remaining user interface to be closed).

After the payment request has been accepted and the PaymentResponse returned to the caller but before the caller calls complete() the payment request user interface remains in a pending state. At this point the user interface ought not offer a cancel command because acceptance of the payment request has been returned. However, if something goes wrong and the developer never calls complete() then the user interface is blocked.

For this reason, implementations MAY impose a timeout for developers to call complete(). If the timeout expires then the implementation will behave as if complete() was called with no arguments.

The complete(result) method MUST act as follows:

  1. Let response be the context object.
  2. If response.[[\complete]] is true, return a promise rejected with an "InvalidStateError" DOMException.
  3. Let promise be a new promise.
  4. Set response.[[\complete]] to true.
  5. If response.[[\retryPromise]] is not null, reject promise with an "InvalidStateError" DOMException.
  6. Return promise and perform the remaining steps in parallel.
  7. If document stops being fully active while the user interface is being shown, or no longer is by the time this step is reached, then:
    1. Close down the user interface.
    2. Set the user agent's payment request is showing boolean to false.
    3. Reject promise with an "AbortError" DOMException.
  8. Otherwise:
    1. Close down any remaining user interface. The user agent MAY use the value result to influence the user experience.
    2. Set the user agent's payment request is showing boolean to false.
    3. Resolve promise with undefined.

onpayerdetailchange attribute

Allows a developer to handle "payerdetailchange" events.

Internal Slots

Instances of PaymentResponse are created with the internal slots in the following table:

Internal Slot Description (non-normative)
[[\complete]] Is true if the request for payment has completed (i.e., complete() was called, or there was a fatal error that made the response not longer usable), or false otherwise.
[[\request]] The PaymentRequest instance that instantiated this PaymentResponse.
[[\retryPromise]] Null, or a Promise that resolves when a user accepts the payment request or rejects if the user aborts the payment request.

PaymentRequest and iframe elements

To indicate that a cross-origin iframe is allowed to invoke the payment request API, the allowpaymentrequest attribute can be specified on the iframe element.

Events

Summary

Event name Interface Dispatched when… Target
merchantvalidation MerchantValidationEvent The user agent requires the merchant to perform merchant validation. PaymentRequest
shippingaddresschange PaymentRequestUpdateEvent The user provides a new shipping address. PaymentRequest
shippingoptionchange PaymentRequestUpdateEvent The user chooses a new shipping option. PaymentRequest
payerdetailchange PaymentRequestUpdateEvent The user changes the payer name, the payer email, or the payer phone (see payer detail changed algorithm). PaymentResponse
paymentmethodchange PaymentMethodChangeEvent The user chooses a different payment method within a payment handler. PaymentRequest

MerchantValidationEvent interface

          [Constructor(DOMString type, optional MerchantValidationEventInit eventInitDict),
          SecureContext, Exposed=Window]
          interface MerchantValidationEvent : Event {
            readonly attribute DOMString methodName;
            readonly attribute USVString validationURL;
            void complete(Promise<any> merchantSessionPromise);
          };
        

methodName attribute

When getting, returns the value it was initialized with. See methodName member of MerchantValidationEventInit for more information.

MerchantValidationEvent constructor

The event constructing steps, which take a MerchantValidationEvent event, are as follows:

  1. Let base be the event’s relevant settings object’s API base URL.
  2. Let validationURL be the result of URL parsing eventInitDict["validationURL"] and base.
  3. If validationURL is failure, throw a TypeError.
  4. Initialize event.validationURL attribute to validationURL.
  5. If eventInitDict["methodName"] is not the empty string, run the steps to validate a payment method identifier with eventInitDict["methodName"]. If it returns false, then throw a RangeError exception. Optionally, inform the developer that the payment method identifier is invalid.
  6. Initialize event.methodName attribute to eventInitDict["methodName"].
  7. Initialize event.[[\waitForUpdate]] to false.

validationURL attribute

A URL from which a developer can fetch payment handler-specific verification data. By then passing that data (or a promise that resolves with that data) to complete(), the user agent can verify that the payment request is from a authorized merchant.

When getting, returns the value it was initialized with.

complete() method

The MerchantValidationEvent's complete(merchantSessionPromise) method MUST act as follows:

  1. Let event be the context object.
  2. If event's isTrusted attribute is false, then throw an "InvalidStateError" DOMException.
  3. If event.[[\waitForUpdate]] is true, then throw an "InvalidStateError" DOMException.
  4. Let request be event's target.
  5. If request.[[\state]] is not "interactive", then throw an "InvalidStateError" DOMException.
  6. If request.[[\updating]] is true, then throw an "InvalidStateError" DOMException.
  7. Set event's stop propagation flag and stop immediate propagation flag.
  8. Set event.[[\waitForUpdate]] to true.
  9. Run the validate merchant's details algorithm with merchantSessionPromise and request.

Internal Slots

Instances of MerchantValidationEvent are created with the internal slots in the following table:

Internal Slot Description (non-normative)
[[\waitForUpdate]] A boolean indicating whether an complete()-initiated update is currently in progress.

MerchantValidationEventInit dictionary

            dictionary MerchantValidationEventInit : EventInit {
              DOMString methodName = "";
              USVString validationURL = "";
            };
          
methodName member
A payment method identifier representing the payment handler that is requiring merchant validation.
validationURL member
A URL from which a developer would fetch payment handler-specific verification data.

PaymentMethodChangeEvent interface

          [Constructor(DOMString type, optional PaymentMethodChangeEventInit eventInitDict), SecureContext, Exposed=Window]
          interface PaymentMethodChangeEvent : PaymentRequestUpdateEvent {
            readonly attribute DOMString methodName;
            readonly attribute object? methodDetails;
          };
        

methodDetails attribute

When getting, returns the value it was initialized with. See methodDetails member of PaymentMethodChangeEventInit for more information.

methodName attribute

When getting, returns the value it was initialized with. See methodName member of PaymentMethodChangeEventInit for more information.

PaymentMethodChangeEventInit dictionary

            dictionary PaymentMethodChangeEventInit : PaymentRequestUpdateEventInit {
              DOMString methodName = "";
              object? methodDetails = null;
            };
          
methodName member
A string representing the payment method identifier.
methodDetails member
An object representing some data from the payment method, or null.

PaymentRequestUpdateEvent interface

          [Constructor(DOMString type, optional PaymentRequestUpdateEventInit eventInitDict), SecureContext, Exposed=Window]
          interface PaymentRequestUpdateEvent : Event {
            void updateWith(Promise<PaymentDetailsUpdate> detailsPromise);
          };
        

The PaymentRequestUpdateEvent enables developers to update the details of the payment request in response to a user interaction.

Constructor

The PaymentRequestUpdateEvent(type, eventInitDict) constructor MUST act as follows:

  1. Let event be the result of constructing a PaymentRequestUpdateEvent instance with type and eventInitDict.
  2. Set event.[[\waitForUpdate]] to false.
  3. Return event.

updateWith() method

The updateWith(detailsPromise) method MUST act as follows:

  1. Let event be this PaymentRequestUpdateEvent instance.
  2. If event's isTrusted attribute is false, then then throw an "InvalidStateError" DOMException.
  3. If event.[[\waitForUpdate]] is true, then throw an "InvalidStateError" DOMException.
  4. If event's target is an instance of PaymentResponse, let request be event's target.[[\request]].
  5. Otherwise, let request be the value of event's target.
  6. Assert: request is an instance of PaymentRequest.
  7. If request.[[\state]] is not "interactive", then throw an "InvalidStateError" DOMException.
  8. If request.[[\updating]] is true, then throw an "InvalidStateError" DOMException.
  9. Set event's stop propagation flag and stop immediate propagation flag.
  10. Set event.[[\waitForUpdate]] to true.
  11. Run the update a PaymentRequest's details algorithm with detailsPromise and request.

Internal Slots

Instances of PaymentRequestUpdateEvent are created with the internal slots in the following table:

Internal Slot Description (non-normative)
[[\waitForUpdate]] A boolean indicating whether an updateWith()-initiated update is currently in progress.

PaymentRequestUpdateEventInit dictionary

            dictionary PaymentRequestUpdateEventInit : EventInit {};
          

Algorithms

When the internal slot [[\state]] of a PaymentRequest object is set to "interactive", the user agent will trigger the following algorithms based on user interaction.

Merchant validation

Merchant validation is the process by which a payment handler validates the identity of a merchant against some value (usually some cryptographic challenge response). Validated merchants are allowed to interface with a payment handler. Details of how actual validation is performed is outside the scope of this specification.

It is OPTIONAL for a payment handler to support merchant validation.

For payment methods that support merchant validation, the user agent runs the request merchant validation algorithm. The algorithm takes a USVString merchantSpecificURL, provided by the payment handler:

  1. Let request be the PaymentRequest object that the user is interacting with.
  2. Let validationURL be a absolute URL string from which a developer can fetch payment handler-specific verification data.
  3. Let methodName be the payment method identifier for the payment handler that is requiring merchant validation.
  4. Queue a task on the user interaction task source to run the following steps:
    1. Assert: request.[[\updating]] is false.
    2. Assert: request.[[\state]] is "interactive".
    3. Let eventInitDict be an new MerchantValidationEventInit dictionary.
    4. Set eventInitDict["validationURL"] to validationURL.
    5. Set eventInitDict["methodName"] to methodName.
    6. Let event be the result of constructing a MerchantValidationEvent with "merchantvalidation" and eventInitDict.
    7. Initialize event’s isTrusted attribute to true.
    8. Dispatch event to request.

Shipping address changed algorithm

The shipping address changed algorithm runs when the user provides a new shipping address. It MUST run the following steps:

  1. Let request be the PaymentRequest object that the user is interacting with.
  2. Queue a task on the user interaction task source to run the following steps:
    1. The redactList optionally gives user agents the possibility to limit the amount of personal information about the recipient that the API shares with the merchant.

      For merchants, the resulting PaymentAddress object provides enough information to, for example, calculate shipping costs, but, in most cases, not enough information to physically locate and uniquely identify the recipient.

      Unfortunately, even with the redactList, recipient anonymity cannot be assured. This is because in some countries postal codes are so fine-grained that they can uniquely identify a recipient.

      Let redactList be the empty list. Optionally, set redactList to « "organization", "phone", "recipient", "addressLine" ».
    2. Let address be the result of running the steps to create a PaymentAddress from user-provided input with redactList.
    3. Set the shippingAddress attribute on request to address.
    4. Run the PaymentRequest updated algorithm with request and "shippingaddresschange".

Shipping option changed algorithm

The shipping option changed algorithm runs when the user chooses a new shipping option. It MUST run the following steps:

  1. Let request be the PaymentRequest object that the user is interacting with.
  2. Queue a task on the user interaction task source to run the following steps:
    1. Set the shippingOption attribute on request to the id string of the PaymentShippingOption provided by the user.
    2. Run the PaymentRequest updated algorithm with request and "shippingoptionchange".

Payment method changed algorithm

A payment handler MAY run the payment method changed algorithm when the user changes payment method with methodDetails, which is either dictionary or an object or null, and a methodName, which is a DOMString that represents the payment method identifier of the payment handler the user is interacting with:

  1. Let request be the PaymentRequest object that the user is interacting with.
  2. Queue a task on the user interaction task source to run the following steps:
    1. Assert: request.[[\updating]] is false. Only one update can take place at a time.
    2. Assert: request.[[\state]] is "interactive".
    3. Fire an event named "paymentmethodchange" at request using PaymentMethodChangeEvent, with its methodName attribute initialized to methodName, and its methodDetails attribute initialized to methodDetails.

PaymentRequest updated algorithm

The PaymentRequest updated algorithm is run by other algorithms above to fire an event to indicate that a user has made a change to a PaymentRequest called request with an event name of name:

  1. Assert: request.[[\updating]] is false. Only one update can take place at a time.
  2. Assert: request.[[\state]] is "interactive".
  3. Let event be the result of creating an event using the PaymentRequestUpdateEvent interface.
  4. Initialize event's type attribute to name.
  5. Dispatch event at request.
  6. If event.[[\waitForUpdate]] is true, disable any part of the user interface that could cause another update event to be fired.

Payer detail changed algorithm

The user agent MUST run the payer detail changed algorithm when the user changes the payer name, or the payer email, or the payer phone in the user interface:

  1. Let request be the PaymentRequest object that the user is interacting with.
  2. If request.[[\response]] is null, return.
  3. Let response be request.[[\response]].
  4. Queue a task on the user interaction task source to run the following steps:
    1. Assert: request.[[\updating]] is false.
    2. Assert: request.[[\state]] is "interactive".
    3. Let options be request.[[\options]].
    4. If payer name changed and options.requestPayerName is true:
      1. Set response's payerName attribute to payer name.
    5. If payer email changed and options.requestPayerEmail is true:
      1. Set response's payerEmail attribute to payer email.
    6. If payer phone changed and options.requestPayerPhone is true:
      1. Set response's payerPhone attribute to payer phone.
    7. Let event be the result of creating an event using PaymentRequestUpdateEvent.
    8. Initialize event's type attribute to "payerdetailchange".
    9. Dispatch event at response.
    10. If event.[[\waitForUpdate]] is true, disable any part of the user interface that could cause another change to the payer details to be fired.

User accepts the payment request algorithm

The user accepts the payment request algorithm runs when the user accepts the payment request and confirms that they want to pay. It MUST queue a task on the user interaction task source to perform the following steps:

  1. Let request be the PaymentRequest object that the user is interacting with.
  2. If the request.[[\updating]] is true, then terminate this algorithm and take no further action. The user agent user interface SHOULD ensure that this never occurs.
  3. If request.[[\state]] is not "interactive", then terminate this algorithm and take no further action. The user agent user interface SHOULD ensure that this never occurs.
  4. If the requestShipping value of request.[[\options]] is true, then if the shippingAddress attribute of request is null or if the shippingOption attribute of request is null, then terminate this algorithm and take no further action. The user agent SHOULD ensure that this never occurs.
  5. Let isRetry be true if request.[[\response]] is not null, false otherwise.
  6. Let response be request.[[\response]] if isRetry is true, or a new PaymentResponse otherwise.
  7. If isRetry if false, initialize the newly created response:
    1. Set response.[[\request]] to request.
    2. Set response.[[\retryPromise]] to null.
    3. Set response.[[\complete]] to false.
    4. Set the requestId attribute value of response to the value of request.[[\details]].id.
    5. Set request.[[\response]] to response.
  8. Let handler be the payment handler selected by the user.
  9. Set the methodName attribute value of response to the payment method identifier of handler.
  10. Set the details attribute value of response to an object resulting from running the handler's steps to respond to a payment request.
  11. If the requestShipping value of request.[[\options]] is false, then set the shippingAddress attribute value of response to null. Otherwise:
    1. Let redactList be the empty list.
    2. Let shippingAddress be the result of create a PaymentAddress from user-provided input with redactList.
    3. Set the shippingAddress attribute value of response to shippingAddress.
    4. Set the shippingAddress attribute value of request to shippingAddress.
  12. If the requestShipping value of request.[[\options]] is true, then set the shippingOption attribute of response to the value of the shippingOption attribute of request. Otherwise, set it to null.
  13. If the requestPayerName value of request.[[\options]] is true, then set the payerName attribute of response to the payer's name provided by the user, or to null if none was provided. Otherwise, set it to null.
  14. If the requestPayerEmail value of request.[[\options]] is true, then set the payerEmail attribute of response to the payer's email address provided by the user, or to null if none was provided. Otherwise, set it to null.
  15. If the requestPayerPhone value of request.[[\options]] is true, then set the payerPhone attribute of response to the payer's phone number provided by the user, or to null if none was provided. When setting the payerPhone value, the user agent SHOULD format the phone number to adhere to [[E.164]].
  16. If isRetry is true, resolve response.[[\retryPromise]] with undefined. Otherwise, resolve request.[[\acceptPromise]] with response.
  17. Set request.[[\state]] to "closed".

User aborts the payment request algorithm

The user aborts the payment request algorithm runs when the user aborts the payment request through the currently interactive user interface. It MUST queue a task on the user interaction task source to perform the following steps:

  1. Let request be the PaymentRequest object that the user is interacting with.
  2. If the request.[[\updating]] is true, then terminate this algorithm and take no further action. The user agent user interface SHOULD ensure that this never occurs.
  3. If request.[[\state]] is not "interactive", then terminate this algorithm and take no further action. The user agent user interface SHOULD ensure that this never occurs.
  4. Set request.[[\state]] to "closed".
  5. Set the user agent's payment request is showing boolean to false.
  6. Let error be an "AbortError" DOMException.
  7. Let response be request.[[\response]].
  8. If response is not null:
    1. Set response.[[\complete]] to true.
    2. Assert: response.[[\retryPromise]] is not null.
    3. Reject response.[[\retryPromise]] with error.
  9. Otherwise, reject request.[[\acceptPromise]] with error.

Update a PaymentRequest's details algorithm

The update a PaymentRequest's details algorithm takes a PaymentDetailsUpdate detailsPromise and a PaymentRequest request. The steps are conditional on the detailsPromise settling. If detailsPromise never settles then the payment request is blocked. The user agent SHOULD provide the user with a means to abort a payment request. Implementations MAY choose to implement a timeout for pending updates if detailsPromise doesn't settle in a reasonable amount of time. If an implementation chooses to implement a timeout, they MUST execute the steps listed below in the "upon rejection" path. Such a timeout is a fatal error for the payment request.

  1. Set request.[[\updating]] to true.
  2. In parallel, disable the user interface that allows the user to accept the payment request. This is to ensure that the payment is not accepted until the user interface is updated with any new details.
  3. Upon rejection of detailsPromise:
    1. Abort the update with request and an "AbortError" DOMException.
  4. Upon fulfillment of detailsPromise with value value:
    1. Let details be the result of converting value to a PaymentDetailsUpdate dictionary. If this throws an exception, abort the update with request and with the thrown exception.
    2. Let serializedModifierData be an empty list.
    3. Let selectedShippingOption be null.
    4. Let shippingOptions be an empty sequence<PaymentShippingOption>.
    5. Validate and canonicalize the details:
      1. If the total member of details is present, then:
        1. Check and canonicalize total amount details.total.amount. If an exception is thrown, then abort the update with request and that exception.
      2. If the displayItems member of details is present, then for each item in details.displayItems:
        1. Check and canonicalize amount item.amount. If an exception is thrown, then abort the update with request and that exception.
      3. If the shippingOptions member of details is present, and request.[[\options]].requestShipping is true, then:
        1. Let seenIDs be an empty set.
        2. For each option in details.shippingOptions:
          1. Check and canonicalize amount option.amount. If an exception is thrown, then abort the update with request and that exception.
          2. If seenIDs[option.id] exists, then abort the update with request and a TypeError.
          3. Append option.id to seenIDs.
          4. Append option to shippingOptions.
          5. If option.selected is true, then set selectedShippingOption to option.id.
      4. If the modifiers member of details is present, then:
        1. Let modifiers be the sequence details.modifiers.
        2. Let serializedModifierData be an empty list.
        3. For each PaymentDetailsModifier modifier in modifiers:
          1. Run the steps to validate a payment method identifier with modifier.supportedMethods. If it returns false, then abort the update with request and a RangeError exception. Optionally, inform the developer that the payment method identifier is invalid.
          2. If the total member of modifier is present, then:
            1. Check and canonicalize total amount modifier.total.amount. If an exception is thrown, then abort the update with request and that exception.
          3. If the additionalDisplayItems member of modifier is present, then for each PaymentItem item in modifier.additionalDisplayItems:
            1. Check and canonicalize amount item.amount. If an exception is thrown, then abort the update with request and that exception.
          4. If the data member of modifier is missing, let serializedData be null. Otherwise, let serializedData be the result of JSON-serializing modifier.data into a string. If JSON-serializing throws an exception, then abort the update with request and that exception.
          5. Add serializedData to serializedModifierData.
          6. Remove the data member of modifier, if it is present.
    6. Update the PaymentRequest using the new details:
      1. If the total member of details is present, then:
        1. Set request.[[\details]].total to details.total.
      2. If the displayItems member of details is present, then:
        1. Set request.[[\details]].displayItems to details.displayItems.
      3. If the shippingOptions member of details is present, and request.[[\options]].requestShipping is true, then:
        1. Set request.[[\details]].shippingOptions to shippingOptions.
        2. Set the value of request's shippingOption attribute to selectedShippingOption.
      4. If the modifiers member of details is present, then:
        1. Set request.[[\details]].modifiers to details.modifiers.
        2. Set request.[[\serializedModifierData]] to serializedModifierData.
      5. If request.[[\options]].requestShipping is true, and request.[[\details]].shippingOptions is empty, then the developer has signified that there are no valid shipping options for the currently-chosen shipping address (given by request's shippingAddress).

        In this case, the user agent SHOULD display an error indicating this, and MAY indicate that the currently-chosen shipping address is invalid in some way. The user agent SHOULD use the error member of details, if it is present, to give more information about why there are no valid shipping options for that address.

        Further, if details["shippingAddressErrors"] member is present, the user agent SHOULD display an error specifically for each erroneous field of the shipping address. This is done by matching each present member of the AddressErrors to a corresponding input field in the shown user interface.

        Similarly, if details["payerErrors"] member is present and request.[[\options]]'s requestPayerName, requestPayerEmail, or requestPayerPhone is true, then display an error specifically for each erroneous field.

        Likewise, if details["paymentMethodErrors"] is present, then display errors specifically for each erroneous input field for the particular payment method.

  5. Set request.[[\updating]] to false.
  6. Update the user interface based on any changed values in request. Re-enable user interface elements disabled prior to running this algorithm.

Abort the update

To abort the update with a PaymentRequest request and exception exception:

  1. Optionally, show an error message to the user when letting them know an error has occurred.
  2. Abort the current user interaction and close down any remaining user interface.
  3. Queue a task on the user interaction task source to perform the following steps:
    1. Set the user agent's payment request is showing boolean to false.
    2. Set request.[[\state]] to "closed".
    3. Let response be request.[[\response]].
    4. If response is not null, then:
      1. Set response.[[\complete]] to true.
      2. Assert: response.[[\retryPromise]] is not null.
      3. Reject response.[[\retryPromise]] with exception.
    5. Otherwise, reject request.[[\acceptPromise]] with exception.
    6. Set request.[[\updating]] to false.
  4. Abort the algorithm.

Abort the update runs when there is a fatal error updating the payment request, such as the supplied detailsPromise rejecting, or its fulfillment value containing invalid data. This would potentially leave the payment request in an inconsistent state since the developer hasn't successfully handled the change event.

Consequently, the PaymentRequest moves to a "closed" state. The error is signaled to the developer through the rejection of the [[\acceptPromise]], i.e., the promise returned by show().

Similarly, abort the update occurring during retry() causes the [[\retryPromise]] to reject, and the corresponding PaymentRequest's [[\complete]] internal slot will be set to true (i.e., it can no longer be used).

Validate merchant's details algorithm

The validate merchant's details algorithm takes a Promise opaqueDataPromise and a PaymentRequest request. The steps are conditional on the opaqueDataPromise settling. If opaqueDataPromise never settles then the payment request is blocked. The user agent SHOULD provide the user with a means to abort a payment request. Implementations MAY choose to implement a timeout for pending updates if opaqueDataPromise doesn't settle in a reasonable amount of time. If an implementation chooses to implement a timeout, they MUST execute the steps listed below in the "upon rejection" path. Such a timeout is a fatal error for the payment request.

  1. Set request.[[\updating]] to true.
  2. In parallel, disable the user interface that allows the user to accept the payment request. This is to ensure that the payment is not accepted until the user interface is updated with any new details.
  3. Upon rejection of opaqueDataPromise:
    1. Abort the update with request and an "AbortError" DOMException.
  4. Upon fulfillment of opaqueDataPromise with value opaqueData:
    1. Validate the merchant using opaqueData.
    2. If opaqueData is invalid, as per the validation rules of the payment handler, abort the update with request and an appropriate exception and return.
    3. Otherwise, set request.[[\updating]] to false.
    4. Enable the user interface, allowing the request for payment to proceed.

Privacy and Security Considerations

User Protections with show() method

To help ensure that users do not inadvertently share sensitive credentials with an origin, this API requires that PaymentRequest's show() method be triggered by user activation (e.g., via a click or press).

To avoid a confusing user experience, this specification limits the user agent to displaying one at a time via the show() method. In addition, the user agent can limit the rate at which a page can call show().

Secure contexts

The API defined in this specification is only exposed in secure contexts. In practice, this means that this API is only available over HTTPS. This is to limit the possibly of payment method data (e.g., credit card numbers) being sent in the clear.

Cross-origin payment requests

It is common for merchants and other payees to delegate checkout and other e-commerce activities to payment service providers through an iframe. This API supports payee-authorized cross-origin iframes through [[HTML]]'s allowpaymentrequest attribute.

Payment handlers have access to both the origin that hosts the iframe and the origin of the iframe content (where the PaymentRequest initiates).

Encryption of data fields

The PaymentRequest API does not directly support encryption of data fields. Individual payment methods may choose to include support for encrypted data but it is not mandatory that all payment methods support this.

How user agents match payment handlers

As part of show(), the user agent typically displays a list of matching payment handlers that satisfy the payment methods accepted by the merchant and other conditions. Matching can take into account payment method information provided as input to the API, information provided by the payment method owner, the payment handlers registered by the user, user preferences, and other considerations.

For security reasons, a user agent can limit matching (in show() and canMakePayment()) to payment handlers from the same origin as a URL payment method identifier.

Privacy Considerations

Exposing user information

The user agent MUST NOT share information about the user with a developer (e.g., the shipping address) without user consent.

One way that the API supports limited information sharing is through the "redactList" associated with the creation of physical addresses throughout the API. This feature enables user agents to provide the payee with enough information to compute shipping costs or tax information, while limiting the payee's ability to identify the payer via the address.

The user agent MUST NOT share the values of the displayItems member or additionalDisplayItems member with a third-party payment handler without user consent.

canMakePayment() protections

The canMakePayment() method enables the payee to call show() if the user is ready to take advantage of the API, or to fall back to a legacy checkout experience if not. Because this method shares some information with the payee, user agents are expected to protect the user from abuse of the method, for example, by restricting the number or frequency of calls.

Accessibility Considerations

For the user-facing aspects of Payment Request API, implementations integrate with platform accessibility APIs via form controls and other input modalities. Furthermore to increase the intelligibility of total, shipping addresses, and contact information, implementations format data according to system conventions.

Dependencies

This specification relies on several other underlying specifications.

ISO 3366-2
Country subdivision name and country subdivision code element are defined in [[ISO3166-2]].
Infra
The [[INFRA] specification defines how to strip leading and trailing ascii whitespace. It also defines the concept of a list and code point.
Payment Method Identifiers
The term payment method identifier is defined by [[payment-method-id]]. It's an unique identifier for a payment method.
HTML
The following are defined by [[HTML]]: EventHandler, queue a task, user interaction task source, top-level browsing context, current settings object, allowed to use, triggered by user activation, in parallel, the iframe element, and the allowpaymentrequest attribute.
ECMAScript
The terms Promise, internal slot, RangeError, TypeError, and JSON.stringify are defined by [[ECMASCRIPT]].

The term JSON-serialize applied to a given object means to run the algorithm specified by the original value of the JSON.stringify function on the supplied object, passing the supplied object as the sole argument, and return the resulting string. This can throw an exception.

Writing Promise-Using Specifications
The terms a new promise, a promise rejected with r, upon fulfillment and upon rejection are defined by [[PROMISES-GUIDE]].
DOM
The Event interface, the EventTarget interface, the EventInit dictionary, and the terms fire an event, dispatch flag, stop propagation flag, isTrusted attribute, context object, and stop immediate propagation flag are defined by [[DOM]].
Web IDL

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: "AbortError", "InvalidStateError", "NotAllowedError", "NotSupportedError", and "SecurityError".

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

Although this specification is primarily targeted at web browsers, it is feasible that other software could also implement this specification in a conforming manner.

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.

Acknowledgements

This specification was derived from a report published previously by the Web Platform Incubator Community Group.