Copyright © 2021 W3C® (MIT, ERCIM, Keio, Beihang). W3C liability, trademark and permissive document license rules apply.
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.
This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at https://www.w3.org/TR/.
The working group maintains a list of all bug reports that the group has not yet addressed. Pull requests with proposed specification text for outstanding issues are strongly encouraged.
The working group will demonstrate implementation experience by producing an implementation report. The report will show two or more independent implementations passing each mandatory test in the test suite (i.e., each test corresponds to a MUST requirement of the specification).
There has been no change in dependencies on other workings groups during the development of this specification.
This document was published by the Web Payments Working Group as a Proposed Recommendation. This document is intended to become a W3C Recommendation.
GitHub Issues are preferred for discussion of this specification.
Publication as a Proposed Recommendation does not imply endorsement by the W3C Membership.
This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress. Future updates to this specification may incorporate new features.
The W3C Membership and other interested parties are invited to review the document and send comments through 28 October 2021. Advisory Committee Representatives should consult their WBS questionnaires. Note that substantive technical comments were expected during the Candidate Recommendation review period that ended 27 July 2021.
This document was produced by a group operating under the 1 August 2017 W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.
This document is governed by the 15 September 2020 W3C Process Document.
This version of the specification removes data features from the API, essentially pushing data details to payment method descriptions. The complete list of changes, including all editorial changes, is viewable in the commit history. Key set of changes are viewable in the Changelog.
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 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.
The following are out of scope for this specification:
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:
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.").
PaymentDetailsInit
dictionary. This includes total cost, and
optionally a list of goods or services being purchased. 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".
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
.
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).
const methodData = [
{
supportedMethods: "https://example.com/payitforward",
data: {
payItForwardField: "ABC",
},
},
{
supportedMethods: "https://example.com/bobpay",
data: {
merchantIdentifier: "XXXX",
bobPaySpecificField: true,
},
},
];
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" },
},
{
label: "Standard shipping",
amount: { currency: "GBP", value: "5.00" },
},
],
total: {
label: "Total due",
// The total is GBP£65.00 here because we need to
// add tax and shipping.
amount: { currency: "GBP", value: "65.00" },
},
};
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 });
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);
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();
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 Standard:
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();
To indicate that a cross-origin iframe
is allowed to invoke the
payment request API, the 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 allow
to
"payment *"
. The Permissions Policy specification provides
further details and examples.
PaymentRequest
interface
WebIDL[SecureContext, Exposed=Window]
interface PaymentRequest
: EventTarget {
constructor
(
sequence<PaymentMethodData
> methodData,
PaymentDetailsInit
details
);
[NewObject]
Promise<PaymentResponse
> show
(optional Promise<PaymentDetailsUpdate
> detailsPromise);
[NewObject]
Promise<undefined> abort
();
[NewObject]
Promise<boolean> canMakePayment
();
readonly attribute DOMString id
;
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).
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.
The PaymentRequest
is constructed using the supplied sequence of
PaymentMethodData
methodData including any payment
method specific data
, and the
PaymentDetailsInit
details.
The PaymentRequest(methodData,
details)
constructor MUST act as follows:
payment
" permission, then throw
a "SecurityError
" DOMException
.
TypeError
, optionally informing the
developer that at least one payment method is required.
supportedMethods
. If it
returns false, then throw a RangeError
exception.
Optionally, inform the developer that the payment method
identifier is invalid.
supportedMethods
with
basic URL parser:
supportedMethods
.
RangeError
DOMException
optionally letting the
developer this payment method identifier is a duplicate.
data
member of
paymentMethod is missing, let serializedData be null.
Otherwise, let serializedData be the result of
JSON-serializing
paymentMethod.data
into a string.
Rethrow any exceptions.
supportedMethods
:
Convert object to an
IDL value of the type specified by the specification
that defines the
paymentMethod.supportedMethods
Rethrow any exceptions.
This step assures that any IDL type conversion errors are caught as early as possible.
supportedMethods
,
serializedData) to serializedMethodData.
total
.amount
.
Rethrow any exceptions.
displayItems
member of details is
present, then for each item in
details.displayItems
:
amount
. Rethrow any exceptions.
sequence
<PaymentDetailsModifier
>.
modifiers
member of details
is present, then:
modifiers
.
total
member of
modifier is present, then:
total
.amount
.
Rethrow any exceptions.
additionalDisplayItems
member
of modifier is present, then for each item of
modifier.additionalDisplayItems
:
amount
. Rethrow any
exceptions.
data
member of
modifier is missing, let serializedData be null.
Otherwise, let serializedData be the result of
JSON-serializing
modifier.data
into a string.
Rethrow any exceptions.
supportedMethods
,
serializedData) to serializedModifierData.
data
member of
modifier, if it is present.
modifiers
to
modifiers.
PaymentRequest
.
[[handler]]
to null
.
[[state]]
to
"created".
[[updating]]
to false.
[[details]]
to details.
[[serializedModifierData]]
to
serializedModifierData.
[[serializedMethodData]]
to
serializedMethodData.
[[response]]
to null.
id
attribute
When getting, the id
attribute returns this
PaymentRequest
's
[[details]]
.id
.
For auditing and reconciliation purposes, a merchant can associate
a unique identifier for each transaction with the
id
attribute.
show()
method
The show
()
method is called when a developer
wants to begin user interaction for the payment request. The
show
()
method returns a Promise
that will be
resolved when the user accepts the payment request. Some
kind of user interface will be presented to the user to facilitate
the payment request after the show
()
method
returns.
Each payment handler controls what happens when multiple browsing
context simultaneously call the 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:
SecurityError
"
DOMException
.
Document
.
AbortError
" DOMException
.
Optionally, if the user agent wishes to disallow the call
to show
()
to protect the user, then return a
promise rejected with a "SecurityError
" DOMException
. For
example, the user agent may limit the rate at which a page
can call show
()
, as described in section
§ 14.
Privacy and Security Considerations.
[[state]]
is not
"created" then return a promise rejected
with an "InvalidStateError
" DOMException
.
[[state]]
to
"closed".
AbortError
"
DOMException
.
[[state]]
to
"interactive".
[[acceptPromise]]
to
acceptPromise.
Optionally:
AbortError
"
DOMException
.
[[state]]
to
"closed".
This allows the user agent to act as if the user had immediately aborted the payment request, at its discretion. For example, in "private browsing" modes or similar, user agents might take advantage of this step.
[[serializedMethodData]]
:
object
.
[[state]]
to
"closed".
[[state]]
to
"closed".
NotSupportedError
"
DOMException
.
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's language, if any, or an appropriate fallback if that is not available.
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.
[[handler]]
be the payment
handler selected by the end-user.
[[serializedModifierData]]
:
[[handler]]
, then append the second
element of tuple (the serialized method data) to modifiers.
Pass the 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
[[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
[[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).
The acceptPromise will later be resolved or rejected by either the user accepts the payment request algorithm or the user aborts the payment request algorithm, which are triggered through interaction with the user interface.
If document stops being fully active while the user interface is being shown, or no longer is by the time this step is reached, then:
abort()
method
The abort
()
method is called if a developer
wishes to tell the user agent to abort the payment request
and to tear down any user interface that might be shown. The
abort
()
can only be called after the
show
()
method has been called (see
states) and before this instance's
[[acceptPromise]]
has been resolved. For
example, developers might choose to do this if the goods they are
selling are only available for a limited amount of time. If the
user does not accept the payment request within the allowed time
period, then the request will be aborted.
A user agent might not always be able to abort a request.
For example, if the user agent has delegated responsibility
for the request to another app. In this situation,
abort
()
will reject the returned Promise
.
See also the algorithm when the user aborts the payment request.
The abort
()
method MUST act as follows:
[[response]]
is not null, and
request.[[response]]
.[[retryPromise]]
is not null, return a promise rejected with an
"InvalidStateError
" DOMException
.
[[state]]
is not
"interactive" then return a promise rejected
with an "InvalidStateError
" DOMException
.
InvalidStateError
"
DOMException
and abort these steps.
[[state]]
to
"closed".
[[acceptPromise]]
with an
"AbortError
" DOMException
.
canMakePayment()
method
The canMakePayment
()
method can be used by the
developer to determine if the user agent has support for one
of the desired payment methods. See
§ 14.8
canMakePayment()
protections.
A true result from canMakePayment
()
does not
imply that the user has a provisioned instrument ready for payment.
The canMakePayment
()
method MUST run the can
make payment algorithm.
onpaymentmethodchange
attribute
A PaymentRequest
's onpaymentmethodchange
attribute is an EventHandler
for a PaymentMethodChangeEvent
named "paymentmethodchange
".
Instances of PaymentRequest
are created with the internal slots in the following table:
Internal Slot | Description (non-normative) |
---|---|
[[serializedMethodData]] |
The methodData supplied to the constructor, but
represented as tuples containing supported methods and a string
or null for data (instead of the original object form).
|
[[serializedModifierData]] |
A list containing the serialized string form of each
data member for each corresponding
item in the sequence
[[details]] .modifier ,
or null if no such member was present.
|
[[details]] |
The current PaymentDetailsBase for the payment request
initially supplied to the constructor and then updated with calls
to updateWith () . Note that all
data members of
PaymentDetailsModifier instances contained in the
modifiers member will be removed, as they
are instead stored in serialized form in the
[[serializedModifierData]] internal slot.
|
[[state]] |
The current state of the payment request, which transitions from:
The state transitions are illustrated in the figure below: |
[[updating]] |
True if there is a pending
updateWith () call to update the
payment request and false otherwise.
|
[[acceptPromise]] |
The pending Promise created during show ()
that will be resolved if the user accepts the payment request.
|
[[response]] |
Null, or the PaymentResponse instantiated by this
PaymentRequest .
|
[[handler]] |
The Payment Handler associated with this
PaymentRequest . Initialized to null .
|
PaymentMethodData
dictionary
WebIDLdictionary PaymentMethodData
{
required DOMString supportedMethods
;
object data
;
};
A PaymentMethodData
dictionary is used to indicate a set of
supported payment methods and any associated payment
method specific data for those methods.
supportedMethods
member
data
member
The value of supportedMethods
was changed from array to
string, but the name was left as a plural to maintain compatibility
with existing content on the Web.
PaymentCurrencyAmount
dictionary
WebIDLdictionary PaymentCurrencyAmount
{
required DOMString currency
;
required DOMString value
;
};
A PaymentCurrencyAmount
dictionary is used to supply monetary
amounts.
currency
member
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
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.
value
member
{
"currency": "OMR",
"value": "1.234"
}
A JavaScript string is a valid decimal monetary value if it consists of the following code points in the given order:
^-?[0-9]+(\.[0-9]+)?$
To check and canonicalize amount given a
PaymentCurrencyAmount
amount, run the following steps:
currency
)
is false, then throw a RangeError
exception, optionally informing
the developer that the currency is invalid.
value
is not a valid
decimal monetary value, throw a TypeError
, optionally
informing the developer that the currency is invalid.
currency
to the result of
ASCII uppercase amount.currency
.
To check and canonicalize total amount given a
PaymentCurrencyAmount
amount, run the
following steps:
value
is U+002D (-), then throw a
TypeError
optionally informing the developer that a total's value
can't be a negative number.
PaymentDetailsBase
dictionary
WebIDLdictionary PaymentDetailsBase
{
sequence<PaymentItem
> displayItems
;
sequence<PaymentDetailsModifier
> modifiers
;
};
displayItems
member
PaymentItem
dictionaries contains line items for
the payment request that the user agent MAY display.
modifiers
member
PaymentDetailsModifier
dictionaries that contains
modifiers for particular payment method identifiers. For example,
it allows you to adjust the total amount based on payment method.
PaymentDetailsInit
dictionary
WebIDLdictionary PaymentDetailsInit
: PaymentDetailsBase
{
DOMString id
;
required PaymentItem
total
;
};
In addition to the members inherited from the PaymentDetailsBase
dictionary, the following members are part of the
PaymentDetailsInit
dictionary:
id
member
total
member
PaymentItem
containing a non-negative total amount for the
payment request.
PaymentDetailsUpdate
dictionary
WebIDLdictionary PaymentDetailsUpdate
: PaymentDetailsBase
{
PaymentItem
total
;
object paymentMethodErrors
;
};
The PaymentDetailsUpdate
dictionary is used to update the payment
request using updateWith
()
.
In addition to the members inherited from the PaymentDetailsBase
dictionary, the following members are part of the
PaymentDetailsUpdate
dictionary:
total
member
PaymentItem
containing a non-negative amount
.
Algorithms in this specification that accept a
PaymentDetailsUpdate
dictionary will throw if the
total
.amount
.value
is a negative number.
paymentMethodErrors
member
Payment method specific errors.
PaymentDetailsModifier
dictionary
WebIDLdictionary PaymentDetailsModifier
{
required DOMString supportedMethods
;
PaymentItem
total
;
sequence<PaymentItem
> additionalDisplayItems
;
object data
;
};
The PaymentDetailsModifier
dictionary provides details that modify
the PaymentDetailsBase
based on a payment method identifier.
It contains the following members:
supportedMethods
member
PaymentDetailsModifier
only apply if the user selects this
payment method.
total
member
PaymentItem
value that overrides the
total
member in the PaymentDetailsInit
dictionary for the payment method identifiers of the
supportedMethods
member.
additionalDisplayItems
member
PaymentItem
dictionaries provides additional
display items that are appended to the
displayItems
member in the
PaymentDetailsBase
dictionary for the payment method
identifiers in the supportedMethods
member. This member is commonly used to add a discount or surcharge
line item indicating the reason for the different
total
amount for the selected payment
method that the user agent MAY display.
It is the developer's responsibility to verify that the
total
amount is the sum of the
displayItems
and the
additionalDisplayItems
.
data
member
PaymentItem
dictionary
WebIDLdictionary PaymentItem
{
required DOMString label
;
required PaymentCurrencyAmount
amount
;
boolean pending
= false;
};
A sequence of one or more PaymentItem
dictionaries is included in
the PaymentDetailsBase
dictionary to indicate what the payment
request is for and the value asked for.
label
member
amount
member
PaymentCurrencyAmount
containing the monetary amount for the
item.
pending
member
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.
PaymentComplete
enum
WebIDLenum PaymentComplete
{
"fail
",
"success
",
"unknown
"
};
fail
"
success
"
unknown
"
PaymentResponse
interface
WebIDL[SecureContext, Exposed=Window]
interface PaymentResponse
: EventTarget {
[Default] object toJSON();
readonly attribute DOMString requestId
;
readonly attribute DOMString methodName
;
readonly attribute object details
;
[NewObject]
Promise<undefined> complete
(optional PaymentComplete
result = "unknown");
[NewObject]
Promise<undefined> retry
(optional PaymentValidationErrors
errorFields = {});
};
A PaymentResponse
is returned when a user has selected a payment
method and approved a payment request.
retry()
method
The retry(errorFields)
method
MUST act as follows:
[[request]]
.
AbortError
" DOMException
.
[[complete]]
is true, return
a promise rejected with an "InvalidStateError
"
DOMException
.
[[retryPromise]]
is not null,
return a promise rejected with an "InvalidStateError
"
DOMException
.
[[state]]
to
"interactive".
[[retryPromise]]
to
retryPromise.
paymentMethod
member was passed, and if required by the specification that
defines response.payment
/a>, then
convert errorFields's
paymentMethod
member to an IDL value
of the type specified there. Otherwise, convert to object
.
error
member is passed,
present the error in the user agent's UI. In the case where the
value of a member is the empty string, the user agent MAY
substitute a value with a suitable error message.
[[retryPromise]]
to null.
The retryPromise will later be resolved by the user accepts the payment request algorithm, or rejected by either the user aborts the payment request algorithm or abort the update.
PaymentValidationErrors
dictionary
WebIDLdictionary PaymentValidationErrors
{
DOMString error
;
object paymentMethod
;
};
error
member
error
member on its own to give a
general overview of validation issues, or it can be passed in
combination with other members of the PaymentValidationErrors
dictionary.
paymentMethod
member
methodName
attribute
The payment method identifier for the payment method that the user selected to fulfill the transaction.
details
attribute
An object
or dictionary generated by a payment
method that a merchant can use to process or validate a
transaction (depending on the payment method).
requestId
attribute
The corresponding payment request id
that spawned
this payment response.
complete()
method
The complete
()
method is called after the user
has accepted the payment request and the
[[acceptPromise]]
has been resolved. Calling the
complete
()
method tells the user agent
that the payment interaction is over (and SHOULD cause any remaining
user interface to be closed).
After the payment request has been accepted and the
PaymentResponse
returned to the caller, but before the caller
calls complete
()
, the payment request user
interface remains in a pending state. At this point the user
interface 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 complete
()
then the
user interface is blocked.
For this reason, implementations MAY impose a timeout for developers
to call complete
()
. If the timeout expires then
the implementation will behave as if complete
()
was called with no arguments.
The complete
()
method MUST act as follows:
[[complete]]
is true, return
a promise rejected with an "InvalidStateError
"
DOMException
.
[[retryPromise]]
is not null,
return a promise rejected with an "InvalidStateError
"
DOMException
.
[[complete]]
to true.
Instances of PaymentResponse
are created with the internal slots in the following table:
Internal Slot | Description (non-normative) |
---|---|
[[complete]] |
Is true if the request for payment has completed (i.e.,
complete () was called, or there was a fatal
error that made the response not longer usable), or false
otherwise.
|
[[request]] |
The PaymentRequest instance that instantiated this
PaymentResponse .
|
[[retryPromise]] |
Null, or a Promise that resolves when a user accepts the
payment request or rejects if the user aborts the payment
request.
|
This specification defines a policy-controlled feature identified
by the string "payment
" [permissions-policy]. Its default
allowlist is 'self
'.
This section is non-normative.
Event name | Interface | Dispatched when… | Target |
---|---|---|---|
paymentmethodchange
|
PaymentMethodChangeEvent
|
The user chooses a different payment method within a payment handler. |
PaymentRequest
|
PaymentMethodChangeEvent
interface
WebIDL[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
methodDetails
member of
PaymentMethodChangeEventInit
for more information.
methodName
attribute
When getting, returns the value it was initialized with. See
methodName
member of
PaymentMethodChangeEventInit
for more information.
PaymentMethodChangeEventInit
dictionary
WebIDLdictionary PaymentMethodChangeEventInit
: PaymentRequestUpdateEventInit
{
DOMString methodName
= "";
object? methodDetails
= null;
};
methodName
member
methodDetails
member
PaymentRequestUpdateEvent
interface
WebIDL[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.
Constructor
The PaymentRequestUpdateEvent
's
constructor
(type, eventInitDict)
MUST
act as follows:
PaymentRequestUpdateEvent
with
type and eventInitDict.
[[waitForUpdate]]
to
false.
updateWith()
method
The updateWith
()
with
detailsPromise method MUST act as follows:
isTrusted
attribute is false, then
throw an "InvalidStateError
" DOMException
.
[[waitForUpdate]]
is
true, then throw an "InvalidStateError
"
DOMException
.
PaymentResponse
, let request be event's
target's [[request]]
.
PaymentRequest
.
[[state]]
is not
"interactive", then throw an
"InvalidStateError
" DOMException
.
[[updating]]
is true, then
throw an "InvalidStateError
" DOMException
.
[[waitForUpdate]]
to
true.
methodName
attribute, set pmi to the methodName
attribute's value.
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
updateWith () -initiated update is
currently in progress.
|
PaymentRequestUpdateEventInit
dictionary
WebIDLdictionary PaymentRequestUpdateEventInit
: EventInit {};
When the internal slot [[state]]
of a
PaymentRequest
object is set to "interactive",
the user agent will trigger the following algorithms based on
user interaction.
The can make payment algorithm checks if the user
agent supports making payment with the payment methods
with which the PaymentRequest
was constructed.
PaymentRequest
object on
which the method was called.
[[state]]
is not
"created", then return a promise rejected
with an "InvalidStateError
" DOMException
.
NotAllowedError
" DOMException
.
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.
[[serializedMethodData]]
:
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.
PaymentRequest
object
that the user is interacting with.
[[updating]]
is false.
Only one update can take place at a time.
[[state]]
is
"interactive".
paymentmethodchange
" at
request using PaymentMethodChangeEvent
, with its
methodName
attribute initialized
to methodName, and its
methodDetails
attribute
initialized to methodDetails.
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:
[[updating]]
is false. Only
one update can take place at a time.
[[state]]
is
"interactive".
PaymentRequestUpdateEvent
interface.
type
attribute to name.
[[waitForUpdate]]
is
true, disable any part of the user interface that could cause another
update event to be fired.
[[waitForUpdate]]
to true.
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:
PaymentRequest
object
that the user is interacting with.
[[updating]]
is true, then
terminate this algorithm and take no further action. The user
agent user interface SHOULD ensure that this never occurs.
[[state]]
is not
"interactive", then terminate this algorithm and
take no further action. The user agent user interface SHOULD
ensure that this never occurs.
[[response]]
is not null, false
otherwise.
[[response]]
if isRetry is true, or a
new PaymentResponse
otherwise.
[[request]]
to request.
[[retryPromise]]
to null.
[[complete]]
to false.
requestId
attribute value of
response to the value of
request.[[details]]
.id
.
[[response]]
to response.
[[handler]]
.
methodName
attribute value of
response to the payment method identifier of handler.
details
attribute value of response
to an object resulting from running the handler's steps to
respond to a payment request.
[[state]]
to
"closed".
[[retryPromise]]
with undefined.
Otherwise, resolve request.[[acceptPromise]]
with response.
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
object
that the user is interacting with.
[[state]]
is not
"interactive", then terminate this algorithm and
take no further action. The user agent user interface SHOULD
ensure that this never occurs.
[[state]]
to
"closed".
AbortError
" DOMException
.
[[response]]
.
[[complete]]
to true.
[[retryPromise]]
is
not null.
[[retryPromise]]
with
error.
[[acceptPromise]]
with error.
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.
[[updating]]
to true.
AbortError
"
DOMException
.
PaymentDetailsUpdate
dictionary. If this throw
an exception, abort the update with request and with the
thrown exception.
total
member of details
is present, then:
total
.amount
.
If an exception is thrown, then abort the update
with request and that exception.
displayItems
member of
details is present, then for each item in
details.displayItems
:
amount
. If an exception is
thrown, then abort the update with request and
that exception.
modifiers
member of
details is present, then:
modifiers
.
PaymentDetailsModifier
modifier in
modifiers:
supportedMethods
.
If it returns false, then abort the update
with request and a RangeError
exception.
Optionally, inform the developer that the payment
method identifier is invalid.
total
member of
modifier is present, then:
total
.amount
.
If an exception is thrown, then abort the
update with request and that exception.
additionalDisplayItems
member of modifier is present, then for each
PaymentItem
item in
modifier.additionalDisplayItems
:
amount
. If an exception
is thrown, then abort the update with
request and that exception.
data
member of
modifier is missing, let serializedData be null.
Otherwise, let serializedData be the result of
JSON-serializing
modifier.data
into a
string. If JSON-serializing throws an
exception, then abort the update with
request and that exception.
data
member
of modifier, if it is present.
paymentMethodErrors
member is
present and identifier is not null:
paymentMethodErrors
to an IDL value.
paymentMethodErrors
.
PaymentRequest
using the new details:
total
member of details
is present, then:
[[details]]
.total
to details.total
.
displayItems
member of
details is present, then:
[[details]]
.displayItems
to details.displayItems
.
modifiers
member of
details is present, then:
[[details]]
.modifiers
to details.modifiers
.
[[serializedModifierData]]
to serializedModifierData.
[[updating]]
to false.
To abort the update with a
PaymentRequest
request and exception exception:
[[state]]
to
"closed".
[[response]]
.
[[complete]]
to
true.
[[retryPromise]]
is not null.
[[retryPromise]]
with exception.
[[acceptPromise]]
with
exception.
[[updating]]
to false.
Abort the update runs when there is a fatal error updating the payment request, such as the supplied detailsPromise rejecting, or its fulfillment value containing invalid data. This would potentially leave the payment request in an inconsistent state since the developer hasn't successfully handled the change event.
Consequently, the PaymentRequest
moves to a
"closed" state. The error is signaled to the
developer through the rejection of the
[[acceptPromise]]
, i.e., the promise returned by
show
()
.
Similarly, abort the update occurring during
retry
()
causes the
[[retryPromise]]
to reject, and the
corresponding PaymentResponse
's
[[complete]]
internal slot will be set to
true (i.e., it can no longer be used).
show()
method
This section is non-normative.
To help ensure that users do not inadvertently share sensitive
credentials with an origin, this API requires that PaymentRequest's
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
show
()
method. In addition, the user agent can
limit the rate at which a page can call show
()
.
This section is non-normative.
The 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.
This section is non-normative.
It is common for merchants and other payees to delegate checkout and
other e-commerce activities to payment service providers through an
iframe. This API supports payee-authorized cross-origin
iframes through [HTML]'s 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).
This section is non-normative.
The PaymentRequest
API does not directly support encryption of
data fields. Individual payment methods may choose to include
support for encrypted data but it is not mandatory that all
payment methods support this.
This section is non-normative.
As part of show
()
, the user agent typically
displays a list of matching payment handlers that satisfy the
payment methods accepted by the merchant and other conditions.
Matching can take into account payment method information
provided as input to the API, information provided by the payment
method owner, the payment handlers registered by the user,
user preferences, and other considerations.
For security reasons, a user agent can limit matching (in
show
()
and canMakePayment
()
) to
payment handlers from the same origin as a URL payment method
identifier.
Payment 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.
The user agent MUST NOT share information about the user with a developer without user consent.
In particular, the PaymentMethodData
's data
and PaymentResponse
's 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
details
member carries data from the payment
handler, whether Web-based (as defined by the Payment Handler API)
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
displayItems
member or
additionalDisplayItems
member with a
third-party payment handler without user consent.
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
methodDetails
attribute. Requirements
and approaches for minimizing shared data are likely to vary by
payment method.
Where sharing of privacy-sensitive information might not be obvious to users (e.g., when 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 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. purposes. 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 eTLDs or the user experience friction of opening multiple windows (tabs or pop-ups).
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.
This specification relies on several other underlying specifications.
JSON-serialize runs JSON stringify
()
, passing the
supplied object as the sole argument, and returns the resulting
string. This can throw an exception.
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.
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.
WebIDL[SecureContext, Exposed=Window]
interface PaymentRequest
: EventTarget {
constructor
(
sequence<PaymentMethodData
> methodData,
PaymentDetailsInit
details
);
[NewObject]
Promise<PaymentResponse
> show
(optional Promise<PaymentDetailsUpdate
> detailsPromise);
[NewObject]
Promise<undefined> abort
();
[NewObject]
Promise<boolean> canMakePayment
();
readonly attribute DOMString id
;
attribute EventHandler onpaymentmethodchange
;
};
dictionary PaymentMethodData
{
required DOMString supportedMethods
;
object data
;
};
dictionary PaymentCurrencyAmount
{
required DOMString currency
;
required DOMString value
;
};
dictionary PaymentDetailsBase
{
sequence<PaymentItem
> displayItems
;
sequence<PaymentDetailsModifier
> modifiers
;
};
dictionary PaymentDetailsInit
: PaymentDetailsBase
{
DOMString id
;
required PaymentItem
total
;
};
dictionary PaymentDetailsUpdate
: PaymentDetailsBase
{
PaymentItem
total
;
object paymentMethodErrors
;
};
dictionary PaymentDetailsModifier
{
required DOMString supportedMethods
;
PaymentItem
total
;
sequence<PaymentItem
> additionalDisplayItems
;
object data
;
};
dictionary PaymentItem
{
required DOMString label
;
required PaymentCurrencyAmount
amount
;
boolean pending
= false;
};
enum PaymentComplete
{
"fail
",
"success
",
"unknown
"
};
[SecureContext, Exposed=Window]
interface PaymentResponse
: EventTarget {
[Default] object toJSON();
readonly attribute DOMString requestId
;
readonly attribute DOMString methodName
;
readonly attribute object details
;
[NewObject]
Promise<undefined> complete
(optional PaymentComplete
result = "unknown");
[NewObject]
Promise<undefined> retry
(optional PaymentValidationErrors
errorFields = {});
};
dictionary PaymentValidationErrors
{
DOMString error
;
object paymentMethod
;
};
[SecureContext, Exposed=Window]
interface PaymentMethodChangeEvent
: PaymentRequestUpdateEvent
{
constructor
(DOMString type, optional PaymentMethodChangeEventInit
eventInitDict = {});
readonly attribute DOMString methodName
;
readonly attribute object? methodDetails
;
};
dictionary PaymentMethodChangeEventInit
: PaymentRequestUpdateEventInit
{
DOMString methodName
= "";
object? methodDetails
= null;
};
[SecureContext, Exposed=Window]
interface PaymentRequestUpdateEvent
: Event {
constructor
(DOMString type, optional PaymentRequestUpdateEventInit
eventInitDict = {});
undefined updateWith
(Promise<PaymentDetailsUpdate
> detailsPromise);
};
dictionary PaymentRequestUpdateEventInit
: EventInit {};
This specification was derived from a report published previously by the Web Platform Incubator Community Group.
Changes from between CR2 until now:
Changes from between CR1 and CR2:
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:
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:
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:
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: