diff --git a/README.md b/README.md index ea5a5007..facd0415 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ +# Web Payments - Payment Request API +## A Payment API for Browsers -# Payment API for Browsers +This repository contains a draft specification from the [W3C Web Payments Working Group](https://www.w3.org/Payments/WG/). -This is the repository contains drafts from the [W3C Web Payments Working Group](https://www.w3.org/Payments/WG/) for a browser API to make payments. - -An index of documents available is at https://w3c.github.io/browser-payment-api/. +The editor's draft is available at: https://w3c.github.io/browser-payment-api/ \ No newline at end of file diff --git a/specs/state-transitions.svg b/images/state-transitions.svg similarity index 100% rename from specs/state-transitions.svg rename to images/state-transitions.svg diff --git a/index.html b/index.html index 027302c5..cea239d4 100644 --- a/index.html +++ b/index.html @@ -1,50 +1,1338 @@ -
- -+ This specification describes a web API to allow merchants (i.e. web sites selling + physical or digital goods) to easily accept payments from different payment methods with + minimal integration. User agents (e.g., browsers) will facilitate the payment flow between + merchant and user. +
++ The 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 specification was derived from a report published previously by the + Web Platform Incubator Community Group. +
+Buying things on the + web, particularly on mobile, can be a frustrating experience for users. Every web site has its own flow + and its own validation rules, and most require users to manually type in the same set of information + over and over again. Likewise, it is difficult and time consuming for developers to create good + checkout flows that support various payment schemes.
+ +This specification describes an API that allows user agents (e.g., browsers) to act + as an intermediary between the three key parties in every transaction: the merchant (e.g., an + online web store), the buyer (e.g., the user buying from the online web store), and the + Payment Method (e.g., credit card). Information necessary to process and confirm a + transaction is passed between the Payment Method and the merchant via the user agent + with the buyer confirming and authorizing as necessary across the flow.
+ +In addition to better, more consistent user experiences, this 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 API described in this document forms part of the Payment Request system described in + the Payment Request Architecture [[PAYMENT-ARCH]] document.
+ ++ This specification defines one class of products: +
++ A user agent MUST behave as described in this specification + in order to be considered conformant. In this specification, user agent means a Web + browser or other interactive user agent as defined in [[!HTML5]]. +
++ 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. +
++ A conforming Payment Request API user agent MUST also be a + conforming implementation of the IDL fragments + of this specification, as described in the + “Web IDL” specification. [[!WEBIDL]] +
+ + ++ This specification relies on several other underlying specifications. +
+TypeError
, JSON.stringify, and JSON.parse are
+ defined by [[!ECMA-262-2015]].
+ This document uses the format object@[[\slotname]] to mean the internal slot [[\slotname]] + of the object object.
+The term JSON-serializable object used in this specification means an object that can + be serialized to a string using JSON.stringify and later deserialized back to an object + using JSON.parse with no loss of data.
+Event
type and the terms fire an event, dispatch flag,
+ stop propagation flag, and stop immediate propagation flag are defined by [[!DOM4]].
+ DOMException and the following DOMException types from [[!DOM4]] are used:
+Type | Message (optional) |
---|---|
AbortError | The payment request was aborted |
InvalidStateError | The object is in an invalid state |
NotSupportedError | The payment method was not supported |
SecurityError | The operation is only supported in a secure context |
The term extended attribute is defined by [[!WEBIDL]].
+ [Constructor(sequence<PaymentMethodData> methodData, PaymentDetails details, optional PaymentOptions options), + SecureContext] + interface PaymentRequest : EventTarget { + Promise<PaymentResponse> show(); + Promise<void> abort(); + + readonly attribute PaymentAddress? shippingAddress; + readonly attribute DOMString? shippingOption; + + /* Supports "shippingaddresschange" event */ + attribute EventHandler onshippingaddresschange; + + /* Supports "shippingoptionchange" event */ + attribute EventHandler onshippingoptionchange; + }; ++ +
+ A web page creates a PaymentRequest
to make a payment request. This is
+ typically associated with the user initiating a payment process
+ (e.g., selecting a "Power Up" in an interactive game, pulling up to an automated kiosk in a parking structure,
+ or activating a "Buy", "Purchase", or "Checkout" button).
+ The PaymentRequest
allows the web page to exchange information with the
+ user agent while the user is providing input before approving or denying a payment request.
+
+ The [SecureContext]
extended attribute means that the PaymentRequest
+ is only exposed within a secure context and won't be accessible elsewhere.
+
The following example shows how to construct a PaymentRequest
and begin the
+ user interaction:
+ var payment = new PaymentRequest(methodData, details, options); + payment.addEventListener("shippingaddresschange", function (changeEvent) { + // Process shipping address change + }); + + payment.show().then(function(paymentResponse) { + // Process paymentResponse + // paymentResponse.methodName contains the selected payment method + // paymentResponse.details contains a payment method specific response + paymentResponse.complete("success"); + }).catch(function(err) { + console.error("Uh oh, something bad happened", err.message); + }); ++ +
+ The PaymentRequest
is constructed using the supplied methodData
+ list including any payment method specific data
, the payment details
,
+ and the payment options
.
+
The methodData
sequence contains PaymentMethodData
dictionaries
+ containing the payment method identifiers for the payment methods that the web site accepts
+ and any associated payment method specific data.
+ [ + { + supportedMethods: ["visa","bitcoin"] + }, + { + supportedMethods: ["bobpay.com"], + data: { + merchantIdentifier: "XXXX", + bobPaySpecificField: true + } + } + ] ++ +
The details
object contains information about the transaction that the
+ user is being asked to complete such as the line items in an order.
+ { + displayItems: [ + { + label: "Sub-total", + amount: { currency: "USD", value : "55.00" }, // US$55.00 + }, + { + label: "Sales Tax", + amount: { currency: "USD", value : "5.00" }, // US$5.00 + } + ], + total: { + label: "Total due", + amount: { currency: "USD", value : "60.00" }, // US$60.00 + } + } ++ + +
The options
object contains information about what options the web page
+ wishes to use from the payment request system.
+ { + requestShipping: true + } ++
methodData
, details
, and data
+ should be combined into a single object.
+
+ The PaymentRequest
constructor MUST act as follows:
+
methodData
sequence is zero, then throw
+ a TypeError
.
+ PaymentMethodData
dictionary, if the length of the
+ supportedMethods
sequence is zero, then throw a TypeError
.
+ SecurityError
.
+ There is an open issue about requiring
+ a top-level browsing context for using PaymentRequest
. Requiring one
+ is a mitigation for a user being tricked into thinking a trusted site is asking for
+ payment when in fact an untrusted iframe is asking for payment. The problem is some iframes may
+ have a legitimate reason to request payment.
details
does not contain a value for total
, then throw a
+ TypeError
.
+ details.total.amount.value
is U+002D HYPHEN-MINUS, then throw a
+ TypeError
. total
MUST be a non-negative amount.
+ PaymentMethodData
in methodData
, if the data
field
+ is supplied but is not a JSON-serializable object, then throw a TypeError
.
+ PaymentRequest
.methodData
into request@[[\methodData]].
+
+ The methodData
supplied to the PaymentRequest
constructor
+ SHOULD be in the order of preference of the caller. Implementations MAY show payment methods
+ in this order if possible but SHOULD prioritize the preference of the user when presenting
+ payment methods.
+
details
into request@[[\details]].options
into request@[[\options]].shippingAddress
attribute on request to null.
+ shippingOption
attribute on request to null.
+ details
contains a shippingOptions
sequence with a
+ length of 1, then set shippingOption
to the id
of
+ the only ShippingOption
in the sequence.
+ details
contains a shippingOptions
sequence with a
+ length greater than 1, and if any ShippingOption
in the sequence
+ has the selected
field set to true
, then set
+ shippingOption
to the id
of the last ShippingOption
+ in the sequence with selected
set to true
.
+
+ The show
method is called when the page wants to begin user interaction for the
+ payment request. The show
method will return 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.
+
+ The show
method MUST act as follows:
+
PaymentRequest
object on which the method is called.
+ InvalidStateError
.supportedMethods
sequences from each
+ PaymentMethodData
in the request@[[\methodData]] sequence.
+ NotSupportedError
.
+
+ The abort
method may be called if the web page wishes to tell the
+ user agent to abort the payment request and to tear down any user interface that
+ might be shown. abort
can only be called after the show
method
+ has been called and before the request@[[\acceptPromise]] has been resolved.
+ For example, a web page 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.
+
+ The architecture document suggests that payment apps may take + numerous forms, including as web-based apps. This specification + should describe how the user-agent will pass the payment request + data and the complete signal to a web-based payment app and also how + it will receive the payment response from the payment app. +
+ ++ This specification should describe how the user agent will pass the + payment request data and the complete signal to a native payment app + and also how it will receive the payment response from the payment app. +
+ +The abort
method MUST act as follows:
PaymentRequest
object on which the method is called.
+ InvalidStateError
.InvalidStateError
and abort this algorithm.AbortError
.undefined
.The internal slot [[\state]] follows the following state transitions:
+
+ shippingAddress
is populated when the user provides a shipping
+ address. It is null by default.
+ When a user provides a shipping address, the shipping address changed algorithm runs.
+
+ onshippingaddresschange
is an EventHandler
for an
+ Event
named shippingaddresschange
.
+
+ shippingOption
is populated when the user chooses a shipping
+ option. It is null by default.
+ When a user chooses a shipping option, the shipping option changed algorithm runs.
+
+ onshippingoptionchange
is an EventHandler
for an
+ Event
named shippingoptionchange
.
+
Instances of PaymentRequest
are created with the internal slots in
+ the following table:
Internal Slot | Description (non-normative) |
---|---|
[[\methodData]] | +The methodData supplied to the constructor. |
+
[[\details]] | +
+ The current PaymentDetails for the payment request initially
+ supplied to the constructor and then updated with calls to updateWith .
+ |
+
[[\options]] | +The PaymentOptions supplied to the constructor. |
+
[[\state]] | +The current state of the payment request. | +
[[\updating]] | +
+ true is 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.
+ |
+
+ dictionary PaymentMethodData { + required sequence<DOMString> supportedMethods; + object data; + }; ++
+ A PaymentMethodData
dictionary is used to indicate a set of supported payment
+ methods and any associated payment method specific data for those methods.
+
The following fields are part of the PaymentMethodData
dictionary:
supportedMethods
supportedMethods
is a required sequence of strings containing payment method identifiers for
+ payment methods that the merchant web site accepts.data
data
is a JSON-serializable object that provides optional information that
+ might be needed by the supported payment methods.+dictionary CurrencyAmount { + required DOMString currency; + required DOMString value; +}; ++
+ A CurrencyAmount
dictionary is used to supply monetary amounts.
+ The following fields MUST be supplied for a CurrencyAmount
to be valid:
+
currency
currency
is a string containing a currency identifier. The most common
+ identifiers are three-letter alphabetic codes as defined by [[!ISO4217]] (for example,
+ "USD"
for US Dollars) however any string is considered valid and
+ user agents MUST not attempt to validate this string.
+ value
^-?[0-9]+(\.[0-9]+)?$
.
+ The following example shows how to represent US$55.00.
++{ + "currency": "USD", + "value" : "55.00" +} ++
+dictionary PaymentDetails { + PaymentItem total; + sequence<PaymentItem> displayItems; + sequence<ShippingOption> shippingOptions; +}; ++ +
+ The PaymentDetails
dictionary is passed to the PaymentRequest
+ constructor and provides information about the requested transaction. The PaymentDetails
+ dictionary is also used to update the payment request using updateWith
.
+
+ The following fields are part of the PaymentDetails
dictionary:
+
total
PaymentItem
contains the total amount of the payment request.
+
+ total
MUST be a non-negative value. This means that the total.amount.value
+ field MUST NOT begin with a U+002D HYPHEN-MINUS character.
+
displayItems
PaymentItem
dictionaries contains line items
+ for the payment request that the user agent MAY display. For example, it might include
+ details of products or breakdown of tax and shipping. It is optional to provide this
+ information.
+ The user agent MAY validate that the total
amount is the
+ sum of these items, but it is the responsibility of the calling code to ensure that.
shippingOptions
If the sequence is empty, then this indicates that the merchant
+ cannot ship to the current shippingAddress
.
If the sequence only contains one item, then this is the shipping option that
+ will be used and shippingOption
will be set to the id
+ of this option without running the shipping option changed algorithm.
If an item in the sequence has the selected
field set to true
,
+ then this is the shipping option that will be used by default and shippingOption
+ will be set to the id
of this option without running the shipping option changed
+ algorithm. Authors SHOULD NOT set selected
to true
on more than
+ one item. If more than one item in the sequence has selected
set to true
,
+ then user agents MUST select the last one in the sequence.
The shippingOptions
field is only used if the PaymentRequest
was
+ constructed with PaymentOptions
requestShipping
+ set to true
.
+ If the sequence contains only one item or if the sequence has an item with the selected
+ field set to true
, then authors SHOULD ensure that the total
field includes
+ the cost of the shipping option. This is because no shippingoptionchange
event
+ will be fired for this option unless the user selects an alternative option first.
+
+dictionary PaymentOptions { + boolean requestPayerEmail = false; + boolean requestPayerPhone = false; + boolean requestShipping = false; +}; ++ +
+ The PaymentOptions
dictionary is passed to the PaymentRequest
+ constructor and provides information about the options desired for the payment request.
+
+ The following fields MAY be passed to the PaymentRequest
constructor:
+
requestPayerEmail
true
to allow a merchant to email a receipt.
+ requestPayerPhone
true
to allow a merchant to phone a customer with a billing enquiry.
+ requestShipping
true
when physical goods need to be shipped by the merchant to the user.
+ This would be set to false
for an online-only electronic purchase transaction.
+ + dictionary PaymentItem { + required DOMString label; + required CurrencyAmount amount; + }; ++
+ A sequence of one or more PaymentItem
dictionaries is included in the PaymentDetails
+ dictionary to indicate the what the payment request is for and the value asked for.
+
+ The following fields MUST be included in a PaymentItem
for it to be valid:
+
label
amount
CurrencyAmount
containing the monetary amount for the item.
+ PaymentItem
+ with amounts in more than once currency.
+ + interface PaymentAddress { + readonly attribute DOMString country; + readonly attribute FrozenArray<DOMString> addressLine; + readonly attribute DOMString region; + readonly attribute DOMString city; + readonly attribute DOMString dependentLocality; + readonly attribute DOMString postalCode; + readonly attribute DOMString sortingCode; + readonly attribute DOMString languageCode; + readonly attribute DOMString organization; + readonly attribute DOMString recipient; + readonly attribute DOMString careOf; + readonly attribute DOMString phone; + }; ++
country
addressLine
region
city
dependentLocality
postalCode
sortingCode
languageCode
organization
recipient
careOf
phone
+ If the requestShipping flag was set to true
in the PaymentOptions
+ passed to the PaymentRequest constructor, then the user agent will populate the
+ shippingAddress
field of the PaymentRequest
and ultimately the
+ PaymentResponse
object with the user's selected shipping address after
+ the user has accepted the payment.
+
+ dictionary ShippingOption { + required string id; + required string label; + required CurrencyAmount amount; + boolean selected = false; + }; ++
+ The ShippingOption dictionary has fields describing a shipping option. A web page can + provide the user with one or more shipping options by calling the updateWith + method in response to a change event. +
+
+ The following fields MUST be included in a PaymentItem
for it to be valid:
+
id
ShippingOption
. It MUST be
+ unique for a given PaymentRequest
.label
amount
CurrencyAmount
containing the monetary amount for the item.
+ selected
true
to indicate that this is the default selected ShippingOption
+ in a sequence. User agents SHOULD display this option by default in the user interface.+ enum PaymentComplete { "success", "fail", "" }; + + interface PaymentResponse { + readonly attribute DOMString methodName; + readonly attribute object details; + readonly attribute PaymentAddress? shippingAddress; + readonly attribute DOMString? payerEmail; + readonly attribute DOMString? payerPhone; + + Promise<void> complete(optional PaymentComplete result = ""); + }; ++ +
+ A PaymentResponse
is returned when a user has selected a payment method and
+ approved a payment request. It contains the following fields:
+
methodName
details
shippingAddress
true
in the PaymentOptions
+ passed to the PaymentRequest constructor, then shippingAddress
will
+ be the full and final shipping address chosen by the user.
+ payerEmail
true
in the PaymentOptions
+ passed to the PaymentRequest constructor, then payerEmail
will
+ be the email address chosen by the user.
+ payerPhone
true
in the PaymentOptions
+ passed to the PaymentRequest constructor, then payerPhone
will
+ be the phone number chosen by the user.
+ The complete
method must be 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 user interaction is over (and should cause any remaining user interface to be
+ closed).
The complete
method takes a string argument from the PaymentComplete
+ enum (result
). These values are used to influence the user experience provided by the user agent
+ when the user interface is dismissed. The value of result
has the following meaning:
"success"
"fail"
""
result
.The complete
method MUST act as follows:
InvalidStateError
.
+ result
+ to influence the user experience. User agents SHOULD treat unrecognized result
+ values as the value ""
.undefined
.Instances of PaymentResponse
are created with the internal slots in
+ the following table:
Internal Slot | Description (non-normative) |
---|---|
[[\completeCalled]] | +
+ true if the complete method has been called and false
+ otherwise.
+ |
+
Event name | Interface | Dispatched when... |
---|---|---|
shippingaddresschange |
+ PaymentRequestUpdateEvent | +The user provides a new shipping address. | +
shippingoptionchange |
+ PaymentRequestUpdateEvent | +The user chooses a new shipping option. | +
+[Constructor(DOMString type, optional PaymentRequestUpdateEventInit eventInitDict)] +interface PaymentRequestUpdateEvent : Event { + void updateWith(Promise<PaymentDetails> d); +}; + +dictionary PaymentRequestUpdateEventInit : EventInit { +}; ++
The PaymentRequestUpdateEvent
enables the web page to update
+ the details of the payment request in response to a user interaction.
If the web page wishes to update the payment request then it should call updateWith
+ and provide a promise that will resolve with a PaymentDetails
+ dictionary containing changed values that the user agent SHOULD present to the user.
The PaymentRequestUpdateEvent constructor MUST set the internal slot [[\waitForUpdate]] + to false.
+The updateWith
method MUST act as follows:
PaymentRequest
object that is the target of
+ the event.
+ InvalidStateError
.InvalidStateError
.
+ InvalidStateError
.
+ InvalidStateError
.
+ d
+ to indicate that the payment request is valid again.
+ The user agent SHOULD disable any part of the user interface that could cause + another update event to be fired. Only one update may be processed at a time.
+d
settles.d
is resolved with details
and details
is a
+ PaymentDetails
dictionary, then:
+ details
contains a total
value and the first character of
+ total.amount.value
is NOT U+002D HYPHEN-MINUS, then copy
+ total
value to the total
field of target@[[\details]]
+ (total
MUST be a non-negative amount).
+ details
contains a displayItems
value, then copy
+ this value to the displayItems
field of target@[[\details]].
+ details
contains a shippingOptions
sequence, then:
+ shippingOptions
sequence from details
to the
+ shippingOptions
field of target@[[\details]].
+ details
contains a shippingOptions
sequence with a
+ length of 1, then set newOption to the id
of the only
+ ShippingOption
in the sequence.
+ details
contains a shippingOptions
sequence with a
+ length greater than 1, and if any ShippingOption
in the sequence
+ has the selected
field set to true
, then set
+ newOption to the id
of the last ShippingOption
+ in the sequence with selected
set to true
.
+ shippingOption
on target to
+ newOption.
+ + The spec needs to clearly state how it will handle internationalization + issues (such as selection order for language via explicit preferences, + Accept-Language headers, etc.) +
+ +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 shipping address changed algorithm runs when the user provides a new shipping + address. It MUST run the following steps: +
+PaymentRequest
object that the user is
+ interacting with.shippingaddresschange
.shippingAddress
attribute on request to the
+ shipping address provided by the user.
+ + The shipping option changed algorithm runs when the user chooses a new shipping + option. It MUST run the following steps: +
+PaymentRequest
object that the user is
+ interacting with.shippingoptionchange
.shippingOption
attribute on request to the
+ id
string of the ShippingOption
provided by the user.
+
+ 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.
It MUST run the following steps:
+PaymentRequestUpdateEvent
.+ The user accepts the payment request + algorithm runs when the user accepts the payment request and confirms that they want + to pay. It MUST run the following steps: +
+PaymentRequest
object that the user is
+ interacting with.
+ requestShipping
value of request@[[\options]]
+ is true
, then if the shippingAddress
attribute of request
+ is null
or if the shippingOption
attribute of request
+ is null
, then terminate this algorithm and take no further action. This should
+ never occur.
+ PaymentResponse
.
+ methodName
attribute value of response to the payment method identifier
+ for the payment method that the user selected to accept the payment.
+ details
attribute value of response to a JSON-serializable object
+ containing the payment method specific message used by the merchant to process
+ the transaction. The format of this response will be defined by a Payment Transaction
+ Message Specification.
+ requestShipping
value of request@[[\options]]
+ is true
, then copy the shippingAddress
attribute of
+ request to the shippingAddress
attribute of response.
+ requestPayerEmail
value of request@[[\options]]
+ is true
, then set the payerEmail
attribute of
+ response to the payer's email address selected by the user.
+ requestPayerPhone
value of request@[[\options]]
+ is true
, then set the payerPhone
attribute of
+ response to the payer's phone number selected by the user.
+ + This section is a placeholder to record security considerations as we gather them through working + group discussion. +
+
+ 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 a placeholder to record privacy considerations as we gather them through working + group discussion. +
++ The user agent should never share information about the user to the web page + (such as the shipping address) without user consent. +
+