Orchestrer des transactions de paiement avec un service worker

Découvrez comment adapter votre application de paiement Web aux paiements Web et offrir une meilleure expérience utilisateur à vos clients.

Une fois l'application de paiement enregistrée, vous pouvez accepter les demandes de paiement des marchands. Cet article explique comment orchestrer une transaction de paiement à partir d'un service worker pendant l'exécution (c'est-à-dire lorsqu'une fenêtre s'affiche et que l'utilisateur interagit avec elle).

Orchestration des transactions de paiement avec un service worker
Orchestrer les transactions de paiement avec un service worker

Les "modifications de paramètres de paiement au moment de l'exécution" désignent un ensemble d'événements qui permettent au marchand et au gestionnaire de paiement d'échanger des messages pendant que l'utilisateur interagit avec le gestionnaire de paiement. Pour en savoir plus, consultez Gérer les informations de paiement facultatives avec un service worker.

Recevoir un événement de demande de paiement du marchand

Lorsqu'un client choisit de payer avec votre application de paiement basée sur le Web et que le marchand appelle PaymentRequest.show(), votre service worker reçoit un événement paymentrequest. Ajoutez un écouteur d'événements au service worker pour capturer l'événement et préparer l'action suivante.

[payment handler] service-worker.js:

…
let payment_request_event;
let resolver;
let client;

// `self` is the global object in service worker
self.addEventListener('paymentrequest', async e => {
  if (payment_request_event) {
    // If there's an ongoing payment transaction, reject it.
    resolver.reject();
  }
  // Preserve the event for future use
  payment_request_event = e;
…

L'PaymentRequestEvent conservé contient des informations importantes sur cette transaction:

Nom de propriété Description
topOrigin Chaîne qui indique l'origine de la page Web de niveau supérieur (généralement le marchand bénéficiaire). Utilisez-le pour identifier l'origine du marchand.
paymentRequestOrigin Chaîne indiquant l'origine de l'appelant. Il peut être identique à topOrigin lorsque le marchand appelle directement l'API Payment Request, mais il peut être différent si l'API est appelée à partir d'un iFrame par un tiers tel qu'une passerelle de paiement.
paymentRequestId Propriété id de l'PaymentDetailsInit fournie à l'API Payment Request. Si le marchand ne le fournit pas, le navigateur fournira un ID généré automatiquement.
methodData Données spécifiques au mode de paiement fournies par le marchand dans le cadre de PaymentMethodData. Utilisez-le pour déterminer les détails de la transaction de paiement.
total Montant total fourni par le marchand dans le cadre de PaymentDetailsInit. Utilisez-le pour créer une UI permettant d'indiquer au client le montant total à payer.
instrumentKey Clé de l'instrument sélectionnée par l'utilisateur. Il s'agit du instrumentKey que vous avez fourni à l'avance. Une chaîne vide indique que l'utilisateur n'a spécifié aucun instrument.

Ouvrir la fenêtre du gestionnaire de paiement pour afficher le frontend de l'application de paiement Web

Lorsqu'un événement paymentrequest est reçu, l'application de paiement peut ouvrir une fenêtre de gestionnaire de paiement en appelant PaymentRequestEvent.openWindow(). La fenêtre du gestionnaire de paiement présente aux clients l'interface de votre application de paiement, où ils peuvent s'authentifier, choisir l'adresse et les options de livraison, et autoriser le paiement. Nous verrons comment écrire le code du frontend dans Gérer les paiements sur le frontend de paiement (bientôt disponible).

Parcours de paiement avec une application de paiement Web.

Transmettez une promesse conservée à PaymentRequestEvent.respondWith() afin de pouvoir la résoudre avec un résultat de paiement à l'avenir.

[payment handler] service-worker.js:

…
self.addEventListener('paymentrequest', async e => {
…
  // Retain a promise for future resolution
  // Polyfill for PromiseResolver is provided below.
  resolver = new PromiseResolver();

  // Pass a promise that resolves when payment is done.
  e.respondWith(resolver.promise);
  // Open the checkout page.
  try {
    // Open the window and preserve the client
    client = await e.openWindow(checkoutURL);
    if (!client) {
      // Reject if the window fails to open
      throw 'Failed to open window';
    }
  } catch (err) {
    // Reject the promise on failure
    resolver.reject(err);
  };
});
…

Vous pouvez utiliser un polyfill PromiseResolver pratique pour résoudre une promesse à un moment arbitraire.

class PromiseResolver {
  constructor() {
    this.promise_ = new Promise((resolve, reject) => {
      this.resolve_ = resolve;
      this.reject_ = reject;
    })
  }
  get promise() { return this.promise_ }
  get resolve() { return this.resolve_ }
  get reject() { return this.reject_ }
}

Échanger des informations avec l'interface

Le service worker de l'application de paiement peut échanger des messages avec le frontend de l'application de paiement via ServiceWorkerController.postMessage(). Pour recevoir des messages depuis le frontend, écoutez les événements message.

[payment handler] service-worker.js:

// Define a convenient `postMessage()` method
const postMessage = (type, contents = {}) => {
  if (client) client.postMessage({ type, ...contents });
}

Recevoir le signal de disponibilité du frontend

Une fois la fenêtre du gestionnaire de paiement ouverte, le service worker doit attendre un signal d'état prêt de l'interface de l'application de paiement. Le service worker peut transmettre des informations importantes au frontend lorsqu'il est prêt.

[payment handler] frontend:

navigator.serviceWorker.controller.postMessage({
  type: 'WINDOW_IS_READY'
});

[payment handler] service-worker.js:

…
// Received a message from the frontend
self.addEventListener('message', async e => {
  let details;
  try {
    switch (e.data.type) {
      // `WINDOW_IS_READY` is a frontend's ready state signal
      case 'WINDOW_IS_READY':
        const { total } = payment_request_event;
…

Transmettre les détails de la transaction à l'interface

Envoyez-nous maintenant les détails du mode de paiement. Dans ce cas, vous n'envoyez que le montant total de la demande de paiement, mais vous pouvez transmettre plus de détails si vous le souhaitez.

[payment handler] service-worker.js:

…
        // Pass the payment details to the frontend
        postMessage('PAYMENT_IS_READY', { total });
        break;
…

[payment handler] frontend:

let total;

navigator.serviceWorker.addEventListener('message', async e => {
  switch (e.data.type) {
      case 'PAYMENT_IS_READY':
        ({ total } = e.data);
        // Update the UI
        renderHTML(total);
        break;
…

Renvoyer les identifiants de paiement du client

Lorsque le client autorise le paiement, le frontend peut envoyer un message post au service worker pour continuer. Vous pouvez résoudre la promesse transmise à PaymentRequestEvent.respondWith() pour renvoyer le résultat au marchand. Transmettez un objet PaymentHandlerResponse.

Nom de propriété Description
methodName Identifiant du mode de paiement utilisé pour effectuer le paiement.
details Données spécifiques au mode de paiement qui fournissent les informations nécessaires au marchand pour traiter le paiement.

[payment handler] frontend:

  const paymentMethod = …

  postMessage('PAYMENT_AUTHORIZED', {
    paymentMethod,              // Payment method identifier
  });

[payment handler] service-worker.js:

…
// Received a message from the frontend
self.addEventListener('message', async e => {
  let details;
  try {
    switch (e.data.type) {
      …
      case 'PAYMENT_AUTHORIZED':
        // Resolve the payment request event promise
        // with a payment response object
        const response = {
          methodName: e.data.paymentMethod,
          details: { id: 'put payment credential here' },
        }
        resolver.resolve(response);
        // Don't forget to initialize.
        payment_request_event = null;
        break;
      …

Annuler la transaction de paiement

Pour permettre au client d'annuler la transaction, le frontend peut envoyer un message post au service worker pour ce faire. Le service worker peut ensuite résoudre la promesse transmise à PaymentRequestEvent.respondWith() avec null pour indiquer au marchand que la transaction a été annulée.

[payment handler] frontend:

  postMessage('CANCEL_PAYMENT');

[payment handler] service-worker.js:

…
// Received a message from the frontend
self.addEventListener('message', async e => {
  let details;
  try {
    switch (e.data.type) {
      …
      case 'CANCEL_PAYMENT':
        // Resolve the payment request event promise
        // with null
        resolver.resolve(null);
        // Don't forget to initialize.
        payment_request_event = null;
        break;
      …

Exemple de code

Tous les exemples de code que vous avez vus dans ce document étaient des extraits de l'exemple d'application fonctionnel suivant:

https://paymenthandler-demo.glitch.me

[payment handler] service worker

[payment handler] frontend

Pour essayer cette fonctionnalité:

  1. Accédez à la page https://paymentrequest-demo.glitch.me/.
  2. Accédez au bas de la page.
  3. Appuyez sur le bouton Ajouter un mode de paiement.
  4. Saisissez https://paymenthandler-demo.glitch.me dans le champ Identifiant du mode de paiement.
  5. Appuyez sur le bouton Payer à côté du champ.

Étapes suivantes

Dans cet article, nous avons appris à orchestrer une transaction de paiement à partir d'un service worker. L'étape suivante consiste à apprendre à ajouter des fonctionnalités plus avancées au service worker.