Abstract 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.

1. Introduction This section is non-normative. This specification describes an API that allows user agents (e.g., browsers) to act as an intermediary between three parties in a transaction: The payee: the merchant that runs an online store, or other party that requests to be paid.

The payer: the party that makes a purchase at that online store, and who authenticates and authorizes payment as required.

The payment method : the means that the payer uses to pay the payee (e.g., a basic card payment). The payment method provider establishes the ecosystem to support that payment method. 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. 1.1 Goals and scope Allow the user agent to act as intermediary between a merchant, user, and payment method provider.

Enable user agents to streamline the user's payment experience by taking into account user preferences, merchant information, security considerations, and other factors.

Standardize (to the extent that it makes sense) the communication flow between a merchant, user agent, and payment method provider.

Enable a payment method provider to bring more secure payment transactions to the web. The following are out of scope for this specification: Create a new payment method.

Integrate directly with payment processors.

2. Examples of usage This section is non-normative. 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: The methodData : A sequence of PaymentMethodData s that represents the payment methods that the site supports (e.g., "we support card-based payments, but only Visa and MasterCard credit cards.").

: A sequence of s that represents the payment methods that the site supports (e.g., "we support card-based payments, but only Visa and MasterCard credit cards."). The details : The details of the transaction, as a PaymentDetailsInit dictionary. This includes total cost, and optionally a list of goods or services being purchased, for physical goods, and shipping options. Additionally, it can optionally include "modifiers" to how payments are made. For example, "if you pay with a card belonging to network X, it incurs a US$3.00 processing fee".

: The details of the transaction, as a dictionary. This includes total cost, and optionally a list of goods or services being purchased, for physical goods, and shipping options. Additionally, it can optionally include "modifiers" to how payments are made. For example, "if you pay with a card belonging to network X, it incurs a US$3.00 processing fee". The options : Optionally, a list of things as PaymentOptions that the site needs to deliver the good or service (e.g., for physical goods, the merchant will typically need a physical address to ship to. For digital goods, an email will usually suffice). 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 . 2.1 Declaring multiple ways of paying When 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). Example 1 : The `methodData` argument const methodData = [ { supportedMethods : "basic-card" , data : { supportedNetworks : [ "visa" , "mastercard" ], }, }, { supportedMethods : "https://example.com/bobpay" , data : { merchantIdentifier : "XXXX" , bobPaySpecificField : true , }, }, ]; 2.2 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. Example 2 : The `details` argument 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" , amount: { currency : "USD" , value : "65.00" }, }, }; 2.3 Adding shipping options Here we see an example of how to add two shipping options to the details . Example 3 : Adding shipping options 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 }); 2.4 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. Example 4 : Modifying payment request based on card type const cardFee = { label : "Card processing fee" , amount : { currency : "USD" , value : "3.00" }, }; const modifiers = [ { additionalDisplayItems : [cardFee], supportedMethods : "basic-card" , total : { label : "Total due" , amount : { currency : "USD" , value : "68.00" }, }, data : { supportedNetworks : networks, }, }, ]; Object .assign(details, { modifiers }); 2.5 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 ) 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. Example 5 : The `options` argument const options = { requestPayerEmail : false , requestPayerName : true , requestPayerPhone : false , requestShipping : true , } 2.6 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: Example 6 : Constructing a `PaymentRequest` async function doPaymentRequest ( ) { try { const request = new PaymentRequest(methodData, details, options); request.onshippingaddresschange = ev => ev.updateWith(details); request.onshippingoptionchange = ev => ev.updateWith(details); const response = await request.show(); await validateResponse(response); } catch (err) { console .error(err); } } async function validateResponse ( response ) { try { const errors = await checkAllValuesAreGood(response); if (errors.length) { await request.retry(errors); return validateResponse(response); } await response.complete( "success" ); } catch (err) { await response.complete( "fail" ); } } doPaymentRequest(); 2.7 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. Example 7 : Registering event handlers const request = new PaymentRequest(methodData, details, options); request.onshippingaddresschange = ev => { ev.updateWith(checkShipping(request)); }; request.onshippingoptionchange = ev => { 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.` }; } } 2.8 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. Example 8 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." , }; const shippingOptions = []; return { error, shippingAddressErrors, shippingOptions }; } 2.9 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 Standard : Example 9 : POSTing with `fetch()` 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();

4. PaymentMethodData dictionary DOMString supportedMethods ; required object data ; dictionary PaymentMethodData }; 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. Note 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.

8. PaymentShippingType enum shipping " delivery " pickup " enum PaymentShippingType }; " 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 the destination 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.

10. PaymentItem dictionary DOMString label ; required PaymentCurrencyAmount amount ; required boolean pending = false; dictionary PaymentItem }; 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.

12. PaymentShippingOption dictionary DOMString id ; required DOMString label ; required PaymentCurrencyAmount amount ; required boolean selected = false; dictionary PaymentShippingOption }; 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.

13. PaymentComplete enum fail " success " unknown " enum PaymentComplete }; " 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.

20. Accessibility Considerations This section is non-normative. 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.

21. Dependencies This specification relies on several other underlying specifications. ECMAScript The terms internal slot , 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. ISO 3366-2 Country subdivision name and country subdivision code element are defined in [ ISO3166-2 ].

