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.
In September 2022 the Web Payments Working Group published a Payment Request Recommendation. Following privacy and internationalization reviews, the Recommendation excluded capabilities related to billing and shipping addresses. However, implementations have continued to support those features interoperably, and so the Working Group has decided to try to re-align the specification with implementations, and re-engage the community on associated issues.
This document is a Candidate Recommendation Snapshot based on the text of the original Recommendation. A subsequent Candidate Recommendation Draft will add back address capabilities and a small number of other changes made since publication of the Recommendation.
As part of adding back support for addresses, this specification now refers to the address components defined in the Contact Picker API rather than define those components itself. Indeed, the Contact Picker API is derived from the original definitions found in Payment Request API, and pulled out of the specification because addresses are useful on the Web beyond payments.
The Working Group plans to engage in discussion and follow the usual review process before advancing the specification to Proposed Recommendation status.
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).
IntroductionThis specification describes an API that allows user agents (e.g., browsers) to act as an intermediary between three parties in a transaction:
A payment method defines:
The details of how to fulfill a payment request for a given payment method is an implementation detail of a payment handler, which is an application or service that handles requests for payment. Concretely, a payment handler defines:
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 and scopeThe following are out of scope for this specification:
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 {{PaymentRequest/show()}} method. The {{PaymentRequest/show()}} returns a promise that, once the user confirms request for payment, results in a {{PaymentResponse}}.
Declaring multiple ways of payingWhen constructing a new {{PaymentRequest}}, a merchant uses the first argument (|methodData|) to list the different ways a user can pay for things (e.g., credit cards, Apple Pay, Google Pay, etc.). More specifically, the |methodData| sequence contains PaymentMethodData dictionaries containing the payment method identifiers for the payment methods that the merchant accepts and any associated payment method specific data (e.g., which credit card networks are supported).
const methodData = [ { supportedMethods: "https://example.com/payitforward", data: { payItForwardField: "ABC", }, }, { supportedMethods: "https://example.com/bobpay", data: { merchantIdentifier: "XXXX", bobPaySpecificField: true, }, }, ];Describing what is being paid for
When constructing a new {{PaymentRequest}}, a merchant uses the second argument of the constructor (|details|) to provide the details of the transaction that the user is being asked to complete. This includes the total of the order and, optionally, some line items that can provide a detailed breakdown of what is being paid for.
const details = { id: "super-store-order-123-12312", displayItems: [ { label: "Sub-total", amount: { currency: "GBP", value: "55.00" }, }, { label: "Value-Added Tax (VAT)", amount: { currency: "GBP", value: "5.00" }, }, ], total: { label: "Total due", // The total is GBP£65.00 here because we need to // add shipping (below). The selected shipping // costs GBP£5.00. amount: { currency: "GBP", value: "65.00" }, }, };Adding shipping options
Here we see an example of how to add two shipping options to the |details|.
const shippingOptions = [ { id: "standard", // Shipping by truck, 2 days label: "🚛 Envío por camión (2 dias)", amount: { currency: "EUR", value: "5.00" }, selected: true, }, { id: "drone", // Drone shipping, 2 hours label: "🚀 Drone Express (2 horas)", amount: { currency: "EUR", value: "25.00" } }, ]; Object.assign(details, { shippingOptions });Conditional modifications to payment request
Here we see how to add a processing fee for using a card on a particular network. Notice that it requires recalculating the total.
// Certain cards incur a $3.00 processing fee. const cardFee = { label: "Card processing fee", amount: { currency: "AUD", value: "3.00" }, }; // Modifiers apply when the user chooses to pay with // a card. const modifiers = [ { additionalDisplayItems: [cardFee], supportedMethods: "https://example.com/cardpay", total: { label: "Total due", amount: { currency: "AUD", value: "68.00" }, }, data: { supportedNetworks: networks, }, }, ]; Object.assign(details, { modifiers });Requesting specific information from the end user
Some financial transactions require a user to provide specific information in order for a merchant to fulfill a purchase (e.g., the user's shipping address, in case a physical good needs to be shipped). To request this information, a merchant can pass a third optional argument (|options:PaymentOptions |) to the {{PaymentRequest}} constructor indicating what information they require. When the payment request is shown, the user agent will request this information from the end user and return it to the merchant when the user accepts the payment request.
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 { const errors = await checkAllValuesAreGood(response); if (errors.length) { await response.retry(errors); return validateResponse(response); } await response.complete("success"); } catch (err) { // Something went wrong... await response.complete("fail"); } } // Must be called as a result of a click // or some explicit user action. 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 { shippingAddress } = request; await ensureCanShipTo(shippingAddress); const { shippingOptions, total } = await calculateShipping(shippingAddress); return { shippingOptions, total }; } catch (err) { // Shows error to user in the payment sheet. return { error: `Sorry! we can't ship to your address.` }; } }Fine-grained error reporting
A developer can use the {{PaymentDetailsUpdate/shippingAddressErrors}} member of the {{PaymentDetailsUpdate}} dictionary to indicate that there are validation errors with specific attributes of a {{ContactAddress}}. The {{PaymentDetailsUpdate/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}} can use the [=default toJSON steps=] (i.e., `.toJSON()`) to serializes the object directly into JSON. This makes it trivial to POST the resulting JSON back to a server using the [[[fetch]]]:
async function doPaymentRequest() { const payRequest = new PaymentRequest(methodData, details); 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();Using with cross-origin iframes
To indicate that a cross-origin [^iframe^] is allowed to invoke the payment request API, the [^iframe/allow^] attribute along with the "payment" keyword can be specified on the [^iframe^] element.
<iframe src="https://cross-origin.example" allow="payment"> </iframe>
If the [^iframe^] will be navigated across multiple origins that support the Payment Request API, then one can set [^iframe/allow^] to `"payment *"`. The [[[permissions-policy]]] specification provides further details and examples.
PaymentRequest interface[SecureContext, Exposed=Window] interface PaymentRequest : EventTarget { constructor( sequence<PaymentMethodData> methodData, PaymentDetailsInit details, optional PaymentOptions options = {} ); [NewObject] Promise<PaymentResponse> show(optional Promise<PaymentDetailsUpdate> detailsPromise); [NewObject] Promise<undefined> abort(); [NewObject] Promise<boolean> canMakePayment(); readonly attribute DOMString id; readonly attribute ContactAddress? shippingAddress; readonly attribute DOMString? shippingOption; readonly attribute PaymentShippingType? shippingType; 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 {{PaymentRequest/shippingAddress}}, {{PaymentRequest/shippingOption}}, and {{PaymentRequest/shippingType}} attributes are populated during processing if the {{PaymentOptions/requestShipping}} member is set.
A |request|'s payment-relevant browsing context is that {{PaymentRequest}}'s [=relevant global object=]'s browsing context's top-level browsing context. Every payment-relevant browsing context has a payment request is showing boolean, which prevents showing more than one payment UI at a time.
The payment request is showing boolean simply prevents more than one payment UI being shown in a single browser tab. However, a payment handler can restrict the user agent to showing only one payment UI across all browser windows and tabs. Other payment handlers might allow showing a payment UI across disparate browser tabs.
ConstructorThe {{PaymentRequest}} is constructed using the supplied sequence of PaymentMethodData |methodData| including any payment method specific {{PaymentMethodData/data}}, the PaymentDetailsInit |details|, and the {{PaymentOptions}} |options|.
The PaymentRequest(|methodData|, |details|, |options|)
constructor MUST act as follows:
Let |idl| be the result of [=converted to an IDL value|converting=] |object| to an IDL value of the [=Payment Method/additional data type=]. Rethrow any exceptions.
Run the steps to validate payment method data, if any, from the specification that defines the |paymentMethod|.{{PaymentMethodData/supportedMethods}} on |object|. Rethrow any exceptions.
These step assures that any IDL type conversion and validation errors are caught as early as possible.
sequence
<{{PaymentShippingOption}}>.sequence
<{{PaymentDetailsModifier}}>.When getting, the {{PaymentRequest/id}} attribute returns this {{PaymentRequest}}'s {{PaymentRequest/[[details]]}}.{{PaymentDetailsInit/id}}.
For auditing and reconciliation purposes, a merchant can associate a unique identifier for each transaction with the {{PaymentDetailsInit/id}} attribute.
show() methodThe {{PaymentRequest/show()}} method is called when a developer wants to begin user interaction for the payment request. The {{PaymentRequest/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 {{PaymentRequest/show()}} method returns.
Each payment handler controls what happens when multiple browsing context simultaneously call the {{PaymentRequest/show()}} method. For instance, some payment handlers will allow multiple payment UIs to be shown in different browser tabs/windows. Other payment handlers might only allow a single payment UI to be shown for the entire user agent.
The show(optional |detailsPromise|)
method MUST act as follows:
This allows the user agent to not require user activation, for example to support redirect flows where a user activation may not be present upon redirect. See for security considerations.
See also issue #1022 for discussion around providing more guidance in the specification on when user agents should or should not require a user activation for {{PaymentRequest/show()}}.
Optionally, if the user agent wishes to disallow the call to {{PaymentRequest/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 {{PaymentRequest/show()}}, as described in section .
Optionally:
This allows the user agent to act as if the user had immediately [=user aborts the payment request|aborted the payment request=], at its discretion. For example, in "private browsing" modes or similar, user agents might take advantage of this step.
Present a user interface that will allow the user to interact with the |handlers|. The user agent SHOULD prioritize the user's preference when presenting payment methods. The user interface SHOULD be presented using the language and locale-based formatting that matches the |document|'s [=document element|document element's=] [=Node/language=], if any, or an appropriate fallback if that is not available.
The API does not currently provide a way for developers to specify the language and base direction in which the payment sheet is presented to end users. Instead, the API relies on localization information inherited from the document.
PaymentRequest
's details algorithm with |detailsPromise|, |request|, and null.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.
Pass the [=converted to an IDL value|converted=] second element in the |paymentMethod| tuple and |modifiers|. 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 other [=internal slots=] of |request| (some MAY be excluded for privacy reasons where appropriate).
Handling of multiple applicable modifiers in the {{PaymentRequest/[[serializedModifierData]]}} [=internal slot=] is payment handler specific and beyond the scope of this specification. Nevertheless, it is RECOMMENDED that payment handlers use a "last one wins" approach with items in the {{PaymentRequest/[[serializedModifierData]]}} list: that is to say, an item at the end of the list always takes precedence over any item at the beginning of the list (see example below).
This example demonstrates precedence order of {{PaymentRequest/[[serializedModifierData]]}}. The first modifier applies equally to all cards, irrespective of network. The second modifier applies specifically to cards on the "coolcard" network.
const details = { total: { label: "Total due", amount: { currency: "USD", value: "50.00" }, }, }; // All cards incur a $3.00 processing fee. const cardFee = { label: "Card processing fee", amount: { currency: "USD", value: "3.00" }, }; // But coolcard incurs a $1.00 processing fee. const coolCardFee = { label: "Coolcard processing fee", amount: { currency: "USD", value: "1.00" }, }; // Modifiers apply when the user chooses to pay with // a credit card. details.modifiers = [ // Applies to all cards... { additionalDisplayItems: [cardFee], supportedMethods: "https://example.com/cardpay", total: { label: "Total due", amount: { currency: "USD", value: "53.00" }, }, data: { supportedNetworks: [], // All networks }, }, // Applies only to cool cards... { additionalDisplayItems: [coolCardFee], supportedMethods: "https://example.com/cardpay", total: { label: "Total due", amount: { currency: "USD", value: "51.00" }, }, data: { supportedNetworks: ["coolcard"], // coolcard network only }, }, ];
If the modifiers array in the example above was to be reversed (i.e., supportedNetworks: []
was to come last in the modifiers list), then it would take precedence over the "coolcard" modifier even though the coolcard modifier matches cards more specifically. This is because "last one wins".
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 [=Document/fully active=] while the user interface is being shown, or no longer is by the time this step is reached, then:
The {{PaymentRequest/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 {{PaymentRequest/abort()}} can only be called after the {{PaymentRequest/show()}} method has been called (see [=PaymentRequest/states=]) and before this instance's {{PaymentRequest/[[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, {{PaymentRequest/abort()}} will reject the returned {{Promise}}.
See also the algorithm when the user aborts the payment request.
The {{PaymentRequest/abort()}} method MUST act as follows:
The {{PaymentRequest/canMakePayment()}} method can be used by the developer to determine if the user agent has support for one of the desired payment methods. See [[[#canmakepayment-protections]]].
A true result from {{PaymentRequest/canMakePayment()}} does not imply that the user has a provisioned instrument ready for payment.
The {{PaymentRequest/canMakePayment()}} method MUST run the can make payment algorithm.
shippingAddress attributeA {{PaymentRequest}}'s {{PaymentRequest/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 attributeA {{PaymentRequest}}'s {{PaymentRequest/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 [=PaymentRequest.PaymentRequest()|construction=] (see {{PaymentOptions}}'s {{PaymentOptions/shippingType}} member).
onshippingaddresschange attributeA {{PaymentRequest}}'s {{PaymentRequest/onshippingaddresschange}} attribute is an {{EventHandler}} for a {{PaymentRequestUpdateEvent}} named shippingaddresschange.
shippingOption attributeA {{PaymentRequest}}'s {{PaymentRequest/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 attributeA {{PaymentRequest}}'s {{PaymentRequest/onshippingoptionchange}} attribute is an {{EventHandler}} for a {{PaymentRequestUpdateEvent}} named shippingoptionchange.
onpaymentmethodchange attributeA {{PaymentRequest}}'s {{PaymentRequest/onpaymentmethodchange}} attribute is an {{EventHandler}} for a {{PaymentMethodChangeEvent}} named "paymentmethodchange".
Internal SlotsInstances of {{PaymentRequest}} are created with the [=internal slots=] in the following table:
Internal Slot Description (non-normative) [[\serializedMethodData]] ThemethodData
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 {{PaymentDetailsModifier/data}} member for each corresponding item in the sequence {{PaymentRequest/[[details]]}}.{{PaymentDetailsBase/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 {{PaymentRequestUpdateEvent/updateWith()}}. Note that all {{PaymentDetailsModifier/data}} members of {{PaymentDetailsModifier}} instances contained in the {{PaymentDetailsBase/modifiers}} member will be removed, as they are instead stored in serialized form in the {{PaymentRequest/[[serializedModifierData]]}} [=internal slot=]. [[\options]] The {{PaymentOptions}} supplied to the constructor. [[\state]]
The current state of the payment request, which transitions from:
The [=PaymentRequest/state=] transitions are illustrated in the figure below:
The constructor sets the initial [=PaymentRequest/state=] to "[=PaymentRequest/created=]". The {{PaymentRequest/show()}} method changes the [=PaymentRequest/state=] to "[=PaymentRequest/interactive=]". From there, the {{PaymentRequest/abort()}} method or any other error can send the [=PaymentRequest/state=] to "[=PaymentRequest/closed=]"; similarly, the user accepts the payment request algorithm and user aborts the payment request algorithm will change the [=PaymentRequest/state=] to "[=PaymentRequest/closed=]". [[\updating]] True if there is a pending {{PaymentRequestUpdateEvent/updateWith()}} call to update the payment request and false otherwise. [[\acceptPromise]] The pending {{Promise}} created during {{PaymentRequest/show()}} that will be resolved if the user accepts the payment request. [[\response]] Null, or the {{PaymentResponse}} instantiated by this {{PaymentRequest}}. [[\handler]] The Payment Handler associated with this {{PaymentRequest}}. Initialized to `null`. PaymentMethodData dictionarydictionary 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.
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.
dictionary PaymentCurrencyAmount { required DOMString currency; required DOMString value; };
A {{PaymentCurrencyAmount}} dictionary is used to supply monetary amounts.
An [[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.
When displaying a monetary value, it is RECOMMENDED that user agents display the currency code, but it's OPTIONAL for user agents to display a currency symbol. This is because currency symbols can be ambiguous due to use across a number of different currencies (e.g., "$" could mean any of USD, AUD, NZD, CAD, and so on.).
User agents MAY format the display of the {{PaymentCurrencyAmount/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 U+0024 Dollar Sign ($), "GBP" is shown as U+00A3 Pound Sign (£), "PLN" is shown as U+007A U+0142 Złoty (zł), and the non-standard "XBT" could be shown as U+0243 Latin Capital Letter B with Stroke (Ƀ)).
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.
{ "currency": "OMR", "value": "1.234" }Validity checkers
A [=JavaScript string=] is a valid decimal monetary value if it consists of the following [=code points=] in the given order:
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:
To check and canonicalize total amount given a {{PaymentCurrencyAmount}} |amount:PaymentCurrencyAmount|, run the following steps:
The algorithm does not alter or canonicalize the |amount|.{{PaymentCurrencyAmount/value}}. For example, a user agent will not change "55" into "55.00". Payment handlers need to be prepared to deal with such values.
Payment details dictionaries PaymentDetailsBase dictionarydictionary PaymentDetailsBase { sequence<PaymentItem> displayItems; sequence<PaymentShippingOption> shippingOptions; sequence<PaymentDetailsModifier> modifiers; };
A sequence containing the different shipping options for the user to choose from.
If an item in the sequence has the {{PaymentShippingOption/selected}} member set to true, then this is the shipping option that will be used by default and {{PaymentRequest/shippingOption}} will be set to the {{PaymentShippingOption/id}} of this option without running the shipping option changed algorithm. If more than one item in the sequence has {{PaymentShippingOption/selected}} set to true, then the user agent selects the last one in the sequence.
The {{PaymentDetailsBase/shippingOptions}} member is only used if the {{PaymentRequest}} was constructed with {{PaymentOptions}} and {{PaymentOptions/requestShipping}} set to true.
If the sequence has an item with the {{PaymentShippingOption/selected}} member set to true, then authors are responsible for ensuring that the {{PaymentDetailsInit/total}} member includes the cost of the shipping option. This is because no shippingoptionchange event will be fired for this option unless the user selects an alternative option first.dictionary PaymentDetailsInit : PaymentDetailsBase { DOMString id; required PaymentItem total; };The PaymentDetailsInit dictionary is used in the construction of the payment request.
In addition to the members inherited from the {{PaymentDetailsBase}} dictionary, the following members are part of the PaymentDetailsInit 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 {{PaymentRequestUpdateEvent/updateWith()}}.
In addition to the members inherited from the {{PaymentDetailsBase}} dictionary, the following members are part of the {{PaymentDetailsUpdate}} dictionary:
Algorithms in this specification that accept a {{PaymentDetailsUpdate}} dictionary will throw if the {{PaymentDetailsUpdate/total}}.{{PaymentItem/amount}}.{{PaymentCurrencyAmount/value}} is a negative number.
Payment method specific errors.
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:
It is the developer's responsibility to verify that the {{PaymentDetailsModifier/total}} amount is the sum of the {{PaymentDetailsBase/displayItems}} and the {{PaymentDetailsModifier/additionalDisplayItems}}.
enum PaymentShippingType { "shipping", "delivery", "pickup" };
dictionary PaymentOptions { boolean requestPayerName = false; boolean requestBillingAddress = 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.
The {{PaymentOptions/shippingType}} member only affects the user interface for the payment request.
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.
The language and direction of the {{PaymentItem/label}} may often be determined from information inherited from the document. However, this approach may not suffice for some use cases. The working group intends to fix this in a future version by aligning with general approaches for the Web that are in development.
dictionary PaymentCompleteDetails { object? data = null; };
The {{PaymentCompleteDetails}} dictionary provides additional information from the merchant website to the payment handler when the payment request completes.
The {{PaymentCompleteDetails}} dictionary contains the following members:
enum PaymentComplete { "fail", "success", "unknown" };
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 {{PaymentRequestUpdateEvent/updateWith()}} method in response to a change event.
[SecureContext, Exposed=Window] interface PaymentResponse : EventTarget { [Default] object toJSON(); readonly attribute DOMString requestId; readonly attribute DOMString methodName; readonly attribute object details; readonly attribute ContactAddress? shippingAddress; readonly attribute DOMString? shippingOption; readonly attribute DOMString? payerName; readonly attribute DOMString? payerEmail; readonly attribute DOMString? payerPhone; [NewObject] Promise<undefined> complete( optional PaymentComplete result = "unknown", optional PaymentCompleteDetails details = {} ); [NewObject] Promise<undefined> 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() methodIf a {{PaymentResponse}} is found to be erroneous (e.g., a payment instrument has expired or shipping information is invalid), the {{PaymentResponse/retry()}} method affords the end user the ability to fix input errors and try to get the merchant to processed the payment again. The passed {{PaymentValidationErrors}} serve as hints as to where input errors have occurred in the {{PaymentResponse}}, which the end user needs to correct.
However, an end user may decide, upon inspection of the {{PaymentValidationErrors}}, to provide an entirely new set of values for the {{PaymentResponse}}. For example, the user might switch to a an entirely different payment instrument and/or provide an entirely different shipping address.
As such, merchants need to be prepared to completely revalidate a {{PaymentResponse}} once the {{PaymentResponse/[[retryPromise]]}} settles.
Lastly, as a {{PaymentResponse}} is inherently tied to a particular [=payment handler=] via a {{PaymentRequest}}, it is not possible for the end user to switch to a different [=payment handler=] during {{PaymentResponse/retry()}}.
The retry(|errorFields:PaymentValidationErrors|)
method MUST act as follows:
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.
dictionary PaymentValidationErrors { PayerErrors payer; AddressErrors shippingAddress; DOMString error; object paymentMethod; };
The language and direction of the {{PaymentValidationErrors/error}} may often be determined from information inherited from the document. However, this approach may not suffice for some use cases. The working group intends to fix this in a future version by aligning with general approaches for the Web that are in development.
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.
const payer = { email: "The domain is invalid.", phone: "Unknown country code.", name: "Not in database.", }; await response.retry({ payer });methodName attribute
The payment method identifier for the payment method that the user selected to fulfill the transaction.
details attributeAn {{object}} or dictionary generated by a payment method that a merchant can use to process or validate a transaction (depending on the payment method).
Each standardized payment method identifier defines its own unique IDL dictionary for use with the details attribute. The shape of this data (i.e., its members and their corresponding types and formats) differs depending on which standardized payment method identifier is selected by the end user.
Similarly, a URL-based payment method identifier defines the shape of details. However, as URL-based payment method identifiers are not standardized by the W3C, developers need to consult whoever controls the URL for the expected shape of the details object.
shippingAddress attributeIf the {{PaymentOptions/requestShipping}} member was set to true in the {{PaymentOptions}} passed to the {{PaymentRequest}} constructor, then {{PaymentRequest/shippingAddress}} will be the full and final [=shipping address=] chosen by the user.
shippingOption attributeIf the {{PaymentOptions/requestShipping}} member was set to true in the {{PaymentOptions}} passed to the {{PaymentRequest}} constructor, then {{PaymentRequest/shippingOption}} will be the {{PaymentShippingOption/id}} attribute of the selected shipping option.
payerName attributeIf the {{PaymentOptions/requestPayerName}} member was set to true in the {{PaymentOptions}} passed to the {{PaymentRequest}} constructor, then {{PaymentResponse/payerName}} will be the name provided by the user.
payerEmail attributeIf the {{PaymentOptions/requestPayerEmail}} member was set to true in the {{PaymentOptions}} passed to the {{PaymentRequest}} constructor, then {{PaymentResponse/payerEmail}} will be the email address chosen by the user.
payerPhone attributeIf the {{PaymentOptions/requestPayerPhone}} member was set to true in the {{PaymentOptions}} passed to the {{PaymentRequest}} constructor, then {{PaymentResponse/payerPhone}} will be the phone number chosen by the user.
requestId attributeThe corresponding payment request {{PaymentRequest/id}} that spawned this payment response.
complete() methodThe {{PaymentResponse/complete()}} method is called after the user has accepted the payment request and the {{PaymentRequest/[[acceptPromise]]}} has been resolved. Calling the {{PaymentResponse/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 {{PaymentResponse/complete()}}, the payment request user interface remains in a pending state. At this point the user interface SHOULD NOT offer a cancel command because acceptance of the payment request has been returned. However, if something goes wrong and the developer never calls {{PaymentResponse/complete()}} then the user interface is blocked.
For this reason, implementations MAY impose a timeout for developers to call {{PaymentResponse/complete()}}. If the timeout expires then the implementation will behave as if {{PaymentResponse/complete()}} was called with no arguments.
The {{PaymentResponse/complete()}} method MUST act as follows:
The steps above assures that errors that could result from IDL type conversion and/or validation are caught as early as possible, giving the developer an opportunity to recover.
Allows a developer to handle "payerdetailchange" events.
Internal SlotsInstances 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., {{PaymentResponse/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. Shipping and billing addressesThe {{PaymentRequest}} interface allows a merchant to request from the user [=physical address|physical addresses=] for the purposes of shipping and/or billing. A shipping address and billing address are [=physical address|physical addresses=].
AddressErrors dictionarydictionary AddressErrors { DOMString addressLine; DOMString city; DOMString country; DOMString dependentLocality; DOMString organization; DOMString phone; DOMString postalCode; DOMString recipient; DOMString region; 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 not to ask the user to fix things they might not have control over.
This specification defines a [=policy-controlled feature=] identified by the string "payment" [[permissions-policy]]. Its [=policy-controlled feature/default allowlist=] is [=default allowlist/'self'=].
A document’s [=Document/permissions policy=] determines whether any content in that document is allowed to construct {{PaymentRequest}} instances. If disabled in any document, no content in the document will be allowed to use the {{PaymentRequest}} constructor (trying to create an instance will throw).
Events Summary Event name Interface Dispatched when… Targetshippingaddresschange
{{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}} PaymentMethodChangeEvent interface
[SecureContext, Exposed=Window] interface PaymentMethodChangeEvent : PaymentRequestUpdateEvent { constructor(DOMString type, optional PaymentMethodChangeEventInit eventInitDict = {}); readonly attribute DOMString methodName; readonly attribute object? methodDetails; };methodDetails attribute
When getting, returns the value it was initialized with. See {{PaymentMethodChangeEventInit/methodDetails}} member of {{PaymentMethodChangeEventInit}} for more information.
methodName attributeWhen getting, returns the value it was initialized with. See {{PaymentMethodChangeEventInit/methodName}} member of {{PaymentMethodChangeEventInit}} for more information.
PaymentMethodChangeEventInit dictionarydictionary PaymentMethodChangeEventInit : PaymentRequestUpdateEventInit { DOMString methodName = ""; object? methodDetails = null; };
[SecureContext, Exposed=Window] interface PaymentRequestUpdateEvent : Event { constructor(DOMString type, optional PaymentRequestUpdateEventInit eventInitDict = {}); undefined updateWith(Promise<PaymentDetailsUpdate> detailsPromise); };
The {{PaymentRequestUpdateEvent}} enables developers to update the details of the payment request in response to a user interaction.
ConstructorThe {{PaymentRequestUpdateEvent}}'s {{PaymentRequestUpdateEvent/constructor(type, eventInitDict)}} MUST act as follows:
If a developer wants to update the payment request, then they need to call {{PaymentRequestUpdateEvent/updateWith()}} and provide a {{PaymentDetailsUpdate}} dictionary, or a promise for one, containing changed values that the user agent presents to the user.
To prevent the user interface from blocking (and to reflect changes made by the end user through the UI), developers need to immediately call {{PaymentRequestUpdateEvent/updateWith()}}.
// ❌ Bad - this won't work! request.onshippingaddresschange = async ev => { // await goes to next tick, and updateWith() // was not called. const details = await getNewDetails(oldDetails); // 💥 So it's now too late! updateWith() // throws "InvalidStateError". ev.updateWith(details); }; // ✅ Good - UI will wait. request.onshippingaddresschange = ev => { // Calling updateWith() with a promise is ok 👍 const promiseForNewDetails = getNewDetails(oldDetails); ev.updateWith(promiseForNewDetails); };
Additionally, {{PaymentRequestUpdateEvent/[[waitForUpdate]]}} prevents reuse of {{PaymentRequestUpdateEvent}}.
// ❌ Bad - calling updateWith() twice doesn't work! request.addEventListener("shippingaddresschange", ev => { ev.updateWith(details); // this is ok. // 💥 [[waitForUpdate]] is true, throws "InvalidStateError". ev.updateWith(otherDetails); }); // ❌ Bad - this won't work either! request.addEventListener("shippingaddresschange", async ev => { const p = Promise.resolve({ ...details }); ev.updateWith(p); await p; // 💥 Only one call to updateWith() is allowed, // so the following throws "InvalidStateError" ev.updateWith({ ...newDetails }); });
The {{PaymentRequestUpdateEvent/updateWith()}} with |detailsPromise:Promise| method MUST act as follows:
PaymentRequest
's details algorithm with |detailsPromise|, |request|, and |pmi|.Instances of {{PaymentRequestUpdateEvent}} are created with the [=internal slots=] in the following table:
Internal Slot Description (non-normative) [[\waitForUpdate]] A boolean indicating whether an {{PaymentRequestUpdateEvent/updateWith()}}-initiated update is currently in progress. PaymentRequestUpdateEventInit dictionarydictionary PaymentRequestUpdateEventInit : EventInit {};Algorithms
When the [=internal slot=] {{PaymentRequest/[[state]]}} of a {{PaymentRequest}} object is set to "[=PaymentRequest/interactive=]", the user agent will trigger the following algorithms based on user interaction.
Can make payment algorithmThe can make payment algorithm checks if the user agent supports making payment with the payment methods with which the {{PaymentRequest}} was constructed.
This allows user agents to apply heuristics to detect and prevent abuse of the calling method for fingerprinting purposes, such as creating {{PaymentRequest}} objects with a variety of supported payment methods and triggering the can make payment algorithm 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.
The shipping address changed algorithm runs when the user provides a new shipping address. It MUST run the following steps:
The |redactList| limits the amount of personal information about the recipient that the API shares with the merchant.
For merchants, the resulting {{ContactAddress}} 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.
The shipping option changed algorithm runs when the user chooses a new shipping option. It MUST run the following steps:
id
string of the {{PaymentShippingOption}} provided by the user.A payment handler MAY run the payment method changed algorithm when the user changes payment method with |methodDetails|, which is a 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.
When the user selects or changes a payment method (e.g., a credit card), the {{PaymentMethodChangeEvent}} includes redacted billing address information for the purpose of performing tax calculations. Redacted attributes include, but are not limited to, [=physical address/address line=], [=physical address/dependent locality=], [=physical address/organization=], [=physical address/phone number=], and [=physical address/recipient=].
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|:
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:
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:
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:
PaymentRequest
's details algorithm
The update a PaymentRequest
's details algorithm takes a {{PaymentDetailsUpdate}} |detailsPromise|, a {{PaymentRequest}} |request|, and |pmi| that is either a DOMString or null (a payment method identifier). 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.
In the case where a timeout occurs, or the user manually aborts, or the payment handler decides to abort this particular payment, the user agent MUST run the user aborts the payment request algorithm.
sequence
<{{PaymentShippingOption}}>.If |request|.{{PaymentRequest/[[options]]}}.{{PaymentOptions/requestShipping}} is true, and |request|.{{PaymentRequest/[[details]]}}.{{PaymentDetailsBase/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 {{PaymentRequest/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 {{PaymentDetailsUpdate/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|["{{PaymentDetailsUpdate/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|.{{PaymentRequest/[[options]]}}'s {{PaymentOptions/requestPayerName}}, {{PaymentOptions/requestPayerEmail}}, or {{PaymentOptions/requestPayerPhone}} is true, then display an error specifically for each erroneous field.
Likewise, if |details|.{{PaymentDetailsUpdate/paymentMethodErrors}} is present, then display errors specifically for each erroneous input field for the particular payment method.
To abort the update with a {{PaymentRequest}} |request| and exception |exception|:
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 "[=PaymentRequest/closed=]" state. The error is signaled to the developer through the rejection of the {{PaymentRequest/[[acceptPromise]]}}, i.e., the promise returned by {{PaymentRequest/show()}}.
Similarly, abort the update occurring during {{PaymentResponse/retry()}} causes the {{PaymentResponse/[[retryPromise]]}} to reject, and the corresponding {{PaymentResponse}}'s {{PaymentResponse/[[complete]]}} [=internal slot=] will be set to true (i.e., it can no longer be used).
Privacy and Security Considerations User protections withshow()
method
To help ensure that users do not inadvertently share sensitive credentials with an origin, this API requires that PaymentRequest's {{PaymentRequest/show()}} method be invoked while the relevant {{Window}} has [=transient 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 {{PaymentRequest/show()}} method. In addition, the user agent can limit the rate at which a page can call {{PaymentRequest/show()}}.
Secure contextsThe API defined in this specification is only exposed in a [=secure context=] - see also the [[[secure-contexts]]] specification for more details. In practice, this means that this API is only available over HTTPS. This is to limit the possibility of payment method data (e.g., credit card numbers) being sent in the clear.
Cross-origin payment requestsIt 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 [^iframe/allow^] 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 fieldsThe {{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 handlersFor security reasons, a user agent can limit matching (in {{PaymentRequest/show()}} and {{PaymentRequest/canMakePayment()}}) to payment handlers from the same origin as a URL payment method identifier.
Data usagePayment method owners establish the privacy policies for how user data collected for the payment method may be used. Payment Request API sets a clear expectation that data will be used for the purposes of completing a transaction, and user experiences associated with this API convey that intention. It is the responsibility of the payee to ensure that any data usage conforms to payment method policies. For any permitted usage beyond completion of the transaction, the payee should clearly communicate that usage to the user.
Exposing user informationThe user agent MUST NOT share information about the user with a developer (e.g., the [=shipping address=]) without user consent.
In particular, the {{PaymentMethodData}}'s {{PaymentMethodData/data}} and {{PaymentResponse}}'s {{PaymentResponse/details}} members allow for the arbitrary exchange of data. In light of the wide range of data models used by existing payment methods, prescribing data specifics in this API would limit its usefulness. The {{PaymentResponse/details}} member carries data from the payment handler, whether Web-based (as defined by the [[[payment-handler]]]) or proprietary. The [=user agent=] MUST NOT support payment handlers unless they include adequate user consent mechanisms (such as awareness of parties to the transaction and mechanisms for demonstrating the intention to share data).
The user agent MUST NOT share the values of the {{PaymentDetailsBase/displayItems}} member or {{PaymentDetailsModifier/additionalDisplayItems}} member for any purpose other than to facilitate completion of the transaction.
The {{PaymentMethodChangeEvent}} enables the payee to update the displayed total based on information specific to a selected payment method. For example, the billing address associated with a selected payment method might affect the tax computation (e.g., VAT), and it is desirable that the user interface accurately display the total before the payer completes the transaction. At the same time, it is desirable to share as little information as possible prior to completion of the payment. Therefore, when a payment method defines the steps for when a user changes payment method, it is important to minimize the data shared via the {{PaymentMethodChangeEvent}}'s {{PaymentMethodChangeEvent/methodDetails}} attribute. Requirements and approaches for minimizing shared data are likely to vary by payment method and might include:
Where sharing of privacy-sensitive information might not be obvious to users (e.g., when [=payment handler/payment method changed algorithm | changing payment methods =]), it is RECOMMENDED that user agents inform the user of exactly what information is being shared with a merchant.
canMakePayment()
protections
The {{PaymentRequest/canMakePayment()}} method provides feature detection for different payment methods. It may become a fingerprinting vector if in the future, a large number of payment methods are available. User agents are expected to protect the user from abuse of the method. For example, user agents can reduce user fingerprinting by:
For rate-limiting the user agent might look at repeated calls from:
These rate-limiting techniques intend to increase the cost associated with repeated calls, whether it is the cost of managing multiple [=host/registrable domains=] or the user experience friction of opening multiple windows (tabs or pop-ups).
User activation requirementIf the user agent does not require user activation as part of the {{PaymentRequest/show()}} method, some additional security mitigations should be considered. Not requiring user activation increases the risk of spam and click-jacking attacks, by allowing a Payment Request UI to be initiated without the user interacting with the page immediately beforehand.
In order to mitigate spam, the user agent may decide to enforce a user activation requirement after some threshold, for example after the user has already been shown a Payment Request UI without a user activation on the current page. In order to mitigate click-jacking attacks, the user agent may implement a time threshold in which clicks are ignored immediately after a dialog is shown.
Another relevant mitigation exists in step 6 of {{PaymentRequest/show()}}, where the document must be visible in order to initiate the user interaction.
Accessibility ConsiderationsFor 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.
DependenciesThis specification relies on several other underlying specifications.
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.
AcknowledgementsThis specification was derived from a report published previously by the Web Platform Incubator Community Group.
ChangelogChanges from between CR2 until now:
Changes from between CR1 and CR2:
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4