Copyright © 2018 W3C ® ( MIT , ERCIM , Keio , Beihang ). W3C liability , trademark and permissive document license rules apply.
This specification defines capabilities that enable Web applications to handle requests for payment.
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 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 an Editor's Draft.
Publication as an Editor's Draft 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.
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 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 1 February 2018 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:
PaymentRequestEvent
).
A
payment
handler
is
an
event
handler
for
the
PaymentRequestEvent
.
PaymentInstrument
s.
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:
method
and
optional
capabilities
inform
the
user
agent
decision
whether
to
display
this
instrument
as
a
candidate
for
payment.
name
and
icon
.
These
provide
hints
about
payment
credentials
that
the
user
agent
will
return
in
the
PaymentHandlerResponse
if
the
user
selects
this
instrument.
CanMakePaymentEvent
is
used
as
part
of
determining
whether
there
is
a
match.
instruments
of
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.
PaymentRequestEvent
(cf.
the
user
interaction
task
source
)
in
the
service
worker
whose
PaymentManager
the
instrument
was
registered
with.
The
PaymentRequestEvent
includes
some
information
from
the
PaymentRequest
(defined
in
[
payment-request
])
as
well
as
additional
information
(e.g.,
origin
and
selected
instrument).
An origin may implement a payment app with more than one service worker and therefore multiple payment handler s may be registered per origin. The handler that is invoked is determined by the selection made by the user of a payment instrument . The service worker which stored the payment instrument with its PaymentManager is the one that will be invoked.
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, such as basic-card 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 [ WebCryptoAPI ]) 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:
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.
PaymentRequestEvent
s.
PaymentManager
s
manage
the
definition,
display,
and
user
selection
of
PaymentInstrument
s.
A
PaymentInstrument
supports
one
or
more
payment
methods.
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.
ServiceWorkerRegistration
interface
This
specification
extends
the
ServiceWorkerRegistration
interface
with
the
addition
of
a
paymentManager
attribute.
partial interface ServiceWorkerRegistration
{
readonly attribute PaymentManager paymentManager
;
};
The
paymentManager
attribute
exposes
payment
handler
functionality
in
the
service
worker.
[SecureContext,
Exposed=(Window,Worker)]
interface PaymentManager {
[SameObject]
readonly attribute PaymentInstruments
instruments
;
[Exposed=Window] static Promise<PermissionState> requestPermission();
attribute DOMString userHint
;
};
The PaymentManager is used by payment handler s to manage their associated instruments and supported payment methods.
instruments
attribute
This attribute allows manipulation of payment instruments associated with a service worker (and therefore its payment handler). To be a candidate payment handler, a handler must have at least one registered payment instrument to present to the user. That instrument needs to match the payment methods and required capabilities specified by the payment request.
requestPermission()
method
The user agent is NOT REQUIRED to prompt the user to grant permission to the origin for each new supported payment method or new payment instrument.
When called, this method executes the following steps:
userHint
attribute
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. When a agent displays all payment instruments available through a payment handler, it may cause confusion to display the additional hint.
PaymentInstruments
interface
[SecureContext,
Exposed=(Window,Worker)]
interface PaymentInstruments
{
Promise<boolean> delete(DOMString instrumentKey);
Promise<any> get(DOMString instrumentKey);
Promise<sequence<DOMString>> keys();
Promise<boolean> has(DOMString instrumentKey);
Promise<void> set(DOMString instrumentKey,
PaymentInstrument
details);
Promise<void> clear();
};
The
PaymentInstruments
interface
represents
a
collection
of
payment
instruments,
each
uniquely
identified
by
an
instrumentKey
.
The
instrumentKey
identifier
will
be
passed
to
the
payment
handler
to
indicate
the
PaymentInstrument
selected
by
the
user,
if
any.
delete()
method
When called, this method executes the following steps:
PaymentInstrument
with
a
matching
instrumentKey
,
remove
it
from
the
collection
and
resolve
p
with
true
.
get()
method
When called, this method executes the following steps:
PaymentInstrument
with
a
matching
instrumentKey
,
resolve
p
with
that
PaymentInstrument
.
undefined
.
keys()
method
When called, this method executes the following steps:
PaymentInstrument
s
contained
in
the
collection,
in
original
insertion
order.
has()
method
When called, this method executes the following steps:
PaymentInstrument
with
a
matching
instrumentKey
,
resolve
p
with
true
.
set()
method
When called, this method executes the following steps:
NotAllowedError
"
DOMException
.
icons
member
of
details
is
present,
then:
icons
member
of
details
is
present,
then
for
each
icon
in
details
.
icons
:
PaymentInstrument
with
a
matching
instrumentKey
,
replace
it
with
the
PaymentInstrument
in
details
.
PaymentInstrument
in
details
as
a
new
member
of
the
collection
and
associate
it
with
the
key
instrumentKey
.
clear()
method
When called, this method executes the following steps:
PaymentInstrument
s
from
the
collection
and
resolve
p
.
PaymentInstrument
dictionary
dictionary PaymentInstrument
{
required DOMString name
;
sequence<ImageObject
> icons
;
DOMString method
;
object capabilities
;
};
name
member
name
member
is
a
string
that
represents
the
label
for
this
PaymentInstrument
as
it
is
usually
displayed
to
the
user.
icons
member
icons
member
is
an
array
of
image
objects
that
can
serve
as
iconic
representations
of
the
payment
instrument
when
presented
to
the
user
for
selection.
method
member
method
member
is
the
payment
method
identifier
of
the
payment
method
supported
by
this
instrument.
capabilities
member
capabilities
member
is
a
list
of
payment-method-specific
capabilities
that
this
payment
handler
is
capable
of
supporting
for
this
instrument.
For
example,
for
the
basic-card
payment
method,
this
object
will
consist
of
an
object
with
two
fields:
one
for
supportedNetworks
,
and
another
for
supportedTypes
.
ImageObject
dictionary
src
member
src
member
is
used
to
specify
the
ImageObject
's
source.
It
is
a
URL
from
which
the
user
agent
can
fetch
the
image’s
data.
sizes
member
sizes
member
is
used
to
specify
the
ImageObject
's
sizes.
It
follows
the
spec
of
sizes
member
in
HTML
link
element
,
which
is
a
string
consisting
of
an
unordered
set
of
unique
space-separated
tokens
which
are
ASCII
case-insensitive
that
represents
the
dimensions
of
an
image.
Each
keyword
is
either
an
ASCII
case-insensitive
match
for
the
string
"any",
or
a
value
that
consists
of
two
valid
non-negative
integers
that
do
not
have
a
leading
U+0030
DIGIT
ZERO
(0)
character
and
that
are
separated
by
a
single
U+0078
LATIN
SMALL
LETTER
X
or
U+0058
LATIN
CAPITAL
LETTER
X
character.
The
keywords
represent
icon
sizes
in
raw
pixels
(as
opposed
to
CSS
pixels).
When
multiple
image
objects
are
available,
a
user
agent
MAY
use
the
value
to
decide
which
icon
is
most
suitable
for
a
display
context
(and
ignore
any
that
are
inappropriate).
The
parsing
steps
for
the
sizes
member
MUST
follow
the
parsing
steps
for
HTML
link
element
sizes
attribute
.
type
member
type
member
is
used
to
specify
the
ImageObject
's
MIME
type.
It
is
a
hint
as
to
the
media
type
of
the
image.
The
purpose
of
this
member
is
to
allow
a
user
agent
to
ignore
images
of
media
types
it
does
not
support.
When this algorithm with inputImages parameter is invoked, the user agent must run the following steps:
ImageObject
.
type
is
not
a
valid
MIME
type
or
the
value
of
type
is
not
a
supported
media
format,
then
return
an
empty
Sequence
of
ImageObject
.
sizes
is
not
a
valid
value
,
then
return
an
empty
Sequence
of
ImageObject
.
src
with
the
context
object
's
relevant
settings
object
's
API
base
URL
.
ImageObject
.
ImageObject
.
src
to
url
.
According
to
the
step
2.3,
it
is
also
possible
to
use
the
relative
url
for
image
.
src
.
The
following
examples
illustrate
how
relative
URL
resolution
works
in
different
execution
contexts.
<-- In this example, code is located in https://www.example.com/bobpay/index.html -->
<script>
const instrumentKey = "c8126178-3bba-4d09-8f00-0771bcfd3b11";
const registration = await navigator.serviceWorker.register("/register/sw.js");
await registration.paymentManager.paymentInstruments.set({
instrumentKey,
{
name: "My Bob Pay Account: john@example.com",
method: "https://bobpay.com",
icons: [{
src: "icon/lowres.webp",
sizes: "48x48",
type: "image/webp"
}]
});
const { storedInstrument } =
await registration.paymentManager.paymentInstruments.get(instrumentKey);
// storedInstrument.icons[0].src == "https://www.example.com/bobpay/icon/lowres.webp";
</script>
// In this example, code is located in https://www.example.com/register/sw.js
const instrumentKey = "c8126178-3bba-4d09-8f00-0771bcfd3b11";
await self.registration.paymentManager.paymentInstruments.set({
instrumentKey,
{
name: "My Bob Pay Account: john@example.com",
method: "https://bobpay.com",
icons: [{
src: "../bobpay/icon/lowres.webp",
sizes: "48x48",
type: "image/webp"
}]
});
const { storedInstrument } =
await registration.paymentManager.paymentInstruments.get(instrumentKey);
// storedInstrument.icons[0].src == "https://www.example.com/bobpay/icon/lowres.webp";
This section is non-normative.
The following example shows how to register a payment handler:
button.addEventListener("click", async() => {
if (!window.PaymentManager) {
return; // not supported, so bail out.
}
const result = await PaymentManager.requestPermission();
if (result !== "granted") {
return;
}
const registration =
await navigator.serviceWorker.register("/sw.js");
// Excellent, we got it! Let's now set up the user's cards.
await addInstruments(registration);
}, { once: true });
function addInstruments(registration) {
return Promise.all([
registration.paymentManager.instruments.set(
"dc2de27a-ca5e-4fbd-883e-b6ded6c69d4f",
{
name: "Visa ending ****4756",
method: "basic-card",
capabilities: {
supportedNetworks: ["visa"],
supportedTypes: ["credit"]
}
}),
registration.paymentManager.instruments.set(
"c8126178-3bba-4d09-8f00-0771bcfd3b11",
{
name: "My Bob Pay Account: john@example.com",
method: "https://bobpay.com"
}),
registration.paymentManager.instruments.set(
"new-card",
{
name: "Add new credit/debit card to ExampleApp",
method: "basic-card",
capabilities: {
supportedNetworks:
["visa", "mastercard", "amex", "discover"],
supportedTypes: ["credit", "debit", "prepaid"]
}
}),
]);
};
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
.
ServiceWorkerGlobalScope
This
specification
extends
the
ServiceWorkerGlobalScope
interface.
partial interface ServiceWorkerGlobalScope
{
attribute EventHandler oncanmakepayment
;
};
oncanmakepayment
attribute
The
oncanmakepayment
attribute
is
an
event
handler
whose
corresponding
event
handler
event
type
is
canmakepayment.
CanMakePaymentEvent
The
CanMakePaymentEvent
is
used
to
check
whether
the
payment
handler
is
able
to
respond
to
a
payment
request.
[Constructor(DOMString type, CanMakePaymentEventInit
eventInitDict),
Exposed=ServiceWorker]
interface CanMakePaymentEvent
: ExtendableEvent {
readonly attribute USVString topLevelOrigin
;
readonly attribute USVString paymentRequestOrigin
;
readonly attribute FrozenArray<PaymentMethodData> methodData
;
readonly attribute FrozenArray<PaymentDetailsModifier> modifiers
;
void respondWith(Promise<boolean> canMakePaymentResponse);
};
The
topLevelOrigin
,
paymentRequestOrigin
,
methodData
,
and
modifiers
members
share
their
definitions
with
those
defined
for
PaymentRequestEvent
.
respondWith()
method
This method is used by the payment handler to indicate whether it can respond to a payment request. The respondWith(canMakePaymentPromise) method MUST act as follows:
CanMakePaymentEvent
instance.
InvalidStateError
"
DOMException
.
InvalidStateError
"
DOMException
.
InvalidStateError
"
DOMException
.
CanMakePaymentEventInit
dictionary
dictionary CanMakePaymentEventInit
: ExtendableEventInit {
USVString topLevelOrigin
;
USVString paymentRequestOrigin
;
sequence<PaymentMethodData> methodData
;
sequence<PaymentDetailsModifier> modifiers
;
};
The
topLevelOrigin
,
paymentRequestOrigin
,
methodData
,
and
modifiers
members
share
their
definitions
with
those
defined
for
PaymentRequestEvent
.
Upon receiving a PaymentRequest , the user agent MUST run the following steps:
CanMakePaymentEvent
(e.g.,
in
private
browsing
mode),
terminate
these
steps.
ServiceWorkerRegistration
.
ServiceWorkerRegistration
of
registration
and
callbackSteps
set
to
the
following
steps:
CanMakePaymentEvent
interface,
with
the
event
type
canmakepayment,
which
does
not
bubble,
cannot
be
canceled,
and
has
no
default
action.
topLevelOrigin
,
paymentRequestOrigin
,
methodData
,
and
modifiers
attributes
of
e
the
same
way
as
when
handling
PaymentRequestEvent
.
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(true);
});
Given
a
PaymentMethodData
and
a
PaymentInstrument
that
match
on
payment
method
identifier
,
this
algorithm
returns
true
if
this
instrument
can
be
used
for
payment:
PaymentInstrument
.
"supported_origins":
"*"
in
its
payment
method
manifest,
filter
based
on
capabilities
:
false
.
true
.
CanMakePaymentEvent
in
the
payment
handler
and
return
the
result.
This section is non-normative.
Example of how a payment handler should provide the list of all its active cards to the browser.
await navigator.serviceWorker.register("/pw/app.js");
const registration = await navigator.serviceWorker.ready;
registration.paymentManager.userHint = "(Visa ****1111)";
await registration.paymentManager.instruments.set(
"12345",
{
name: "Visa ****1111",
icons: [{
src: "/pay/visa.png",
sizes: "32x32",
type: "image/png",
}],
method: "basic-card",
capabilities: {
supportedNetworks: ["visa"],
supportedTypes: ["credit"],
},
});
In
this
case,
new
PaymentRequest([{supportedMethods:
"basic-card"}],
shoppingCart).canMakePayment()
should
return
true
because
there's
an
active
card
in
the
payment
handler.
Note
that
new
PaymentRequest([{supportedMethods:
"basic-card",
data:
{supportedTypes:
["debit"]}}],
shoppingCart).canMakePayment()
would
return
false
because
of
mismatch
in
supportedTypes
in
this
example.
Once
the
user
has
selected
an
Instrument,
the
user
agent
fires
a
PaymentRequestEvent
and
uses
the
subsequent
PaymentHandlerResponse
to
create
a
PaymentReponse
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.
ServiceWorkerGlobalScope
This
specification
extends
the
ServiceWorkerGlobalScope
interface.
partial interface ServiceWorkerGlobalScope
{
attribute EventHandler onpaymentrequest
;
};
onpaymentrequest
attribute
The
onpaymentrequest
attribute
is
an
event
handler
whose
corresponding
event
handler
event
type
is
PaymentRequestEvent
.
PaymentRequestEvent
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.
[Constructor(DOMString type, PaymentRequestEventInit
eventInitDict),
Exposed=ServiceWorker]
interface PaymentRequestEvent
: ExtendableEvent {
readonly attribute USVString topLevelOrigin
;
readonly attribute USVString paymentRequestOrigin
;
readonly attribute DOMString paymentRequestId
;
readonly attribute FrozenArray<PaymentMethodData> methodData
;
readonly attribute object total
;
readonly attribute FrozenArray<PaymentDetailsModifier> modifiers
;
readonly attribute DOMString instrumentKey
;
Promise<WindowClient?> openWindow(USVString url);
void respondWith(Promise<PaymentHandlerResponse
> handlerResponsePromise);
};
topLevelOrigin
attribute
Returns a string that indicates the origin of the top level payee web page. This attribute is initialized by Handling a PaymentRequestEvent .
paymentRequestOrigin
attribute
Returns
a
string
that
indicates
the
origin
where
a
PaymentRequest
was
initialized.
When
a
PaymentRequest
is
initialized
in
the
topLevelOrigin
,
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
topLevelOrigin
,
the
value
of
this
attribute
is
the
origin
of
the
iframe.
This
attribute
is
initialized
by
Handling
a
PaymentRequestEvent
.
paymentRequestId
attribute
When
getting,
the
paymentRequestId
attribute
returns
the
[[details]].
id
from
the
PaymentRequest
that
corresponds
to
this
PaymentRequestEvent
.
methodData
attribute
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.
total
attribute
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
structured
clone
of
the
total
field
of
the
PaymentDetailsInit
provided
when
the
corresponding
PaymentRequest
object
was
instantiated.
modifiers
attribute
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.
instrumentKey
attribute
This
attribute
indicates
the
PaymentInstrument
selected
by
the
user.
It
corresponds
to
the
instrumentKey
provided
to
the
PaymentManager.instruments
interface
during
registration.
An
empty
string
means
that
the
user
did
not
choose
a
specific
PaymentInstrument
.
openWindow()
method
This method is used by the payment handler to show a window to the user. When called, it runs the open window algorithm .
respondWith()
method
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.
PaymentRequestEventInit
dictionary
dictionary PaymentRequestEventInit
: ExtendableEventInit {
USVString topLevelOrigin
;
USVString paymentRequestOrigin
;
DOMString paymentRequestId
;
sequence<PaymentMethodData> methodData
;
PaymentCurrencyAmount total
;
sequence<PaymentDetailsModifier> modifiers
;
DOMString instrumentKey
;
};
The
topLevelOrigin
,
paymentRequestOrigin
,
paymentRequestId
,
methodData
,
total
,
modifiers
,
and
instrumentKey
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:
PaymentInstrument
instrument
in
the
payment
handler
's
PaymentManager
.
instruments
,
add
the
value
of
instrument
.
method
to
registeredMethods
.
methodData
to
dataList
.
To
initialize
the
value
of
the
modifiers
,
the
user
agent
MUST
perform
the
following
steps
or
their
equivalent:
PaymentInstrument
instrument
in
the
payment
handler
's
PaymentManager
.
instruments
,
add
the
value
of
instrument
.
method
to
registeredMethods
.
modifiers
in
the
corresponding
payment
request,
perform
the
following
steps:
total
to
a
structured
clone
of
inModifier
.
total
.
modifiers
to
modifierList
.
Instances
of
CanMakePaymentEvent
are
created
with
the
internal
slots
in
the
following
table:
Internal Slot | Default Value | Description ( non-normative ) |
---|---|---|
[[resultPromise]] | null | This value is set to the pending promise to get back the result when event is triggered from the associated PaymentRequest. |
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. |
[[fetchedImage]] | undefined | This value is a result of fetching image object or a fallback image provided by the user agent. |
[[respondWithCalled]] | false | YAHO |
Upon receiving a PaymentRequest by way of PaymentRequest.show() and subsequent user selection of a payment instrument, the user agent MUST run the following steps:
ServiceWorkerRegistration
corresponding
to
the
PaymentInstrument
selected
by
the
user.
InvalidStateError
"
DOMException
and
terminate
these
steps.
ServiceWorkerRegistration
of
registration
and
callbackSteps
set
to
the
following
steps:
PaymentRequestEvent
interface,
with
the
event
type
paymentrequest
,
which
does
not
bubble,
cannot
be
canceled,
and
has
no
default
action.
topLevelOrigin
attribute
of
e
to
the
serialization
of
the
origin
of
the
top
level
payee
web
page.
paymentRequestOrigin
attribute
of
e
to
the
serialization
of
the
origin
of
the
context
where
PaymentRequest
was
initialized.
paymentRequestId
attribute
of
e
to
the
[[details]].
id
from
the
PaymentRequest
.
methodData
and
modifiers
attributes
of
e
by
executing
the
MethodData
Population
Algorithm
and
Modifiers
Population
Algorithm
respectively.
total
attribute
of
e
to
a
structured
clone
of
the
total
field
on
the
PaymentDetailsInit
from
the
corresponding
PaymentRequest
.
instrumentKey
attribute
of
e
to
the
instrumentKey
of
the
selected
PaymentInstrument
,
or
the
empty
string
if
none
was
selected.
PaymentHandlerResponse
,
reject
the
Promise
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:
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?
PaymentRequestEvent
.
PaymentRequestEvent
.
about:blank
,
return
a
Promise
rejected
with
a
TypeError
.
InvalidAccessError
.
InvalidStateError
"
DOMException
and
abort
these
steps.
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.
self.addEventListener("paymentrequest", function(e) {
e.respondWith(new Promise(function(resolve, reject) {
self.addEventListener("message", listener = function(e) {
self.removeEventListener("message", listener);
if (e.data.hasOwnProperty("name")) {
reject(e.data);
} else {
resolve(e.data);
}
});
e.openWindow("https://www.example.com/bobpay/pay")
.then(function(windowClient) {
windowClient.postMessage(e.data);
})
.catch(function(err) {
reject(err);
});
}));
});
The Web Payments Working Group plans to revisit these two examples.
Using the simple scheme described above, a trivial HTML page that is loaded into the payment handler window to implement the basic card scheme 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>
window.addEventListener("message", function(e) {
var form = document.getElementById("form");
/* Note: message sent from payment app is available in e.data */
form.onsubmit = function() {
/* See https://w3c.github.io/webpayments-methods-card/#basiccardresponse */
var basicCardResponse = {};
[ "cardholderName", "cardNumber","expiryMonth","expiryYear","cardSecurityCode"]
.forEach(function(field) {
basicCardResponse[field] = form.elements[field].value;
});
/* See https://w3c.github.io/payment-handler/#paymenthandlerresponse-dictionary */
var paymentAppResponse = {
methodName: "basic-card",
details: details
};
e.source.postMessage(paymentAppResponse);
window.close();
}
});
</script>
PaymentHandlerResponse
dictionary
dictionary PaymentHandlerResponse
{
DOMString methodName
;
object details
;
};
methodName
attribute
The payment method identifier for the payment method that the user selected to fulfil the transaction.
details
attribute
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:
When this algorithm is invoked with event and handlerResponsePromise parameters, the user agent MUST run the following steps:
InvalidStateError
"
DOMException
and
abort
these
steps.
InvalidStateError
"
DOMException
and
abort
these
steps.
PaymentHandlerResponse
dictionary.
If
this
throws
an
exception,
run
the
payment
app
failure
algorithm
and
terminate
these
steps.
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.
details
is
not
present
or
not
JSON-serializable
,
run
the
payment
app
failure
algorithm
and
terminate
these
steps.
methodName
.
Rethrow
any
exceptions.
details
.
Rethrow
any
exceptions.
The following example shows how to respond to a payment request:
paymentRequestEvent.respondWith(new Promise(function(accept,reject) {
/* ... processing may occur here ... */
accept({
methodName: "basic-card",
details: {
cardHolderName: "John Smith",
cardNumber: "1232343451234",
expiryMonth: "12",
expiryYear : "2020",
cardSecurityCode: "123"
}
});
}));
[ 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.
CanMakePaymentEvent
.
The Web Payments Working Group is also discussing Payment App authenticity; see the (draft) Payment Method Manifest .
CanMakePaymentEvent
event
should
not
be
fired
in
private
browsing
mode.
The
user
agent
should
behave
as
if
respondWith()
was
called
with
true
.
This section is non-normative.
When ordering payment handlers and payment instruments, 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 or instrument display order for an origin, or for all origins.
User experience details are left to implementers.
This specification relies on several other underlying specifications.
TypeError
,
and
JSON.stringify
are
defined
by
[
ECMASCRIPT
].
When this specification says to throw an error, the user agent must throw an error as described in [ WEBIDL ]. When this occurs in a sub-algorithm, this results in termination of execution of the sub-algorithm and all ancestor algorithms until one is reached that explicitly describes procedures for catching exceptions.
The algorithm for converting an ECMAScript value to a dictionary is defined by [ WEBIDL ].
DOMException and the following DOMException types from [ WEBIDL ] are used:
InvalidAccessError
"
InvalidStateError
"
NotAllowedError
"
NotFoundError
"
OperationError
"
SecurityError
"
ServiceWorkerRegistration
,
ServiceWorkerGlobalScope
,
handle
functional
event
,
extend
lifetime
promises
,
pending
promises
count
,
containing
service
worker
registration
,
uninstalling
flag
,
Try
Clear
Registration
,
Try
Activate
,
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 , NOT REQUIRED , SHOULD , and SHOULD NOT are to be interpreted as described in [ RFC2119 ].
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.
partial interfaceServiceWorkerRegistration
{ readonly attribute PaymentManagerpaymentManager
; }; [SecureContext, Exposed=(Window,Worker)] interface PaymentManager { [SameObject] readonly attributePaymentInstruments
instruments
; [Exposed=Window] static Promise<PermissionState> requestPermission(); attribute DOMStringuserHint
; }; [SecureContext, Exposed=(Window,Worker)] interfacePaymentInstruments
{ Promise<boolean> delete(DOMString instrumentKey); Promise<any> get(DOMString instrumentKey); Promise<sequence<DOMString>> keys(); Promise<boolean> has(DOMString instrumentKey); Promise<void> set(DOMString instrumentKey,PaymentInstrument
details); Promise<void> clear(); }; dictionaryPaymentInstrument
{ required DOMStringname
; sequence<ImageObject
>icons
; DOMStringmethod
; objectcapabilities
; }; dictionaryImageObject
{ required USVStringsrc
; DOMStringsizes
; DOMStringtype
; }; partial interfaceServiceWorkerGlobalScope
{ attribute EventHandleroncanmakepayment
; }; [Constructor(DOMString type,CanMakePaymentEventInit
eventInitDict), Exposed=ServiceWorker] interfaceCanMakePaymentEvent
: ExtendableEvent { readonly attribute USVStringtopLevelOrigin
; readonly attribute USVStringpaymentRequestOrigin
; readonly attribute FrozenArray<PaymentMethodData>methodData
; readonly attribute FrozenArray<PaymentDetailsModifier>modifiers
; void respondWith(Promise<boolean> canMakePaymentResponse); }; dictionaryCanMakePaymentEventInit
: ExtendableEventInit { USVStringtopLevelOrigin
; USVStringpaymentRequestOrigin
; sequence<PaymentMethodData>methodData
; sequence<PaymentDetailsModifier>modifiers
; }; partial interfaceServiceWorkerGlobalScope
{ attribute EventHandleronpaymentrequest
; }; [Constructor(DOMString type,PaymentRequestEventInit
eventInitDict), Exposed=ServiceWorker] interfacePaymentRequestEvent
: ExtendableEvent { readonly attribute USVStringtopLevelOrigin
; readonly attribute USVStringpaymentRequestOrigin
; readonly attribute DOMStringpaymentRequestId
; readonly attribute FrozenArray<PaymentMethodData>methodData
; readonly attribute objecttotal
; readonly attribute FrozenArray<PaymentDetailsModifier>modifiers
; readonly attribute DOMStringinstrumentKey
; Promise<WindowClient?> openWindow(USVString url); void respondWith(Promise<PaymentHandlerResponse
> handlerResponsePromise); }; dictionaryPaymentRequestEventInit
: ExtendableEventInit { USVStringtopLevelOrigin
; USVStringpaymentRequestOrigin
; DOMStringpaymentRequestId
; sequence<PaymentMethodData>methodData
; PaymentCurrencyAmounttotal
; sequence<PaymentDetailsModifier>modifiers
; DOMStringinstrumentKey
; }; dictionaryPaymentHandlerResponse
{ DOMStringmethodName
; objectdetails
; };