22. Conformance As well as sections marked as non-normative, all authoring guidelines, diagrams, examples, and notes in this specification are non-normative. Everything else in this specification is normative. The key words MAY, MUST, MUST NOT, OPTIONAL, RECOMMENDED, SHOULD, and SHOULD NOT in this document are to be interpreted as described in BCP 14 [ RFC2119 ] [ RFC8174 ] when, and only when, they appear in all capitals, as shown here. There is only one class of product that can claim conformance to this specification: a user agent . Note 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.

A. IDL Index SecureContext Exposed=Window EventTarget constructor ( sequence< PaymentMethodData > methodData , PaymentDetailsInit details , optional PaymentOptions options = {} ); , optional= {} ); NewObject Promise< PaymentResponse > Promise< PaymentDetailsUpdate > detailsPromise ); show (optional); NewObject Promise<void> abort (); NewObject Promise<boolean> canMakePayment (); DOMString id ; readonly attribute PaymentAddress ? shippingAddress ; readonly attribute DOMString? shippingOption ; readonly attribute PaymentShippingType ? shippingType ; readonly attribute EventHandler onmerchantvalidation ; attribute EventHandler onshippingaddresschange ; attribute EventHandler onshippingoptionchange ; attribute EventHandler onpaymentmethodchange ; attribute ] interface PaymentRequest }; DOMString supportedMethods ; required object data ; dictionary PaymentMethodData }; DOMString currency ; required DOMString value ; required dictionary PaymentCurrencyAmount }; sequence< PaymentItem > displayItems ; sequence< PaymentShippingOption > shippingOptions ; sequence< PaymentDetailsModifier > modifiers ; dictionary PaymentDetailsBase }; PaymentDetailsBase DOMString id ; PaymentItem total ; required dictionary PaymentDetailsInit }; PaymentDetailsBase DOMString error ; PaymentItem total ; AddressErrors shippingAddressErrors ; PayerErrors payerErrors ; object paymentMethodErrors ; dictionary PaymentDetailsUpdate }; DOMString supportedMethods ; required PaymentItem total ; sequence< PaymentItem > additionalDisplayItems ; object data ; dictionary PaymentDetailsModifier }; shipping " delivery " pickup " enum PaymentShippingType }; boolean requestPayerName = false; boolean requestBillingAddress = false; boolean requestPayerEmail = false; boolean requestPayerPhone = false; boolean requestShipping = false; PaymentShippingType shippingType = "shipping"; dictionary PaymentOptions }; DOMString label ; required PaymentCurrencyAmount amount ; required boolean pending = false; dictionary PaymentItem }; SecureContext Exposed =( Window Default object toJSON (); 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 sortingCode ; readonly attribute FrozenArray<DOMString> addressLine ; readonly attribute ] interface PaymentAddress }; DOMString country ; sequence<DOMString> addressLine ; DOMString region ; DOMString city ; DOMString dependentLocality ; DOMString postalCode ; DOMString sortingCode ; DOMString organization ; DOMString recipient ; DOMString phone ; dictionary AddressInit }; DOMString addressLine ; DOMString city ; DOMString country ; DOMString dependentLocality ; DOMString organization ; DOMString phone ; DOMString postalCode ; DOMString recipient ; DOMString region ; DOMString sortingCode ; dictionary AddressErrors }; DOMString id ; required DOMString label ; required PaymentCurrencyAmount amount ; required boolean selected = false; dictionary PaymentShippingOption }; fail " success " unknown " enum PaymentComplete }; SecureContext Exposed=Window EventTarget Default object toJSON (); 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 ; readonly attribute NewObject Promise<void> PaymentComplete result = "unknown"); complete (optional= "unknown"); NewObject Promise<void> PaymentValidationErrors errorFields = {}); retry (optional= {}); EventHandler onpayerdetailchange ; attribute ] interface PaymentResponse }; PayerErrors payer ; AddressErrors shippingAddress ; DOMString error ; object paymentMethod ; dictionary PaymentValidationErrors }; DOMString email ; DOMString name ; DOMString phone ; dictionary PayerErrors }; SecureContext Exposed=Window Event constructor ( DOMString type , optional MerchantValidationEventInit eventInitDict = {}); , optional= {}); DOMString methodName ; readonly attribute USVString validationURL ; readonly attribute void complete ( Promise<any> merchantSessionPromise ); ); ] interface MerchantValidationEvent }; EventInit DOMString methodName = ""; USVString validationURL = ""; dictionary MerchantValidationEventInit }; SecureContext Exposed=Window PaymentRequestUpdateEvent constructor ( DOMString type , optional PaymentMethodChangeEventInit eventInitDict = {}); , optional= {}); DOMString methodName ; readonly attribute object? methodDetails ; readonly attribute ] interface PaymentMethodChangeEvent }; PaymentRequestUpdateEventInit DOMString methodName = ""; object? methodDetails = null; dictionary PaymentMethodChangeEventInit }; SecureContext Exposed=Window Event constructor ( DOMString type , optional PaymentRequestUpdateEventInit eventInitDict = {}); , optional= {}); void updateWith ( Promise< PaymentDetailsUpdate > detailsPromise ); ); ] interface PaymentRequestUpdateEvent }; EventInit dictionary PaymentRequestUpdateEventInit {};

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