Tutoriel : Google Pay

Ce tutoriel vous guidera avec la fonction de passerelle de paiement personnalisée de Snipcart. Nous allons voir comment ajouter une méthode de paiement qui n'est pas prise en charge par défaut dans votre boutique Snipcart. Nous utiliserons Google Pay pour ce tutoriel, qui n'est pas pris en charge directement par Snipcart. Veuillez noter qu'il s'agit uniquement d'une démonstration. Vous devez mettre à jour le code pour répondre à vos besoins.

Référence de PaymentRequest de l'API Google Pay
Référence de l'API de requête de paiement

Avant de commencer, assurez-vous d'avoir configuré votre tableau de bord du commerçant et d'avoir une compréhension de base du fonctionnement de la passerelle de paiement personnalisée.

1. Créer la page de paiement

La première étape pour intégrer une passerelle de paiement personnalisée consiste à créer la page de paiement. Il s'agit de la page vers laquelle l'utilisateur sera redirigé lorsqu'il utilisera la passerelle personnalisée. Lorsque vous redirigez vers cette page, ajoutez le paramètre de requête publicToken.

ex: YOUR_CHECKOUT_URL.com?publicToken=<THE_TOKEN>

Voici à quoi ressemble notre page de paiement de démonstration. Elle utilise l'API de requête de paiement.

Voir le dépôt Github pour plus de détails

1.1 Récupérer les informations de la commande

Dans la page de paiement, vous voudrez récupérer des informations de la commande. Pour ce faire, vous devez appeler notre point de terminaison d'API payment-session. Cela vous permettra d'afficher les informations relatives à la commande sur la page de paiement. Apprenez à récupérer des informations sur la session de paiement.

  // Get the payment session from Snipcart
  const fetchPaymentSession = async () => {
    const publicToken = new URLSearchParams(window.location.search).get('publicToken')
    try {
      const response = await axios
        .get(`https://payment.snipcart.com/api/public/custom-payment-gateway/payment-session?publicToken=${publicToken}`)
      paymentSession = response.data
      currency = paymentSession.invoice.currency
    } catch (e) {
      console.error(e)
    }
  }

1.2 API de requête de paiement

L'API de requête de paiement est utilisée pour traiter les paiements.

Créer les données de requête de Google Pay
Tout d'abord, vous devez créer les données de requête pour Google Pay.

  // Creates the Google Pay Request Data
  // This is needed for the Payment Request Api
  const createGooglePayRequestData = () => ({
    environment: 'TEST',
    apiVersion: 2,
    apiVersionMinor: 0,
    merchantInfo: {
      // A merchant ID is available after approval by Google.
      // 'merchantId':'12345678901234567890',
      merchantName: 'Example Merchant'
    },
    allowedPaymentMethods: [{
      type: 'CARD',
      parameters: {
        allowedAuthMethods: ["PAN_ONLY", "CRYPTOGRAM_3DS"],
        allowedCardNetworks: ["AMEX", "DISCOVER", "INTERAC", "JCB", "MASTERCARD", "VISA"]
      },
      tokenizationSpecification: {
        type: 'PAYMENT_GATEWAY',
        // Check with your payment gateway on the parameters to pass.
        // @see {@link https://developers.google.com/pay/api/web/reference/request-objects#gateway}
        parameters: {
          'gateway': 'example',
          'gatewayMerchantId': 'exampleGatewayMerchantId'
        }
      }
    }]
  })

Créer les détails du paiement
Les détails du paiement contiennent des informations sur la commande. Cela inclut le total, les articles et la devise. Utilisez les sessions de paiement précédemment récupérées pour obtenir ces informations.

  // Create the payment details
  const createPaymentDetails = () => ({
    total: {
      label: 'TOTAL',
      amount: {
        currency: currency,
        value: paymentSession.invoice.amount
      }
    },
    displayItems: paymentSession.invoice.items.map(i => {
      const isItem = i.type !== 'Discount' && i.type !== 'Tax' && i.type !== 'Shipping' // Filter items from discount, tax, and shipping
      const label = isItem ? `${i.name} x ${i.quantity}` : i.name // Add the quantity if needed
      return {
        label,
        amount: {
          value: i.amount,
          currency
        }
      }
    })
  })

Créer la requête de paiement
Ce qui suit instancie une nouvelle requête de paiement.

  // Create the payment request (Using the Payment Request API)
  const createPaymentRequest = () => {
    const supportedMethods = [
      { supportedMethods: 'https://google.com/pay', data: createGooglePayRequestData() },
    ]

    paymentDetails = createPaymentDetails()

    const options = {
      requestPayerEmail: true,
      requestPayerName: true
    }
    paymentRequest = new PaymentRequest(
      supportedMethods,
      paymentDetails,
      options
    )
  }

Lier le bouton d'achat à la requête de paiement

  // Add the buy button Event Listener
  const bindBuyButton = () => {
    paymentRequest.canMakePayment() // Validate the payment request
      .then(function (result) {
        if (result) {
          document.getElementById('pay').addEventListener('click', onBuyClicked);
        }
      })
      .catch(function (err) {
        console.log(err)
      })
  }

Traiter le paiement

// Add the event listener on the Buy button
  const onBuyClicked = async () => {
    try {
      const paymentRes = await paymentRequest.show()
      await handlePayment(paymentRes)
    } catch (e) {
      console.log(e)
    }
  }
  // Payment completed callback
  const handlePayment = async (paymentRes) => {
    try {
      const res = await axios.post(`/api/confirm-payment?sessionId=${paymentSession.id}`, paymentRes)
      paymentRes.complete('success')
      window.location.href = res.data.returnUrl
    } catch (e) {
      console.error(e)
    }
  }

Vous pouvez voir le code complet dans le dépôt Github

2. Point de terminaison des méthodes de paiement

L'étape suivante pour intégrer une passerelle de paiement personnalisée consiste à créer le point de terminaison des méthodes de paiement. Le publicToken est fourni dans le corps de la requête.

Assurez-vous que vous validez que la requête a été faite par notre API.

Référence du webhook des méthodes de paiement

async (req, res) => {
  if (req.body && req.body.publicToken) {
    try {
      // Validate the request was made by Snipcart
      await axios.get(`https://payment.snipcart.com/api/public/custom-payment-gateway/validate?publicToken=${req.body.publicToken}`)
      // Return the payment methods
      return res.json([{
        id: 'paymentrequest-custom-gateway',
        name: 'Google pay',
        checkoutUrl: 'https://paymentrequest-custom-gateway.snipcart.vercel.app',
        iconUrl: `https://paymentrequest-custom-gateway.snipcart.vercel.app/google_pay.png`
      }])
    }catch(e){
      // Couldn't validate the request
      console.error(e)
      return res.status(401).send()
    }
  }
  // No publicToken provided. This means the request was NOT made by Snipcart
  return res.status(401).send()
}

3. Confirmer le paiement

Ce point de terminaison est utilisé pour valider le paiement avec Snipcart lorsque votre passerelle de paiement l'approuve. Il doit être appelé avec les informations de paiement. Cela doit être fait côté serveur car nous ne voulons pas divulguer notre clé API secrète.

Créer une référence de paiement

async (req, res) => {

  // TODO: Validate the request was approved by your payment gateway (in this case Google Pay)

  // Parse the gateway payment info to match Snipcart's schema
  // This will change depending on the payment gateway you choose
  const paymentSessionId = req.query.sessionId
  const data = {
    paymentSessionId,
    state: 'processed',
    transactionId: req.body.requestId,
    instructions: 'Your payment will appear on your statement in the coming days',
    links: {
      refunds: `https://paymentrequest-custom-gateway.snipcart.vercel.app/api/refund?transactionId=${req.body.requestId}`
    },
  }

  // Add authentification
  // This is the secret API key created in Snipcart's merchant dashboar
  const options = {
    headers: {
      Authorization: 'Bearer <YOUR_SECRET_API_KEY>'
    }
  }

  try{
    // Confirm payment with Snipcart
    const resp = await axios.post(`${process.env.PAYMENT_URL}/api/private/custom-payment-gateway/payment`,data, options)

    // ReturnUrl will redirect the user to the Order confirmation page of Snipcart
    return res.json({
      returnUrl: resp.data.returnUrl
    })
  }catch(e){
    console.error(e)
  }

  return res.status(500).send()
}

4. Remboursement (facultatif)

Ceci est appelé lors du remboursement d'une commande via le tableau de bord du commerçant.

Assurez-vous que vous validez que la requête a été faite par notre API.

Référence du webhook de remboursement

async (req, res) => {
  const { transactionId } = req.query
  try {
    // Validate the request was made by Snipcart
    await axios.get(`https://payment.snipcart.com/api/public/custom-payment-gateway/validate?publicToken=${req.body.publicToken}`)

    // TODO: Refund the order via the gateway

    return res.json({
      refundId: transactionId
    })
  } catch (e) {
    // Couldn't validate the request
    console.error(e)
    return res.status(401)
  }
}