From 3659e9b0058d731e6bbe303913e439cced32ad55 Mon Sep 17 00:00:00 2001 From: Eiji Kitamura Date: Wed, 11 Jan 2023 16:53:59 +0900 Subject: [PATCH 1/3] Update payment articles - Remove mentions of `PaymentInstruments` - Revert mentions of shipping address support - Update video scripts - chore --- .../index.md | 9 +- .../index.md | 18 +- .../index.md | 288 +++++++++++++++++- .../index.md | 22 +- .../index.md | 147 +-------- .../setting-up-a-payment-method/index.md | 18 +- .../web-based-payment-apps-overview/index.md | 9 +- 7 files changed, 316 insertions(+), 195 deletions(-) diff --git a/src/site/content/en/payments/android-payment-apps-developers-guide/index.md b/src/site/content/en/payments/android-payment-apps-developers-guide/index.md index f6dd5a40a68..32281951786 100644 --- a/src/site/content/en/payments/android-payment-apps-developers-guide/index.md +++ b/src/site/content/en/payments/android-payment-apps-developers-guide/index.md @@ -22,11 +22,10 @@ information easier than ever before. The API can also invoke platform-specific p apps. {% BrowserCompat 'api.PaymentRequest' %} -
- +
+ {% Video + src="video/YLflGBAPWecgtKJLqCJHSzHqe2J2/hzMuAwPAGpNmgxHpaHAq.mp4", autoplay="true", loop="true" + %}
Checkout flow with platform-specific Google Pay app that uses Web Payments.
diff --git a/src/site/content/en/payments/empowering-payment-apps-with-web-payments/index.md b/src/site/content/en/payments/empowering-payment-apps-with-web-payments/index.md index 67e414a8f9d..fe4bf9ac414 100644 --- a/src/site/content/en/payments/empowering-payment-apps-with-web-payments/index.md +++ b/src/site/content/en/payments/empowering-payment-apps-with-web-payments/index.md @@ -43,11 +43,10 @@ of billing data for every purchase. See a demo below of how Google Pay leverages Web Payments to build a seamless flow. The same can be achieved by any other payment app: -
- +
+ {% Video + src="video/YLflGBAPWecgtKJLqCJHSzHqe2J2/hzMuAwPAGpNmgxHpaHAq.mp4", autoplay="true", loop="true" + %}
Checkout flow with Google Pay and Web Payments.
@@ -220,11 +219,10 @@ In the video above, Google Pay is a platform-specific payment app. * The web-based route is ideal for web services that have a large number of customers with their card on file. -
- +
+ {% Video + src="video/YLflGBAPWecgtKJLqCJHSzHqe2J2/kM6NP47k4Xzl4tHWISCm.mp4", autoplay="true", loop="true" + %}
Checkout flow with a web-based payment app.
diff --git a/src/site/content/en/payments/handling-optional-payment-information/index.md b/src/site/content/en/payments/handling-optional-payment-information/index.md index 2d6834765fb..4acb401b3e1 100644 --- a/src/site/content/en/payments/handling-optional-payment-information/index.md +++ b/src/site/content/en/payments/handling-optional-payment-information/index.md @@ -6,7 +6,7 @@ subhead: | authors: - agektmr date: 2020-08-31 -updated: 2021-09-14 +updated: 2023-01-12 description: | Once a web-based payment app is registered, it's ready to accept payment requests from merchants. This article teaches you how to orchestrate a payment transaction from a service worker during runtime. tags: @@ -19,8 +19,8 @@ feedback: {% Aside 'warning' %} Shipping and address support in [the Payment Request API is removed from the -specification](https://github.com/w3c/payment-request/pull/955) and is no longer -functional in web-based payment apps. +specification](https://github.com/w3c/payment-request/pull/955) and is planned +to be removed in web-based payment apps. {% endAside %} @@ -31,7 +31,7 @@ explains how a payment app can pass information about the payment method, shipping address, or contact information to the merchant using a service worker.
- {% Img src="image/YLflGBAPWecgtKJLqCJHSzHqe2J2/4XRuSFGyEE2Cjwrmu0jb.png", alt="Handling optional payment information with a service worker", width="800", height="1344" %} + {% Img src="image/tcFciHGuF3MxnTr1y5ue01OGLBn2/kDteyNFNEVnJQyTPw5p8.png", alt="Handling optional payment information with a service worker", width="800", height="2335", class="w-screenshot" %}
Handling optional payment information with a service worker
@@ -200,13 +200,271 @@ object. Use the object to update the UI on the frontend. See [Reflect the updated payment details](#reflect-the-updated-payment-details). +## Inform the merchant of a shipping address change {: #shipping-address-changes } + +Payment apps can provide the customer's shipping address to the merchant as part +of the result of a payment transaction. + +This is useful for merchants because they can delegate the address collection to +payment apps. And, because the address data will be provided in [the standard +data format](https://w3c.github.io/payment-request/#dom-addressinit), the +merchant can expect to receive shipping addresses in consistent structure. + +This is beneficial for customers as well because once they register their +address information to their favorite payment app, they can reuse it in +different shops. + +
+ {% Img src="image/tcFciHGuF3MxnTr1y5ue01OGLBn2/0ytdyaEC7tkPkBTv5rIu.png", alt="Shipping address picker UI", width="800", height="1600", class="w-screenshot" %} +
+ Shipping address picker UI +
+
+ +Payment apps can provide a UI to edit a shipping address or to select +pre-registered address information for the customer on a payment transaction. +When a shipping address is determined temporarily, the payment app can let the +merchant know of the redacted address information. This provides merchants with +multiple benefits: + +* A merchant can determine whether the customer meets the regional restriction + to ship the item (for example, domestic only). +* A merchant can change the list of shipping options based on the region of the + shipping address (For example, international regular or express). +* A merchant can apply the new shipping cost based on the address and update the + total price. + +With the Payment Handler API, the payment app can send a "shipping address +change" event to the merchant from the service worker to notify the new shipping +address. The service worker should invoke +[`PaymentRequestEvent.changeShippingAddress()`](https://w3c.github.io/payment-handler/#dom-paymentrequestevent-changeshippingaddress) +with the [new address +object](https://www.w3.org/TR/payment-request/#dom-addressinit). + +
+ {% Img src="image/tcFciHGuF3MxnTr1y5ue01OGLBn2/aVv5d9OEcEjH1Z6nUQKb.png", alt="Inform the merchant of a shipping address change", width="800", height="675", class="w-screenshot" %} +
+ Inform the merchant of a shipping address change +
+
+ +{% Label %} +[payment handler] service-worker.js +{% endLabel %} + +```js +... +// Received a message from the frontend +self.addEventListener('message', async e => { + let details; + try { + switch (e.data.type) { + … + case 'SHIPPING_ADDRESS_CHANGED': + const newAddress = e.data.shippingAddress; + details = + await payment_request_event.changeShippingAddress(newAddress); + … +``` + +{% Aside 'key-term' %} +**Redacted address**. Informing the full shipping address to the merchant in +this case is not necessary and risks customers' privacy. The merchant only +receives the parts of the address that they need to determine the shipping cost. +Specifically, the browser will clear the `organization`, `phone`, `recipient`, +`addressLine` fields from the payment app provided address before raising the +`shippingaddresschange` event in the merchant's DOM. +{% endAside %} + +The merchant will receive a `shippingaddresschange` event from the Payment +Request API so they can respond with the updated [`PaymentDetailsUpdate`](https://w3c.github.io/payment-request/#paymentdetailsupdate-dictionary). + +{% Label %} +[merchant] +{% endLabel %} + +```js +request.addEventListener('shippingaddresschange', e => { + // Read the updated shipping address and update the request. + const addr = request.shippingAddress; + const details = getPaymentDetailsFromShippingAddress(addr); + // `updateWith()` sends back updated payment details + e.updateWith(details); +}); +``` + +When the merchant responds, the promise +[`PaymentRequestEvent.changeShippingAddress()`](https://w3c.github.io/payment-handler/#dom-paymentrequestevent-changeshippingaddress) +returned will resolve with a +[`PaymentRequestDetailsUpdate`](https://w3c.github.io/payment-handler/#the-paymentrequestdetailsupdate) +object. + +{% Label %} +[payment handler] service-worker.js +{% endLabel %} + +```js +… + // Notify the merchant of the shipping address change + details = await payment_request_event.changeShippingAddress(newAddress); + // Provided the new payment details, + // send a message back to the frontend to update the UI + postMessage('UPDATE_REQUEST', details); + break; +… +``` + +Use the object to update the UI on the frontend. See [Reflect the updated +payment details](#reflect-the-updated-payment-details). + +## Inform the merchant of a shipping option change + +Shipping options are delivery methods merchants use to ship purchased items to a customer. Typical shipping options include: +* Free shipping +* Express shipping +* International shipping +* Premium international shipping + +Each comes with its own cost. Usually faster methods/options are more expensive. + +Merchants using the Payment Request API can delegate this selection to a payment +app. The payment app can use the information to construct a UI and let the +customer pick a shipping option. + +
+ {% Img src="image/tcFciHGuF3MxnTr1y5ue01OGLBn2/VkHwTharTqX7oFK62RkA.png", alt="Shipping option picker UI", width="800", height="1600", class="w-screenshot" %} +
+ Shipping option picker UI +
+
+ +The list of shipping options specified in the merchant's Payment Request API is +propagated to the payment app's service worker as a property of +`PaymentRequestEvent`. + +{% Label %} +[merchant] +{% endLabel %} + +```js +const request = new PaymentRequest([{ + supportedMethods: 'https://bobpay.xyz/pay', + data: { transactionId: '****' } +}], { + displayItems: [{ + label: 'Anvil L/S Crew Neck - Grey M x1', + amount: { currency: 'USD', value: '22.15' } + }], + shippingOptions: [{ + id: 'standard', + label: 'Standard', + amount: { value: '0.00', currency: 'USD' }, + selected: true + }, { + id: 'express', + label: 'Express', + amount: { value: '5.00', currency: 'USD' } + }], + total: { + label: 'Total due', + amount: { currency: 'USD', value : '22.15' } + } +}, { requestShipping: true }); +``` + +The payment app can let the merchant know which shipping option the customer +picked. This is important for both the merchant and the customer because +changing the shipping option changes the total price as well. The merchant needs +to be informed of the latest price for the payment verification later and the +customer also needs to be aware of the change. + +With the Payment Handler API, the payment app can send a "shipping option +change" event to the merchant from the service worker. The service worker should +invoke +[`PaymentRequestEvent.changeShippingOption()`](https://w3c.github.io/payment-handler/#dom-paymentrequestevent-changeshippingoption) +with the new shipping option ID. + +
+ {% Img src="image/tcFciHGuF3MxnTr1y5ue01OGLBn2/mERzHqvPGrjKWu29m5q1.png", alt="Inform the merchant of a shipping option change", width="800", height="667", class="w-screenshot" %} +
+ Inform the merchant of a shipping option change +
+
+ +{% Label %} +[payment handler] service-worker.js +{% endLabel %} + +```js +… +// Received a message from the frontend +self.addEventListener('message', async e => { + let details; + try { + switch (e.data.type) { + … + case 'SHIPPING_OPTION_CHANGED': + const newOption = e.data.shippingOptionId; + details = + await payment_request_event.changeShippingOption(newOption); + … +``` + +The merchant will receive a `shippingoptionchange` event from the Payment +Request API. The merchant should use the information to update the total price +and then respond with the updated +[`PaymentDetailsUpdate`](https://w3c.github.io/payment-request/#paymentdetailsupdate-dictionary). + +{% Label %} +[merchant] +{% endLabel %} + +```js +request.addEventListener('shippingoptionchange', e => { + // selected shipping option + const shippingOption = request.shippingOption; + const newTotal = { + currency: 'USD', + label: 'Total due', + value: calculateNewTotal(shippingOption), + }; + // `updateWith()` sends back updated payment details + e.updateWith({ total: newTotal }); +}); +``` + +When the merchant responds, the promise that +[`PaymentRequestEvent.changeShippingOption()`](https://w3c.github.io/payment-handler/#dom-paymentrequestevent-changeshippingoption) +returned will resolve with a +[`PaymentRequestDetailsUpdate`](https://w3c.github.io/payment-handler/#the-paymentrequestdetailsupdate) +object. + +{% Label %} +[payment handler] service-worker.js +{% endLabel %} + +```js +… + // Notify the merchant of the shipping option change + details = await payment_request_event.changeShippingOption(newOption); + // Provided the new payment details, + // send a message back to the frontend to update the UI + postMessage('UPDATE_REQUEST', details); + break; +… +``` + +Use the object to update the UI on the frontend. See [Reflect the updated +payment details](#reflect-the-updated-payment-details). + ## Reflect the updated payment details {: #reflect-the-updated-payment-details } Once the merchant finishes updating the payment details, the promises returned -from `.changePaymentMethod()`, will resolve with a +from `.changePaymentMethod()`, `.changeShippingAddress()` and +`.changeShippingOption()` will resolve with a common [`PaymentRequestDetailsUpdate`](https://w3c.github.io/payment-handler/#the-paymentrequestdetailsupdate) -object. The payment handler can use the result to reflect updated total price in -the UI. +object. The payment handler can use the result to reflect updated total price +and shipping options to the UI. {% Aside %} The `PaymentRequestDetailsUpdate` object is passed from the merchant and it @@ -216,11 +474,23 @@ the UI. provide a JavaScript library to control the information, or both. {% endAside %} -Merchants may return errors if the payment method is not acceptable. Use the -following properties to reflect the error status: +Merchants may return errors for a few reasons: + +* The payment method is not acceptable. +* The shipping address is outside of their supported regions. +* The shipping address contains invalid information. +* The shipping option is not selectable for the provided shipping address or + some other reason. + +Use the following properties to reflect the error status: * **`error`**: Human readable error string. This is the best string to display to customers. +* **`shippingAddressErrors`**: + [`AddressErrors`](https://www.w3.org/TR/payment-request/#dom-addresserrors) + object that contains in-detail error string per address property. This is + useful if you want to open a form that lets the customer edit their address + and you need to point them directly to the invalid fields. * **`paymentMethodErrors`**: Payment-method-specific error object. You can ask merchants to provide a structured error, but the Web Payments spec authors recommend keeping it a simple string. diff --git a/src/site/content/en/payments/orchestrating-payment-transactions/index.md b/src/site/content/en/payments/orchestrating-payment-transactions/index.md index b2c91dc49ef..096366db667 100644 --- a/src/site/content/en/payments/orchestrating-payment-transactions/index.md +++ b/src/site/content/en/payments/orchestrating-payment-transactions/index.md @@ -131,11 +131,10 @@ they can authenticate, choose shipping address and options, and authorize the payment. We'll cover how to write the frontend code in *Handling payments on the payment frontend* (coming soon). -
- +
+ {% Video + src="video/YLflGBAPWecgtKJLqCJHSzHqe2J2/kM6NP47k4Xzl4tHWISCm.mp4", autoplay="true", loop="true", muted="true" + %}
Checkout flow with a web-based payment app.
@@ -174,8 +173,9 @@ self.addEventListener('paymentrequest', async e => { … ``` -{% Aside %} -Use a convenient `PromiseResolver` polyfill to resolve a promise at arbitrary timing. +You can use a convenient `PromiseResolver` polyfill to resolve a promise at +arbitrary timing. + ```js class PromiseResolver { constructor() { @@ -189,15 +189,15 @@ class PromiseResolver { get reject() { return this.reject_ } } ``` -{% endAside %} {% Aside %} + For security reasons, the frontend page opened in the payment handler window must have valid HTTPS certificates and no [mixed -content](/what-is-mixed-content/); -otherwise the payment request will be cancelled by Chrome. Learn more at -[Debugging a web-based payment +content](/what-is-mixed-content/); otherwise the payment request will be +cancelled by Chrome. Learn more at [Debugging a web-based payment app](/registering-a-web-based-payment-app/#debugging-a-web-based-payment-app). + {% endAside %} ## Exchange information with the frontend {: #exchange-information } diff --git a/src/site/content/en/payments/registering-a-web-based-payment-app/index.md b/src/site/content/en/payments/registering-a-web-based-payment-app/index.md index abbd6513840..0846e56f77b 100644 --- a/src/site/content/en/payments/registering-a-web-based-payment-app/index.md +++ b/src/site/content/en/payments/registering-a-web-based-payment-app/index.md @@ -6,7 +6,7 @@ subhead: | authors: - agektmr date: 2020-07-17 -updated: 2021-09-14 +updated: 2023-01-12 description: | Learn how to register a web-based payment app to a customers' browser. You'll also learn how to debug them. tags: @@ -24,7 +24,7 @@ communication with the merchant. To configure a web-based payment app, you need to register available payment methods, and a service worker. You can configure your web-based payment app -declaratively with a web app manifest or imperatively with JavaScript. +declaratively with a web app manifest. {% include 'content/payments/browser-compatibility.njk' %} @@ -67,149 +67,6 @@ JIT registration happens only when the payment method manifest points to a single payment app. {% endAside %} -## Configure a payment app with JavaScript - -Configuring a web-based payment app using JavaScript allows you to register -multiple payment methods and manually unregister service workers. - -### Manually register a service worker - -A service worker is a JavaScript file you can register using -[`navigator.serviceWorker.register()`](https://developer.mozilla.org/docs/Web/API/ServiceWorkerContainer/register). -If you have a service worker file named `service-worker.js`, you can register it -to the visitor's browser by running the following code: - - - -{% Label %}[payment handler] payment app's landing page{% endLabel %} - -```js -// Feature detection -if ('serviceWorker' in navigator) { - // Register a service worker - navigator.serviceWorker.register( - // A service worker JS file is separate - 'service-worker.js' - ); - // PaymentManager requires the service worker to be active. - // One simple method to activate a service worker is through - // a `ready` promise. - const registration = await navigator.serviceWorker.ready; -… -``` - -{% include 'content/reliable/workbox.njk' %} - -{% Aside %} -If you are new to the service worker, learn more at [Service Workers: an -Introduction](https://developer.chrome.com/docs/workbox/service-worker-overview/). -{% endAside %} - -### Set a payment instrument - -{% Aside 'key-term' %} -Payment apps can support multiple ways for making a payment. For example, a -customer can add multiple credit cards or e-wallets to a payment app. Each of -them is a payment instrument. -{% endAside %} - -Once the service worker is registered, [a service worker registration -object](https://developer.mozilla.org/docs/Web/API/ServiceWorkerRegistration) is -returned. Call -[`registration.paymentManager.instrument.set()`](https://w3c.github.io/payment-handler/#paymentinstruments-interface) -to set a payment instrument. It accepts two arguments, a string that represents -the instrument key and a [`PaymentInstrument` -object](https://w3c.github.io/payment-handler/#dom-paymentinstrument) that -contains details about the instrument. - -{% Label %}[payment handler] payment app's landing pages{% endLabel %} - -```js -… - // Feature detection - if (!registration.paymentManager) return; - - - await registration.paymentManager.instruments.set( - // Payment instrument key - 'bobpay_card_1', - // Payment instrument details - { - // This parameter will be ignored in Chrome - name: 'Payment Handler Example', - // This parameter will be used to match against - // the PaymentRequest. - method: 'https://bobpay.xyz/pay' - } - ); -``` - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ArgumentsDescription
- instrumentKey (required) - - An arbitrary string used only to identify the instrument when you want to update it. It's not visible to customers and it's recommended you use an identifier from your payment app backend. -
- PaymentInstrument - - Details of the payment instrument. -
- name (required) - - Sets a string as the instrument name. Required but ignored in Chrome. -
- icons - - Sets an array of ImageObjects that the Payment Request sheet will display. Ignored in Chrome. -
- method - - A supported payment method identifier. -
-
- -{% Aside %} -Chrome ignores the `name` and `icons` properties. It respects the [web app -manifest](/setting-up-a-payment-method/#step-3-serve-a-web-app-manifest)'s -respective properties instead, but other browsers may behave differently. -{% endAside %} - ## Debugging a web-based payment app When developing a web-based payment app frontend, you'll probably jump between diff --git a/src/site/content/en/payments/setting-up-a-payment-method/index.md b/src/site/content/en/payments/setting-up-a-payment-method/index.md index ca0a48ecce9..455f50bf682 100644 --- a/src/site/content/en/payments/setting-up-a-payment-method/index.md +++ b/src/site/content/en/payments/setting-up-a-payment-method/index.md @@ -402,11 +402,10 @@ Request API displays a browser-provided UI called the "Payment Request UI". This UI allows users to choose a payment app. After pressing the **Continue** button in the Payment Request UI, the selected payment app is launched. -
- +
+ {% Video + src="video/YLflGBAPWecgtKJLqCJHSzHqe2J2/8T37CEyLisAjwW39dRwB.mp4", autoplay="true", loop="true", muted="true" + %}
Payment Request UI intervenes before launching the payment app.
@@ -418,11 +417,10 @@ the browser can delegate fulfillment of that information to payment apps and launch a payment app directly without showing the Payment Request UI when `show()` is called. -
- +
+ {% Video + src="video/YLflGBAPWecgtKJLqCJHSzHqe2J2/VOKIj5Tqfi2bNPCjtkyi.mp4", autoplay="true", loop="true", muted="true" + %}
Skip the Payment Request UI and launch the payment app directly.
diff --git a/src/site/content/en/payments/web-based-payment-apps-overview/index.md b/src/site/content/en/payments/web-based-payment-apps-overview/index.md index 057fcf975b6..a024a606255 100644 --- a/src/site/content/en/payments/web-based-payment-apps-overview/index.md +++ b/src/site/content/en/payments/web-based-payment-apps-overview/index.md @@ -26,11 +26,10 @@ apps](/android-payment-apps-developers-guide/). ## Benefits of web-based payment apps -
- +
+ {% Video + src="video/YLflGBAPWecgtKJLqCJHSzHqe2J2/8T37CEyLisAjwW39dRwB.mp4", autoplay="true", loop="true", muted="true" + %}
Checkout flow with a web-based payment app.
From 22ef575182bfe16cad686142e348bababe7dab03 Mon Sep 17 00:00:00 2001 From: Eiji Kitamura Date: Thu, 12 Jan 2023 15:26:33 +0900 Subject: [PATCH 2/3] Updated --- .../handling-optional-payment-information/index.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/site/content/en/payments/handling-optional-payment-information/index.md b/src/site/content/en/payments/handling-optional-payment-information/index.md index 4acb401b3e1..f3f825326bc 100644 --- a/src/site/content/en/payments/handling-optional-payment-information/index.md +++ b/src/site/content/en/payments/handling-optional-payment-information/index.md @@ -202,17 +202,16 @@ payment details](#reflect-the-updated-payment-details). ## Inform the merchant of a shipping address change {: #shipping-address-changes } -Payment apps can provide the customer's shipping address to the merchant as part -of the result of a payment transaction. +Payment apps can provide a customer's shipping address to the merchant as part +of a payment transaction. This is useful for merchants because they can delegate the address collection to payment apps. And, because the address data will be provided in [the standard data format](https://w3c.github.io/payment-request/#dom-addressinit), the merchant can expect to receive shipping addresses in consistent structure. -This is beneficial for customers as well because once they register their -address information to their favorite payment app, they can reuse it in -different shops. +Additionally, customers can register their address information with their +preferred payment app and reuse it for different merchants.
{% Img src="image/tcFciHGuF3MxnTr1y5ue01OGLBn2/0ytdyaEC7tkPkBTv5rIu.png", alt="Shipping address picker UI", width="800", height="1600", class="w-screenshot" %} From 1bdaa59758c45ede86068450bbd3dcb1f669b10d Mon Sep 17 00:00:00 2001 From: Eiji Kitamura Date: Fri, 13 Jan 2023 11:10:37 +0900 Subject: [PATCH 3/3] Update --- .../handling-optional-payment-information/index.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/site/content/en/payments/handling-optional-payment-information/index.md b/src/site/content/en/payments/handling-optional-payment-information/index.md index f3f825326bc..d430f276663 100644 --- a/src/site/content/en/payments/handling-optional-payment-information/index.md +++ b/src/site/content/en/payments/handling-optional-payment-information/index.md @@ -18,9 +18,11 @@ feedback: {% Aside 'warning' %} -Shipping and address support in [the Payment Request API is removed from the -specification](https://github.com/w3c/payment-request/pull/955) and is planned -to be removed in web-based payment apps. +Shipping and address support in [the Payment Request API was once removed from +the specification](https://github.com/w3c/payment-request/pull/955) and from +Chrome, but is [being reverted](https://github.com/w3c/payment-request/pull/996) +in the spec. Thus, we've reverted the documentation about shipping and address as +well. {% endAside %}