CARVIEW |
Payment Handler API
More details about this document
- This version:
- https://www.w3.org/TR/2025/WD-payment-handler-20250927/
- Latest published version:
- https://www.w3.org/TR/payment-handler/
- Latest editor's draft:
- https://w3c.github.io/payment-handler/
- History:
- https://www.w3.org/standards/history/payment-handler/
- Commit history
- Test suite:
- https://wpt.live/payment-handler/
- Editors:
- Ian Jacobs (W3C)
- Jinho Bang (Invited Expert)
- Stephen McGruer (Google)
- Former editors:
- Andre Lyver (Shopify)
- Tommy Thorsen (Opera)
- Adam Roach (Mozilla)
- Rouslan Solomakhin (Google)
- Adrian Hope-Bailie (Coil)
- Feedback:
- GitHub w3c/payment-handler (pull requests, new issue, open issues)
Copyright © 2025 World Wide Web Consortium. W3C® liability, trademark and permissive document license rules apply.
Abstract
This specification defines capabilities that enable Web applications to handle requests for payment.
Status of This Document
This section describes the status of this document at the time of its publication. A list of current W3C publications and the latest revision of this technical report can be found in the W3C standards and drafts index.
The Web Payments Working Group maintains a list of all bug reports that the group has not yet addressed. This draft highlights some of the pending issues that are still to be discussed in the working group. No decision has been taken on the outcome of these issues including whether they are valid. Pull requests with proposed specification text for outstanding issues are strongly encouraged.
This document was published by the Web Payments Working Group as a Working Draft using the Recommendation track.
Publication as a Working Draft does not imply endorsement by W3C and its Members.
This is a draft document and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to cite this document as other than a work in progress.
This document was produced by a group operating under the W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent that the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.
This document is governed by the 18 August 2025 W3C Process Document.
This section is non-normative.
This specification defines a number of new features to allow web applications to handle requests for payments on behalf of users:
- An origin-based permission to handle payment request events.
- A payment request event type (
PaymentRequestEvent
). A payment handler is an event handler for thePaymentRequestEvent
. - An extension to the service worker registration interface
(
PaymentManager
) to manage properties of payment handlers. - A mechanism to respond to the
PaymentRequestEvent
.
This specification does not address how software built with operating-system specific mechanisms (i.e., "native apps") handle payment requests.
In this document we envision the following flow:
- An origin requests permission from the user to handle payment requests for a set of supported payment methods. For example, a user visiting a retail or bank site may be prompted to register a payment handler from that origin. The origin establishes the scope of the permission but the origin's capabilities may evolve without requiring additional user consent.
- Payment handlers are defined in service worker code.
- When the merchant (or other payee) calls the
[payment-request] method canMakePayment() or show()
(e.g., when the user -- the payer -- pushes a button on a
checkout page), the user agent computes a list of candidate payment
handlers, comparing the payment methods accepted by the merchant with
those known to the user agent through any number of mechanisms,
including, but not limited to:
- Those previously registered through this API.
- Those that may be registered through this API during the course of the transaction, e.g., identified through a payment method manifest.
- Those registered through other mechanisms, e.g., the operating system.
- The user agent displays a set of choices to the user: the candidate payment handlers. The user agent displays these choices using information (labels and icons) provided at registration or otherwise available from the Web app.
- When the payer user selects a payment handler, the user agent
fires a
PaymentRequestEvent
(cf. the user interaction task source) in the service worker for the selected payment handler. ThePaymentRequestEvent
includes some information from the PaymentRequest (defined in [payment-request]) as well as additional information (e.g., payee's origin). - Once activated, the payment handler performs whatever steps are necessary to handle the payment request, and return an appropriate payment response to the payee. If interaction with the user is necessary, the payment handler can open a window for that purpose.
- The user agent receives a response asynchronously once the payment handler has finished handling the request. The response becomes the PaymentResponse (of [payment-request]).
An origin may implement a payment app with more than one service worker and therefore multiple payment handlers may be registered per origin. The handler that is invoked is determined by the selection made by the user.
This section is non-normative.
A payment handler is a Web application that can handle a request for payment on behalf of the user.
The logic of a payment handler is driven by the payment methods that it supports. Some payment methods expect little to no processing by the payment handler which simply returns payment card details in the response. It is then the job of the payee website to process the payment using the returned data as input.
In contrast, some payment methods, such as a crypto-currency payments or bank originated credit transfers, require that the payment handler initiate processing of the payment. In such cases the payment handler will return a payment reference, endpoint URL or some other data that the payee website can use to determine the outcome of the payment (as opposed to processing the payment itself).
Handling a payment request may include numerous interactions: with the user through a new window or other APIs (such as Web Cryptography API) or with other services and origins through web requests or other means.
This specification does not address these activities that occur
between the payment handler accepting the PaymentRequestEvent
and
the payment handler returning a response. All of these activities
which may be required to configure the payment handler and handle the
payment request, are left to the implementation of the payment
handler, including:
- how the user establishes an account with an origin that provides payment services.
- how an origin authenticates a user.
- how communication takes place between the payee server and the payee Web application, or between a payment app origin and other parties.
Thus, an origin will rely on many other Web technologies defined elsewhere for lifecycle management, security, user authentication, user interaction, and so on.
This section is non-normative.
This specification does not address how third-party mobile payment apps interact (through proprietary mechanisms) with user agents, or how user agents themselves provide simple payment app functionality.

One registers a payment handler with the user agent through a just-in-time (JIT) registration mechanism.
If a payment handler is not registered when a merchant invokes
show
()
method, a user agent may allow the user to
register this payment handler during the transaction ("just-in-time").
The remaining content of this section is non-normative.
A user agent may perform just-in-time installation by deriving payment handler information from the payment method manifest that is found through the URL-based payment method identifier that the merchant requested.
This section describes the functionality available to a payment handler to manage its own properties.
WebIDLpartial interface ServiceWorkerRegistration
{
[SameObject] readonly attribute PaymentManager
paymentManager
;
};
The paymentManager
attribute exposes payment handler
management functionality.
WebIDL[SecureContext, Exposed=(Window)]
interface PaymentManager
{
attribute DOMString userHint
;
Promise<undefined> enableDelegations
(sequence<PaymentDelegation
> delegations);
};
The PaymentManager
is used by payment handlers to manage
their supported delegations.
When displaying payment handler name and icon, the user agent may use this string to improve the user experience. For example, a user hint of "**** 1234" can remind the user that a particular card is available through this payment handler.
This method allows a payment handler to asynchronously
declare its supported PaymentDelegation
list.
WebIDLenum PaymentDelegation
{
"shippingAddress
",
"payerName
",
"payerPhone
",
"payerEmail
"
};
-
"
shippingAddress
" - The payment handler will provide shipping address whenever needed.
-
"
payerName
" - The payment handler will provide payer's name whenever needed.
-
"
payerPhone
" - The payment handler will provide payer's phone whenever needed.
-
"
payerEmail
" - The payment handler will provide payer's email whenever needed.
If the payment handler supports CanMakePaymentEvent
, the
user agent may use it to help with filtering of the available
payment handlers.
Implementations may impose a timeout for developers to respond to the
CanMakePaymentEvent
. If the timeout expires, then the
implementation will behave as if respondWith
()
was called with false
.
WebIDLpartial interface ServiceWorkerGlobalScope
{
attribute EventHandler oncanmakepayment
;
};
The oncanmakepayment
attribute is an
event handler whose corresponding event handler event
type is "canmakepayment".
The CanMakePaymentEvent
is used to as a signal for whether the
payment handler is able to respond to a payment request.
WebIDL[Exposed=ServiceWorker]
interface CanMakePaymentEvent
: ExtendableEvent {
constructor
(DOMString type);
undefined respondWith
(Promise<boolean> canMakePaymentResponse);
};
This method is used by the payment handler as a signal for whether it can respond to a payment request.
Upon receiving a PaymentRequest, the user agent MUST run the following steps:
- If user agent settings prohibit usage of
CanMakePaymentEvent
(e.g., in private browsing mode), terminate these steps. - Let registration be a
ServiceWorkerRegistration
. - If registration is not found, terminate these steps.
-
Fire Functional Event "
canmakepayment
" usingCanMakePaymentEvent
on registration.
5.4
Example of handling the CanMakePaymentEvent
This section is non-normative.
This example shows how to write a service worker that listens to the
CanMakePaymentEvent
. When a CanMakePaymentEvent
is
received, the service worker always returns true.
self.addEventListener("canmakepayment", function(e) {
e.respondWith(new Promise(function(resolve, reject) {
resolve(true);
}));
});
Given a PaymentMethodData and a payment handler that matches on
payment method identifier, this algorithm returns
true
if this payment handler can be used for payment:
- Let methodName be the payment method identifier string specified in the PaymentMethodData.
- Let methodData be the payment method specific data of PaymentMethodData.
- Let paymentHandlerOrigin be the origin of the
ServiceWorkerRegistration
scope URL of the payment handler. - Let paymentMethodManifest be the ingested and parsed payment method manifest for the methodName.
- If methodName is a URL-based payment method
identifier with the
"*"
string supported origins in paymentMethodManifest, returntrue
. - Otherwise, if the URL-based payment method identifier
methodName has the same origin as
paymentHandlerOrigin, fire the
CanMakePaymentEvent
in the payment handler and return the result. - Otherwise, if supported origins in
paymentMethodManifest is an ordered set of origin
that contains the paymentHandlerOrigin, fire the
CanMakePaymentEvent
in the payment handler and return the result. - Otherwise, return
false
.
Once the user has selected a payment handler, the user agent fires a
PaymentRequestEvent
and uses the subsequent
PaymentHandlerResponse
to create a PaymentResponse for
[payment-request].
Payment Request API supports delegation of responsibility to manage an abort to a payment app. There is a proposal to add a paymentRequestAborted event to the Payment Handler interface. The event will have a respondWith method that takes a boolean parameter indicating if the paymentRequest has been successfully aborted.
6.1
Extension to ServiceWorkerGlobalScope
This specification extends the ServiceWorkerGlobalScope
interface.
WebIDLpartial interface ServiceWorkerGlobalScope
{
attribute EventHandler onpaymentrequest
;
};
The onpaymentrequest
attribute is an event handler
whose corresponding event handler event type is
PaymentRequestEvent
.
The PaymentRequestDetailsUpdate
contains the updated
total (optionally with modifiers and shipping options) and possible
errors resulting from user selection of a payment method, a shipping
address, or a shipping option within a payment handler.
WebIDLdictionary PaymentRequestDetailsUpdate
{
DOMString error
;
PaymentCurrencyAmount total
;
sequence<PaymentDetailsModifier> modifiers
;
sequence<PaymentShippingOption> shippingOptions
;
object paymentMethodErrors
;
AddressErrors shippingAddressErrors
;
};
A human readable string that explains why the user selected payment method, shipping address or shipping option cannot be used.
Updated total based on the changed payment method, shipping address, or shipping option. The total can change, for example, because the billing address of the payment method selected by the user changes the Value Added Tax (VAT); Or because the shipping option/address selected/provided by the user changes the shipping cost.
Updated modifiers based on the changed payment method, shipping address, or shipping option. For example, if the overall total has increased by €1.00 based on the billing or shipping address, then the totals specified in each of the modifiers should also increase by €1.00.
Updated shippingOptions based on the changed shipping address. For example, it is possible that express shipping is more expensive or unavailable for the user provided country.
Validation errors for the payment method, if any.
Validation errors for the shipping address, if any.
The PaymentRequestEvent represents the data and methods available to a Payment Handler after selection by the user. The user agent communicates a subset of data available from the PaymentRequest to the Payment Handler.
WebIDL[Exposed=ServiceWorker]
interface PaymentRequestEvent
: ExtendableEvent {
constructor
(DOMString type, optional PaymentRequestEventInit
eventInitDict = {});
readonly attribute USVString topOrigin
;
readonly attribute USVString paymentRequestOrigin
;
readonly attribute DOMString paymentRequestId
;
readonly attribute FrozenArray<PaymentMethodData> methodData
;
readonly attribute object total
;
readonly attribute FrozenArray<PaymentDetailsModifier> modifiers
;
readonly attribute object? paymentOptions
;
readonly attribute FrozenArray<PaymentShippingOption>? shippingOptions
;
Promise<WindowClient?> openWindow
(USVString url);
Promise<PaymentRequestDetailsUpdate
?> changePaymentMethod
(DOMString methodName, optional object? methodDetails = null);
Promise<PaymentRequestDetailsUpdate
?> changeShippingAddress
(optional AddressInit shippingAddress = {});
Promise<PaymentRequestDetailsUpdate
?> changeShippingOption
(DOMString shippingOption);
undefined respondWith
(Promise<PaymentHandlerResponse
> handlerResponsePromise);
};
Returns a string that indicates the origin of the top level payee web page. This attribute is initialized by Handling a PaymentRequestEvent.
Returns a string that indicates the origin where a
PaymentRequest was initialized. When a PaymentRequest
is initialized in the topOrigin
, the attributes have the
same value, otherwise the attributes have different values. For
example, when a PaymentRequest is initialized within an
iframe from an origin other than topOrigin
, the value of
this attribute is the origin of the iframe. This attribute is
initialized by Handling a PaymentRequestEvent.
When getting, the paymentRequestId
attribute returns the
[[details]]
.id from the PaymentRequest that
corresponds to this PaymentRequestEvent
.
This attribute contains PaymentMethodData dictionaries containing the payment method identifiers for the payment methods that the web site accepts and any associated payment method specific data. It is populated from the PaymentRequest using the MethodData Population Algorithm defined below.
This attribute indicates the total amount being requested for
payment. It is of type PaymentCurrencyAmount dictionary as
defined in [payment-request], and initialized with a copy of the
total
field of the PaymentDetailsInit provided when
the corresponding PaymentRequest object was instantiated.
This sequence of PaymentDetailsModifier dictionaries contains modifiers for particular payment method identifiers (e.g., if the payment amount or currency type varies based on a per-payment-method basis). It is populated from the PaymentRequest using the Modifiers Population Algorithm defined below.
The value of PaymentOptions in the PaymentRequest. Available only when shippingAddress and/or any subset of payer's contact information are requested.
The value of ShippingOptions in the PaymentDetailsInit dictionary of the corresponding PaymentRequest.(PaymentDetailsInit inherits ShippingOptions from PaymentDetailsBase). Available only when shipping address is requested.
This method is used by the payment handler to show a window to the user. When called, it runs the open window algorithm.
This method is used by the payment handler to get updated total given such payment method details as the billing address. When called, it runs the change payment method algorithm.
This method is used by the payment handler to get updated payment details given the shippingAddress. When called, it runs the change payment details algorithm.
This method is used by the payment handler to get updated payment details given the shippingOption identifier. When called, it runs the change payment details algorithm.
This method is used by the payment handler to provide a
PaymentHandlerResponse
when the payment successfully
completes. When called, it runs the Respond to PaymentRequest
Algorithm with event and handlerResponsePromise as
arguments.
Should payment apps receive user data stored in the user agent upon explicit consent from the user? The payment app could request permission either at installation or when the payment app is first invoked.
WebIDLdictionary PaymentRequestEventInit
: ExtendableEventInit {
USVString topOrigin
;
USVString paymentRequestOrigin
;
DOMString paymentRequestId
;
sequence<PaymentMethodData> methodData
;
PaymentCurrencyAmount total
;
sequence<PaymentDetailsModifier> modifiers
;
PaymentOptions paymentOptions
;
sequence<PaymentShippingOption> shippingOptions
;
};
The topOrigin
, paymentRequestOrigin
,
paymentRequestId
, methodData
,
total
, modifiers
, paymentOptions
,
and shippingOptions
members share their definitions with
those defined for PaymentRequestEvent
To initialize the value of the methodData
, the user agent
MUST perform the following steps or their equivalent:
- Let registeredMethods be the set of registered payment method identifiers of the invoked payment handler.
- Create a new empty Sequence.
- Set dataList to the newly created Sequence.
- For each item in
PaymentRequest@[[methodData]] in the
corresponding payment request, perform the following steps:
- Set inData to the item under consideration.
- Set commonMethods to the set intersection of inData.supportedMethods and registeredMethods.
- If commonMethods is empty, skip the remaining substeps and move on to the next item (if any).
- Create a new PaymentMethodData object.
- Set outData to the newly created PaymentMethodData.
- Set outData.supportedMethods to a list containing the members of commonMethods.
- Set outData.data to a copy of inData.data.
- Append outData to dataList.
- Set
methodData
to dataList.
To initialize the value of the modifiers
, the user agent
MUST perform the following steps or their equivalent:
- Let registeredMethods be the set of registered payment method identifiers of the invoked payment handler.
- Create a new empty Sequence.
- Set modifierList to the newly created Sequence.
- For each item in
PaymentRequest@[[paymentDetails]].
modifiers
in the corresponding payment request, perform the following steps:- Set inModifier to the item under consideration.
- Set commonMethods to the set intersection of inModifier.supportedMethods and registeredMethods.
- If commonMethods is empty, skip the remaining substeps and move on to the next item (if any).
- Create a new PaymentDetailsModifier object.
- Set outModifier to the newly created PaymentDetailsModifier.
- Set outModifier.supportedMethods to a list containing the members of commonMethods.
- Set outModifier.
total
to a copy of inModifier.total
. - Append outModifier to modifierList.
- Set
modifiers
to modifierList.
Instances of PaymentRequestEvent
are created with the internal
slots in the following table:
Internal Slot | Default Value | Description (non-normative) |
---|---|---|
[[windowClient]] | null | The currently active WindowClient. This is set if a payment handler is currently showing a window to the user. Otherwise, it is null. |
[[respondWithCalled]] | false | YAHO |
Upon receiving a PaymentRequest by way of PaymentRequest.show() and subsequent user selection of a payment handler, the user agent MUST run the following steps:
- Let registration be the
ServiceWorkerRegistration
corresponding to the payment handler selected by the user. - If registration is not found, reject the
Promise
that was created by PaymentRequest.show() with an "InvalidStateError
"DOMException
and terminate these steps. -
Fire Functional Event "
paymentrequest
" usingPaymentRequestEvent
on registration with the following properties:-
topOrigin
- the serialization of an origin of the top level payee web page.
-
paymentRequestOrigin
- the serialization of an origin of the context where PaymentRequest was initialized.
-
methodData
- The result of executing the MethodData Population Algorithm.
-
modifiers
- The result of executing the Modifiers Population Algorithm.
-
total
- A copy of the total field on the PaymentDetailsInit from the corresponding PaymentRequest.
-
paymentRequestId
- \[\[details\]\].id from the PaymentRequest.
-
paymentOptions
- A copy of the paymentOptions dictionary passed to the constructor of the corresponding PaymentRequest.
-
shippingOptions
- A copy of the shippingOptions field on the PaymentDetailsInit from the corresponding PaymentRequest.
Then run the following steps in parallel, with dispatchedEvent:
- Wait for all of the promises in the extend lifetime promises of dispatchedEvent to resolve.
- If the payment handler has not provided a
PaymentHandlerResponse
, reject thePromise
that was created by PaymentRequest.show() with an "OperationError
"DOMException
.
-
An invoked payment handler may or may not need to display information about itself or request user input. Some examples of potential payment handler display include:
- The payment handler opens a window for the user to provide an authorization code.
- The payment handler opens a window that makes it easy for the user to confirm payment using default information for that site provided through previous user configuration.
- When first selected to pay in a given session, the payment handler opens a window. For subsequent payments in the same session, the payment handler (through configuration) performs its duties without opening a window or requiring user interaction.
A payment handler that requires visual display and user interaction, may call openWindow() to display a page to the user.
Since user agents know that this method is connected to the
PaymentRequestEvent
, they SHOULD render the window in a way that is
consistent with the flow and not confusing to the user. The resulting
window client is bound to the tab/window that initiated the
PaymentRequest. A single payment handler SHOULD NOT be
allowed to open more than one client window using this method.
This algorithm resembles the Open Window Algorithm in the Service Workers specification.
Should we refer to the Service Workers specification instead of copying their steps?
- Let event be this
PaymentRequestEvent
. - If event's
isTrusted
attribute is false, return aPromise
rejected with a "InvalidStateError
"DOMException
. - Let request be the PaymentRequest that
triggered this
PaymentRequestEvent
. - Let url be the result of parsing the url argument.
- If the url parsing throws an exception, return a
Promise
rejected with that exception. - If url is
about:blank
, return aPromise
rejected with aTypeError
. - If url's origin is not the same as the service
worker's origin associated with the payment handler, return a
Promise
resolved with null. - Let promise be a new
Promise
. - Return promise and perform the remaining steps in parallel:
- If event.
[[windowClient]]
is not null, then:- If event.
[[windowClient]]
.visibilityState is not "unloaded", reject promise with an "InvalidStateError
"DOMException
and abort these steps.
- If event.
- Let newContext be a new top-level browsing context.
- Navigate newContext to url, with exceptions enabled and replacement enabled.
- If the navigation throws an exception, reject promise with that exception and abort these steps.
- If the origin of newContext is not the same as the
service worker client origin associated with the payment
handler, then:
- Resolve promise with null.
- Abort these steps.
- Let client be the result of running the create window client algorithm with newContext as the argument.
- Set event.
[[windowClient]]
to client. - Resolve promise with client.
7.2
Example of handling the PaymentRequestEvent
This section is non-normative.
This example shows how to write a service worker that listens to the
PaymentRequestEvent
. When a PaymentRequestEvent
is received,
the service worker opens a window to interact with the user.
async function getPaymentResponseFromWindow() {
return new Promise((resolve, reject) => {
self.addEventListener("message", listener = e => {
self.removeEventListener("message", listener);
if (!e.data || !e.data.methodName) {
reject();
return;
}
resolve(e.data);
});
});
}
self.addEventListener("paymentrequest", e => {
e.respondWith((async() => {
// Open a new window for providing payment UI to user.
const windowClient = await e.openWindow("payment_ui.html");
// Send data to the opened window.
windowClient.postMessage({
total: e.total,
modifiers: e.modifiers
});
// Wait for a payment response from the opened window.
return await getPaymentResponseFromWindow();
})());
});
Using the simple scheme described above, a trivial HTML page that is loaded into the payment handler window might look like the following:
<form id="form">
<table>
<tr><th>Cardholder Name:</th><td><input name="cardholderName"></td></tr>
<tr><th>Card Number:</th><td><input name="cardNumber"></td></tr>
<tr><th>Expiration Month:</th><td><input name="expiryMonth"></td></tr>
<tr><th>Expiration Year:</th><td><input name="expiryYear"></td></tr>
<tr><th>Security Code:</th><td><input name="cardSecurityCode"></td></tr>
<tr><th></th><td><input type="submit" value="Pay"></td></tr>
</table>
</form>
<script>
navigator.serviceWorker.addEventListener("message", e => {
/* Note: message sent from payment app is available in e.data */
});
document.getElementById("form").addEventListener("submit", e => {
const details = {};
["cardholderName", "cardNumber", "expiryMonth", "expiryYear", "cardSecurityCode"]
.forEach(field => {
details[field] = form.elements[field].value;
});
const paymentAppResponse = {
methodName: "https://example.com/pay",
details
};
navigator.serviceWorker.controller.postMessage(paymentAppResponse);
window.close();
});
</script>
WebIDLdictionary PaymentHandlerResponse
{
DOMString methodName
;
object details
;
DOMString? payerName
;
DOMString? payerEmail
;
DOMString? payerPhone
;
AddressInit shippingAddress
;
DOMString? shippingOption
;
};
The payment method identifier for the payment method that the user selected to fulfil the transaction.
A JSON-serializable object that provides a payment method specific message used by the merchant to process the transaction and determine successful fund transfer.
The user agent receives a successful response from the payment
handler through resolution of the Promise provided to the
respondWith
function of the corresponding
PaymentRequestEvent
interface. The application is expected to
resolve the Promise with a PaymentHandlerResponse
instance
containing the payment response. In case of user cancellation or
error, the application may signal failure by rejecting the Promise.
If the Promise is rejected, the user agent MUST run the payment app failure algorithm. The exact details of this algorithm are left to implementers. Acceptable behaviors include, but are not limited to:
- Letting the user try again, with the same payment handler or with a different one.
- Rejecting the Promise that was created by PaymentRequest.show().
The user provided payer's name.
The user provided payer's email.
The user provided payer's phone number.
The user provided shipping address.
The identifier of the user selected shipping option.
When this algorithm is invoked with methodName and methodDetails parameters, the user agent MUST run the following steps:
- Run the payment method changed algorithm with PaymentMethodChangeEvent event constructed using the given methodName and methodDetails parameters.
- If event.updateWith(detailsPromise) is not run, return
null
. - If event.updateWith(detailsPromise) throws, rethrow the error.
- If event.updateWith(detailsPromise) times out
(optional), throw "
InvalidStateError
"DOMException
. - Construct and return a
PaymentRequestDetailsUpdate
from the detailsPromise in event.updateWith(detailsPromise).
When this algorithm is invoked with shippingAddress or shippingOption the user agent MUST run the following steps:
- Run the PaymentRequest updated algorithm with PaymentRequestUpdateEvent event constructed using the updated details (shippingAddress or shippingOption).
- If event.updateWith(detailsPromise) is not run, return
null
. - If event.updateWith(detailsPromise) throws, rethrow the error.
- If event.updateWith(detailsPromise) times out
(optional), throw "
InvalidStateError
"DOMException
. - Construct and return a
PaymentRequestDetailsUpdate
from the detailsPromise in event.updateWith(detailsPromise).
When this algorithm is invoked with event and handlerResponsePromise parameters, the user agent MUST run the following steps:
- If event's
isTrusted
is false, then throw an "InvalidStateError"DOMException
and abort these steps. - If event's dispatch flag is unset, then throw an
"
InvalidStateError
"DOMException
and abort these steps. - If event.
[[respondWithCalled]]
is true, throw an "InvalidStateError
"DOMException
and abort these steps. - Set event.
[[respondWithCalled]]
to true. - Set the event's stop propagation flag and event's stop immediate propagation flag.
- Add handlerResponsePromise to the event's extend lifetime promises
- Increment the event's pending promises count by one.
-
Upon rejection of handlerResponsePromise:
- Run the payment app failure algorithm and terminate these steps.
-
Upon fulfillment of handlerResponsePromise:
- Let handlerResponse be value converted to an
IDL value
PaymentHandlerResponse
. If this throws an exception, run the payment app failure algorithm and terminate these steps. - Validate that all required members exist in
handlerResponse and are well formed.
- If handlerResponse.
methodName
is not present or not set to one of the values from event.methodData
, run the payment app failure algorithm and terminate these steps. - If handlerResponse.
details
is not present or not JSON-serializable, run the payment app failure algorithm and terminate these steps. - Let shippingRequired be the requestShipping
value of the associated PaymentRequest's
paymentOptions. If shippingRequired and
handlerResponse.
shippingAddress
is not present, run the payment app failure algorithm and terminate these steps. - If shippingRequired and
handlerResponse.
shippingOption
is not present or not set to one of shipping options identifiers from event.shippingOptions
, run the payment app failure algorithm and terminate these steps. - Let payerNameRequired be the requestPayerName
value of the associated PaymentRequest's
paymentOptions. If payerNameRequired and
handlerResponse.
payerName
is not present, run the payment app failure algorithm and terminate these steps. - Let payerEmailRequired be the requestPayerEmail
value of the associated PaymentRequest's
paymentOptions. If payerEmailRequired and
handlerResponse.
payerEmail
is not present, run the payment app failure algorithm and terminate these steps. - Let payerPhoneRequired be the requestPayerPhone
value of the associated PaymentRequest's
paymentOptions. If payerPhoneRequired and
handlerResponse.
payerPhone
is not present, run the payment app failure algorithm and terminate these steps.
- If handlerResponse.
- Serialize required members of handlerResponse (
methodName and details are always required;
shippingAddress and shippingOption are
required when shippingRequired is true;
payerName, payerEmail, and
payerPhone are required when
payerNameRequired, payerEmailRequired, and
payerPhoneRequired are true, respectively.):
- For each memberin handlerResponseLet serializeMemberbe the result of StructuredSerializewith handlerResponse.member. Rethrow any exceptions.
- The user agent MUST run the user accepts the payment
request algorithm as defined in [payment-request],
replacing steps 9-15 with these steps or their equivalent.
- Deserialize serialized members:
- For each serializeMemberlet memberbe the result of StructuredDeserializewith serializeMember. Rethrow any exceptions.
- If any exception occurs in the above step, then run the payment app failure algorithm and terminate these steps.
- Assign methodName to associated PaymentRequest's response.methodName.
- Assign details to associated PaymentReqeust's response.details.
- If shippingRequired, then set the shippingAddress attribute of associated PaymentReqeust's response to shippingAddress. Otherwise, set it to null.
- If shippingRequired, then set the shippingOption attribute of associated PaymentReqeust's response to shippingOption. Otherwise, set it to null.
- If payerNameRequired, then set the payerName attribute of associated PaymentReqeust's response to payerName. Otherwise, set it to null.
- If payerEmailRequired, then set the payerEmail attribute of associated PaymentReqeust's response to payerEmail. Otherwise, set it to null.
- If payerPhoneRequired, then set the payerPhone attribute of associated PaymentReqeust's response to payerPhone. Otherwise, set it to null.
- Deserialize serialized members:
- Let handlerResponse be value converted to an
IDL value
-
Upon fulfillment or upon rejection of
handlerResponsePromise, queue a microtask to perform the
following steps:
- Decrement the event's pending promises count by one.
- Let registration be the this's relevant global object's associated service worker's containing service worker registration.
- If registration is not null, invoke Try Activate with registration.
The following example shows how to respond to a payment request:
paymentRequestEvent.respondWith(new Promise(function(accept,reject) {
/* ... processing may occur here ... */
accept({
methodName: "https://example.com/pay",
details: {
cardHolderName: "John Smith",
cardNumber: "1232343451234",
expiryMonth: "12",
expiryYear : "2020",
cardSecurityCode: "123"
},
shippingAddress: {
addressLine: [
"1875 Explorer St #1000",
],
city: "Reston",
country: "US",
dependentLocality: "",
organization: "",
phone: "+15555555555",
postalCode: "20190",
recipient: "John Smith",
region: "VA",
sortingCode: ""
},
shippingOption: "express",
payerEmail: "john.smith@gmail.com",
});
}));
[payment-request] defines an ID that parties in the ecosystem (including payment app providers and payees) can use for reconciliation after network or other failures.
The Web Payments Working Group removed support for shipping and billing addresses from the original version of Payment Request API due to privacy issues; see issue 842. In order to provide documentation for implementations that continue to support this capability, the Working Group is now restoring the feature with an expectation of addressing privacy issues. In doing so the Working Group may also make changes to Payment Request API based on the evolution of other APIs (e.g., the Content Picker API).
- The API does not share information about the user's registered payment handlers. Information from origins is only shared with the payee with the consent of the user.
- User agents should not share payment request information with any payment handler until the user has selected that payment handler.
- In a browser that supports Payment Handler API, when a merchant
creates a PaymentRequest object with URL-based payment method
identifiers, a
CanMakePaymentEvent
will fire in registered payment handlers from a finite set of origins: the origins of the payment method manifests and their supported origins. This event is fired before the user has selected that payment handler, but it contains no information about the triggering origin (i.e., the merchant website) and so cannot be used to track users directly. - We acknowledge the risk of a timing attack via
CanMakePaymentEvent
:- A merchant website sends notice via a backend channel (e.g., the fetch API) to a payment handler origin, sharing that they are about to construct a PaymentRequest object.
- The merchant website then constructs the PaymentRequest,
triggering a
CanMakePaymentEvent
to be fired at the installed payment handler. - That payment handler contacts its own origin, and on the server side attempts to join the two requests.
- User agents should allow users to disable support for the
CanMakePaymentEvent
. - In a browser that supports Payment Handler API,
CanMakePaymentEvent
will fire in registered payment handlers that can provide all merchant requested information including shipping address and payer's contact information whenever needed.
- This specification does not define how the user agent establishes user consent when a payment handler is first registered. The user agent might notify and/or prompt the user during registration.
- User agents MAY reject payment handler registration for security reasons (e.g., due to an invalid SSL certificate) and SHOULD notify the user when this happens.
- One goal of this specification is to minimize the user interaction required to make a payment. However, we also want to ensure that the user has an opportunity to consent to making a payment. Because payment handlers are not required to open a window for user interaction, user agents should take necessary steps to make sure the user (1) is made aware when a payment request is invoked, and (2) has an opportunity to interact with a payment handler before the merchant receives the response from that payment handler.
- By design, a payment handler from one origin shares data with another origin (e.g., the merchant site).
- To mitigate phishing attacks, it is important that user agents make clear to users the origin of a payment handler.
- User agents should help users understand that they are sharing information cross-origin, and ideally what information they are sharing.
- See Service Worker security considerations
- Payment method security is outside the scope of this specification and is addressed by payment handlers that support those payment methods.
- The party responsible for a payment method authorizes payment apps through a payment method manifest. See the Handling a CanMakePaymentEvent algorithm for details.
- The user agent is not required to make available payment handlers
that pose security issues. Security issues might include:
- Certificates that are expired, revoked, self-signed, and so on.
- Mixed content
- Page available through HTTPs redirects to one that is not.
- Payment handler is known from safe browsing database to be malicious
When a payment handler is unavailable for security reasons, the user agent should provide rationale to the payment handler developers (e.g., through console messages) and may also inform the user to help avoid confusion.
- Payment method manifests authorize origins to distribute payment apps for a given payment method. When the user agent is determining whether a payment handler matches the origin listed in a payment method manifest, the user agent uses the scope URL of the payment handler's service worker registration.
- To mitigate the scenario where a hijacked payee site submits fraudlent or malformed payment method data (or, for that matter, payment request data) to the payee's server, the payee's server should validate the data format and correlate the data with authoritative information on the server such as accepted payment methods, total, display items, and shipping address.
- When the Payment Request API is invoked in a "private browsing mode," the user agent should launch payment handlers in a private context. This will generally prevent sites from accessing any previously-stored information. In turn, this is likely to require either that the user log in to the origin or re-enter payment details.
- The
CanMakePaymentEvent
event should not be fired in private browsing mode. The user agent should behave as ifrespondWith()
was called withfalse
. We acknowledge a consequent risk: if an entity controls both the origin of the Payment Request API call and the origin of the payment handler, that entity may be able to deduce that the user may be in private browsing mode.
This section is non-normative.
When ordering payment handlers, the user agent is expected to honor user preferences over other preferences. User agents are expected to permit manual configuration options, such as setting a preferred payment handler display order for an origin, or for all origins.
User experience details are left to implementers.
This specification relies on several other underlying specifications.
- Payment Request API
- The terms payment method, PaymentRequest, PaymentResponse, supportedMethods, PaymentCurrencyAmount, paymentDetailsModifier, paymentDetailsInit, paymentDetailsBase, PaymentMethodData, PaymentOptions, PaymentShippingOption, AddressInit, AddressErrors, PaymentMethodChangeEvent, PaymentRequestUpdateEvent, ID, canMakePayment(), show(), updateWith(detailsPromise), user accepts the payment request algorithm, payment method changed algorithm, PaymentRequest updated algorithm, and JSON-serializable are defined by the Payment Request API specification [payment-request].
- ECMAScript
-
The terms internal
slot and
JSON.stringify
are defined by [ECMASCRIPT]. - Payment Method Manifest
- The terms payment method manifest, ingest payment method manifest, parsed payment method manifest, and supported origins are defined by the Payment Method Manifest specification [payment-method-manifest].
- Service Workers
-
The terms service worker,
service worker registration,
service
worker client,
ServiceWorkerRegistration
,ServiceWorkerGlobalScope
, fire functional event, extend lifetime promises,pending promises count, containing service worker registration, Try Clear Registration, Try Activate, ExtendableEvent, ExtendableEventInit, and scope URL are defined in [SERVICE-WORKERS].
As well as sections marked as non-normative, all authoring guidelines, diagrams, examples, and notes in this specification are non-normative. Everything else in this specification is normative.
The key words MAY, MUST, SHOULD, and SHOULD NOT in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.
There is only one class of product that can claim conformance to this specification: a user agent.
User agents MAY implement algorithms given in this specification in any way desired, so long as the end result is indistinguishable from the result that would be obtained by the specification's algorithms.
User agents MAY impose implementation-specific limits on otherwise
unconstrained inputs, e.g., to prevent denial of service attacks, to
guard against running out of memory, or to work around
platform-specific limitations. When an input exceeds
implementation-specific limit, the user agent MUST throw, or, in the
context of a promise, reject with, a TypeError
optionally informing
the developer of how a particular input exceeded an
implementation-specific limit.
WebIDLpartial interface ServiceWorkerRegistration
{
[SameObject] readonly attribute PaymentManager
paymentManager
;
};
[SecureContext, Exposed=(Window)]
interface PaymentManager
{
attribute DOMString userHint
;
Promise<undefined> enableDelegations
(sequence<PaymentDelegation
> delegations);
};
enum PaymentDelegation
{
"shippingAddress
",
"payerName
",
"payerPhone
",
"payerEmail
"
};
partial interface ServiceWorkerGlobalScope
{
attribute EventHandler oncanmakepayment
;
};
[Exposed=ServiceWorker]
interface CanMakePaymentEvent
: ExtendableEvent {
constructor
(DOMString type);
undefined respondWith
(Promise<boolean> canMakePaymentResponse);
};
partial interface ServiceWorkerGlobalScope
{
attribute EventHandler onpaymentrequest
;
};
dictionary PaymentRequestDetailsUpdate
{
DOMString error
;
PaymentCurrencyAmount total
;
sequence<PaymentDetailsModifier> modifiers
;
sequence<PaymentShippingOption> shippingOptions
;
object paymentMethodErrors
;
AddressErrors shippingAddressErrors
;
};
[Exposed=ServiceWorker]
interface PaymentRequestEvent
: ExtendableEvent {
constructor
(DOMString type, optional PaymentRequestEventInit
eventInitDict = {});
readonly attribute USVString topOrigin
;
readonly attribute USVString paymentRequestOrigin
;
readonly attribute DOMString paymentRequestId
;
readonly attribute FrozenArray<PaymentMethodData> methodData
;
readonly attribute object total
;
readonly attribute FrozenArray<PaymentDetailsModifier> modifiers
;
readonly attribute object? paymentOptions
;
readonly attribute FrozenArray<PaymentShippingOption>? shippingOptions
;
Promise<WindowClient?> openWindow
(USVString url);
Promise<PaymentRequestDetailsUpdate
?> changePaymentMethod
(DOMString methodName, optional object? methodDetails = null);
Promise<PaymentRequestDetailsUpdate
?> changeShippingAddress
(optional AddressInit shippingAddress = {});
Promise<PaymentRequestDetailsUpdate
?> changeShippingOption
(DOMString shippingOption);
undefined respondWith
(Promise<PaymentHandlerResponse
> handlerResponsePromise);
};
dictionary PaymentRequestEventInit
: ExtendableEventInit {
USVString topOrigin
;
USVString paymentRequestOrigin
;
DOMString paymentRequestId
;
sequence<PaymentMethodData> methodData
;
PaymentCurrencyAmount total
;
sequence<PaymentDetailsModifier> modifiers
;
PaymentOptions paymentOptions
;
sequence<PaymentShippingOption> shippingOptions
;
};
dictionary PaymentHandlerResponse
{
DOMString methodName
;
object details
;
DOMString? payerName
;
DOMString? payerEmail
;
DOMString? payerPhone
;
AddressInit shippingAddress
;
DOMString? shippingOption
;
};
- [dom]
- DOM Standard. Anne van Kesteren. WHATWG. Living Standard. URL: https://dom.spec.whatwg.org/
- [ECMASCRIPT]
- ECMAScript Language Specification. Ecma International. URL: https://tc39.es/ecma262/multipage/
- [HTML]
- HTML Standard. Anne van Kesteren; Domenic Denicola; Dominic Farolino; Ian Hickson; Philip Jägenstedt; Simon Pieters. WHATWG. Living Standard. URL: https://html.spec.whatwg.org/multipage/
- [payment-method-id]
- Payment Method Identifiers. Marcos Caceres. W3C. 8 September 2022. W3C Recommendation. URL: https://www.w3.org/TR/payment-method-id/
- [payment-method-manifest]
- Payment Method Manifest. Dapeng(Max) Liu; Domenic Denicola; Zach Koch. W3C. 12 December 2017. FPWD. URL: https://www.w3.org/TR/payment-method-manifest/
- [payment-request]
- Payment Request API. Marcos Caceres; Rouslan Solomakhin; Ian Jacobs. W3C. 15 August 2025. CRD. URL: https://www.w3.org/TR/payment-request/
- [RFC2119]
- Key words for use in RFCs to Indicate Requirement Levels. S. Bradner. IETF. March 1997. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc2119
- [RFC8174]
- Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words. B. Leiba. IETF. May 2017. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc8174
- [SERVICE-WORKERS]
- Service Workers. Yoshisato Yanagisawa; Monica CHINTALA. W3C. 6 March 2025. CRD. URL: https://www.w3.org/TR/service-workers/
- [URL]
- URL Standard. Anne van Kesteren. WHATWG. Living Standard. URL: https://url.spec.whatwg.org/
- [WEBIDL]
- Web IDL Standard. Edgar Chen; Timothy Gu. WHATWG. Living Standard. URL: https://webidl.spec.whatwg.org/
- [WebCryptoAPI]
- Web Cryptography API. Mark Watson. W3C. 26 January 2017. W3C Recommendation. URL: https://www.w3.org/TR/WebCryptoAPI/
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
- § 5. Can make payment (2)
- § 5.2 The CanMakePaymentEvent (2)
- § 5.3 Handling a CanMakePaymentEvent (2)
- § 5.4 Example of handling the CanMakePaymentEvent (2) (3)
- § 5.5 Filtering of Payment Handlers (2)
- § 9.2 Information about the User Environment (2) (3) (4) (5)
- § 9.10 Private Browsing Mode
- § A. IDL Index
Referenced in:
Referenced in:
Referenced in:
Referenced in:
- § 1. Introduction (2) (3)
- § 2. Overview (2)
- § 2.1 Handling a Payment Request
- § 6. Invocation
- § 6.1.1 onpaymentrequest attribute
- § 6.3 The PaymentRequestEvent
- § 6.3.3 paymentRequestId attribute
- § 6.3.14 PaymentRequestEventInit dictionary
- § 6.4 Internal Slots
- § 6.5 Handling a PaymentRequestEvent
- § 7. Windows
- § 7.1 Open Window Algorithm (2)
- § 7.2 Example of handling the PaymentRequestEvent (2) (3)
- § 8.1.2 details attribute
- § A. IDL Index
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in: