@@ -182,6 +182,255 @@ <h2>
182
182
</ section >
183
183
</ section >
184
184
</ section >
185
+ < section class ="informative ">
186
+ < h2 >
187
+ Examples of usage
188
+ </ h2 >
189
+ < p >
190
+ In order to use the API, the developer needs to provide and keep track
191
+ of a number of key pieces of information. These bits of
192
+ information are passed to the < a > PaymentRequest</ a > constructor as
193
+ arguments, and subsequently used to update the payment request being
194
+ displayed to the user. Namely, these bits of information are:
195
+ </ p >
196
+ < ul >
197
+ < li > The < var > methodData</ var > : A sequence of < a > PaymentMethodData</ a > s
198
+ that represents the < a > payment methods</ a > that the site supports
199
+ (e.g., "we support card-based payments, but only Visa and MasterCard
200
+ credit cards.").
201
+ </ li >
202
+ < li > The < var > details</ var > : The details of the transaction, as a
203
+ < a > PaymentDetailsInit</ a > dictionary. This includes total cost, and
204
+ optionally a list of goods or services being purchased, for physical
205
+ goods, and shipping options. Additionally, it can optionally include
206
+ "modifiers" to how payments are made. For example, "if you pay with a
207
+ credit card of type X, it incurs a US$3.00 processing fee".
208
+ </ li >
209
+ < li > The < var > options</ var > : Optionally, a list of things as
210
+ < a > PaymentOptions</ a > that the site needs to deliver the good or
211
+ service (e.g., for physical goods, the merchant will typically need an
212
+ physical address to ship to. For digital goods, an email will usually
213
+ suffice).
214
+ </ li >
215
+ </ ul >
216
+ < p data-link-for ="PaymentRequest ">
217
+ Once a < a > PaymentRequest</ a > is constructed, it's presented to the end
218
+ user via the < a > show()</ a > method. The < a > show()</ a > returns a promise
219
+ that, once the user confirms request for payment, results in a
220
+ < a > PaymentResponse</ a > .
221
+ </ p >
222
+ < section >
223
+ < h3 >
224
+ The < code > methodData</ code > argument
225
+ </ h3 >
226
+ < p >
227
+ The < var > methodData</ var > sequence contains < a > PaymentMethodData</ a >
228
+ dictionaries containing the < a > payment method identifiers</ a > for the
229
+ < a > payment methods</ a > that the web site accepts and any associated
230
+ < a > payment method</ a > specific data.
231
+ </ p >
232
+ < pre class ="example js " title ="The `methodData` argument ">
233
+ const methodData = [
234
+ {
235
+ supportedMethods: "basic-card",
236
+ data: {
237
+ supportedNetworks: ["visa", "mastercard"],
238
+ supportedTypes: ["debit", "credit"],
239
+ },
240
+ },
241
+ {
242
+ supportedMethods: "https://example.com/bobpay",
243
+ data: {
244
+ merchantIdentifier: "XXXX",
245
+ bobPaySpecificField: true,
246
+ },
247
+ },
248
+ ];
249
+ </ pre >
250
+ </ section >
251
+ < section >
252
+ < h3 >
253
+ The < code > details</ code > argument
254
+ </ h3 >
255
+ < p >
256
+ The < var > details</ var > contains information about the transaction
257
+ that the user is being asked to complete, such as the line items in
258
+ an order.
259
+ </ p >
260
+ < pre class ="example js " title ="The `details` argument ">
261
+ const details = {
262
+ id: "super-store-order-123-12312",
263
+ displayItems: [
264
+ {
265
+ label: "Sub-total",
266
+ amount: { currency: "USD", value: "55.00" },
267
+ },
268
+ {
269
+ label: "Sales Tax",
270
+ amount: { currency: "USD", value: "5.00" },
271
+ },
272
+ ],
273
+ total: {
274
+ label: "Total due",
275
+ amount: { currency: "USD", value: "65.00" },
276
+ },
277
+ };
278
+ </ pre >
279
+ < section >
280
+ < h4 >
281
+ Shipping options
282
+ </ h4 >
283
+ < p >
284
+ Here we see an example of how to add two shipping options to the
285
+ < var > details</ var > .
286
+ </ p >
287
+ < pre class ="example js " title ="Adding shipping options ">
288
+ const shippingOptions = [
289
+ {
290
+ id: "standard",
291
+ label: "🚛 Ground Shipping (2 days)",
292
+ amount: { currency: "USD", value: "5.00" },
293
+ selected: true,
294
+ },
295
+ {
296
+ id: "drone",
297
+ label: "🚀 Drone Express (2 hours)",
298
+ amount: { currency: "USD", value: "25.00" }
299
+ },
300
+ ];
301
+ Object.assign(details, { shippingOptions });
302
+ </ pre >
303
+ </ section >
304
+ < section >
305
+ < h4 >
306
+ Conditional modifications to payment request
307
+ </ h4 >
308
+ < p >
309
+ Here we see how to add a processing fee for using a credit card.
310
+ Notice that it requires recalculating the total.
311
+ </ p >
312
+ < pre class ="example js " title =
313
+ "Modifying payment request based on card type ">
314
+ // Credit card incurs a $3.00 processing fee.
315
+ const creditCardFee = {
316
+ label: "Credit card processing fee",
317
+ amount: { currency: "USD", value: "3.00" },
318
+ };
319
+
320
+ // Modifiers apply when the user chooses to pay with
321
+ // a credit card.
322
+ const modifiers = [
323
+ {
324
+ additionalDisplayItems: [creditCardFee],
325
+ supportedMethods: "basic-card",
326
+ total: {
327
+ label: "Total due",
328
+ amount: { currency: "USD", value: "68.00" },
329
+ },
330
+ data: {
331
+ supportedTypes: "credit",
332
+ },
333
+ },
334
+ ];
335
+ Object.assign(details, { modifiers });
336
+ </ pre >
337
+ </ section >
338
+ </ section >
339
+ < section >
340
+ < h3 >
341
+ The < code > options</ code > argument
342
+ </ h3 >
343
+ < p >
344
+ The < var > options</ var > dictionary contains information the developer
345
+ needs from the user to perform the payment (e.g., the payer's name
346
+ and shipping address).
347
+ </ p >
348
+ < pre class ="example " title ="The `options` argument ">
349
+ const options = {
350
+ requestPayerEmail: false,
351
+ requestPayerName: true,
352
+ requestPayerPhone: false,
353
+ requestShipping: true,
354
+ }
355
+ </ pre >
356
+ </ section >
357
+ < section >
358
+ < h3 >
359
+ Constructing a < code > PaymentRequest</ code >
360
+ </ h3 >
361
+ < p >
362
+ Having gathered all the prerequisite bits of information, we can now
363
+ construct a < a > PaymentRequest</ a > and request that the browser
364
+ present it to the user:
365
+ </ p >
366
+ < pre class ="example " title ="Constructing a `PaymentRequest` ">
367
+ async function doPaymentRequest() {
368
+ try {
369
+ const request = new PaymentRequest(methodData, details, options);
370
+ // See below for a detailed example of handling these events
371
+ request.onshippingaddresschange = ev => ev.updateWith(details);
372
+ request.onshippingoptionchange = ev => ev.updateWith(details);
373
+ const response = await request.show();
374
+ await validateResponse(response);
375
+ } catch (err) {
376
+ // AbortError, SecurityError
377
+ console.error(err);
378
+ }
379
+ }
380
+ async function validateResponse(response) {
381
+ try {
382
+ if (await checkAllValuesAreGood(response)) {
383
+ await response.complete("success");
384
+ } else {
385
+ await response.complete("fail");
386
+ }
387
+ } catch (err) {
388
+ // Something went wrong...
389
+ response.complete("unknown");
390
+ }
391
+ }
392
+ doPaymentRequest();
393
+ </ pre >
394
+ </ section >
395
+ < section >
396
+ < h3 >
397
+ Handling events and updating the payment request
398
+ </ h3 >
399
+ < p >
400
+ Prior to the user accepting to make payment, the site is given an
401
+ opportunity to update the payment request in response to user input.
402
+ This can include, for example, providing additional shipping options
403
+ (or modifying their cost), removing items that cannot ship to a
404
+ particular address, etc.
405
+ </ p >
406
+ < pre class ="example ">
407
+ const request = new PaymentRequest(methodData, details, options);
408
+ request.onshippingaddresschange = async ev => {
409
+ // Can we ship here?
410
+ try {
411
+ const json = request.shippingAddress.toJSON();
412
+ const { shippingOptions, total } = await calculateShipping(json);
413
+ const newDetails = {...details, ...{ shippingOptions, total }};
414
+ ev.updateWith(newDetails);
415
+ } catch (err) {
416
+ ev.updateWith({ error: `Sorry! we can't ship to your address.` });
417
+ }
418
+ };
419
+ // update the total
420
+ request.onshippingoptionchange = ev => {
421
+ const shippingOption = shippingOptions.find(
422
+ option => option.id === request.id
423
+ );
424
+ const newTotal = {
425
+ currency: "USD",
426
+ value: calculateNewTotal(shippingOption),
427
+ label: "Total due",
428
+ };
429
+ ev.udpateWith({ ...details, total: newTotal });
430
+ };
431
+ </ pre >
432
+ </ section >
433
+ </ section >
185
434
< section >
186
435
< h2 >
187
436
Definitions
@@ -255,35 +504,6 @@ <h2>
255
504
< a data-lt ="PaymentOptions.requestShipping "> requestShipping</ a > flag is
256
505
set.
257
506
</ p >
258
- < p >
259
- The following example shows how to construct a < a > PaymentRequest</ a >
260
- and begin the user interaction:
261
- </ p >
262
- < pre class ="example " title ="Constructing a PaymentRequest object ">
263
- function validateResponse(response) {
264
- // check that the response is ok... throw if bad, for example.
265
- }
266
-
267
- async function doPaymentRequest() {
268
- const payment = new PaymentRequest(methodData, details, options);
269
- payment.addEventListener("shippingaddresschange", event => {
270
- // Process shipping address change
271
- });
272
- let paymentResponse;
273
- try {
274
- paymentResponse = await payment.show();
275
- // paymentResponse.methodName contains the selected payment method.
276
- // paymentResponse.details contains a payment method specific
277
- // response.
278
- validateResponse(paymentResponse);
279
- paymentResponse.complete("success");
280
- } catch (err) {
281
- console.error("Uh oh, bad payment response!", err.message);
282
- paymentResponse.complete("fail");
283
- }
284
- }
285
- doPaymentRequest();
286
- </ pre >
287
507
< section >
288
508
< h2 >
289
509
Constructor
@@ -294,64 +514,6 @@ <h2>
294
514
specific < a data-lt ="PaymentMethodData.data "> data</ a > , the payment
295
515
< var > details</ var > , and the payment < var > options</ var > .
296
516
</ p >
297
- < div class ="note ">
298
- < p >
299
- The < var > methodData</ var > sequence contains
300
- < a > PaymentMethodData</ a > dictionaries containing the < a > payment
301
- method identifiers</ a > for the < a > payment methods</ a > that the web
302
- site accepts and any associated < a > payment method</ a > specific
303
- data.
304
- </ p >
305
- < pre class ="example " title ="The 'methodData' argument ">
306
- const methodData = [{
307
- supportedMethods: "basic-card",
308
- data: {
309
- supportedNetworks: ['visa', 'mastercard'],
310
- supportedTypes: ['debit']
311
- }
312
- }, {
313
- supportedMethods: "https://example.com/bobpay",
314
- data: {
315
- merchantIdentifier: "XXXX",
316
- bobPaySpecificField: true
317
- }
318
- }];
319
- const request = new PaymentRequest(methodData, details, options);
320
- </ pre >
321
- < p >
322
- The < var > details</ var > object contains information about the
323
- transaction that the user is being asked to complete such as the
324
- line items in an order.
325
- </ p >
326
- < pre class ="example " title ="The 'details' argument ">
327
- const details = {
328
- id: "super-store-order-123-12312",
329
- displayItems: [{
330
- label: "Sub-total",
331
- amount: { currency: "USD", value: "55.00" }, // US$55.00
332
- }, {
333
- label: "Sales Tax",
334
- amount: { currency: "USD", value: "5.00" }, // US$5.00
335
- }],
336
- total: {
337
- label: "Total due",
338
- amount: { currency: "USD", value: "60.00" }, // US$60.00
339
- }
340
- }
341
- const request = new PaymentRequest(methodData, details, options);
342
- </ pre >
343
- < p >
344
- The < var > options</ var > object contains information the developer
345
- needs from the user to perform the payment (e.g., the payer's name
346
- and shipping address).
347
- </ p >
348
- < pre class ="example " title ="The 'options' argument ">
349
- const options = {
350
- requestShipping: true
351
- }
352
- const request = new PaymentRequest(methodData, details, options);
353
- </ pre >
354
- </ div >
355
517
< p >
356
518
The < a > PaymentRequest(methodData, details, options)</ a > constructor
357
519
MUST act as follows:
0 commit comments