Intégrations

Bouton de paiement crypto pour sites web

Comment ajouter un bouton « Payer en crypto » à un site web : pourquoi le bouton ne peut pas appeler directement l'API de paiement, le schéma en trois étapes, du code front-end et serveur fonctionnel et ce qu'il faut protéger.

Un bouton « Payer en crypto » est facile à ajouter, mais il ne peut pas être un extrait à copier-coller : créer un paiement exige votre clé API secrète, qui ne doit jamais atteindre le navigateur. Le bouton doit donc parler à votre propre serveur, qui crée le paiement et renvoie l'adresse de la page de paiement. Ce guide montre ce schéma avec du code fonctionnel et les points qui le gardent sûr.

Pourquoi il n'y a pas encore de bouton à copier-coller

Beaucoup de prestataires de paiement offrent un bouton ou un widget intégrable. Qvard n'a pas encore de bouton sans code : les liens de paiement sont en développement. La caisse intégrée est prête comme widget pour votre site. Les SDK sont prêts. Aujourd'hui l'intégration passe par l'API, et l'API s'authentifie avec une clé secrète dans l'en-tête Authorization: Bearer.

Cette clé peut créer des paiements pour votre projet ; elle doit donc rester sur votre serveur. Un bouton qui porterait la clé dans du code front-end la remettrait à chaque visiteur. Ce n'est pas une limitation à contourner ; c'est la raison pour laquelle le schéma ci-dessous comporte une étape serveur.

Le schéma : bouton, votre point de terminaison, page de paiement

Trois étapes font un bouton qui marche :

  1. Le bouton envoie une requête à un point de terminaison de votre serveur, en disant ce que le visiteur veut acheter (un produit, un forfait), pas combien cela coûte.
  2. Votre point de terminaison retrouve le prix, crée votre propre enregistrement de commande et appelle Qvard : un POST vers https://api.qvard.com/api/v1/payment avec la clé dans l'en-tête Authorization: Bearer et un JSON avec votre numéro de commande comme id et le montant comme price en dollars américains. La réponse est 201 avec un redirectUrl.
  3. Le navigateur est redirigé vers ce redirectUrl, la page de paiement hébergée de Qvard, où le visiteur choisit un actif et un réseau et paie depuis un portefeuille.

Rien de secret ne touche la page, et la page de paiement elle-même est hébergée par Qvard ; vous ne construisez donc pas de caisse crypto.

Le front-end : un bouton et une redirection

Le bouton demande une quinzaine de lignes. Il se désactive pendant la requête, envoie l'identifiant du produit et, en cas de succès, envoie le navigateur à l'adresse renvoyée. En cas d'échec, il se réactive et affiche un message, pour que le visiteur puisse réessayer.

Gardez en tête une règle : le navigateur envoie ce qui est acheté, jamais combien. Si le montant venait de la page, n'importe qui pourrait ouvrir les outils de développement et transformer un forfait à 49 dollars en un paiement d'un dollar.

HTML + JSpay-button.html
<button id="pay-crypto" data-product="pro-plan">Pay with crypto</button>

<script>
  document.getElementById('pay-crypto').addEventListener('click', async (event) => {
    const button = event.currentTarget;
    button.disabled = true;
    try {
      // Send only WHAT is being bought; the server decides the price.
      const res = await fetch('/api/crypto-checkout', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ product: button.dataset.product })
      });
      if (!res.ok) throw new Error('checkout failed');
      const { redirectUrl } = await res.json();
      window.location.assign(redirectUrl);   // the Qvard hosted payment page
    } catch (e) {
      button.disabled = false;
      alert('Could not start the payment. Please try again.');
    }
  });
</script>

Le serveur : prix, commande, paiement

Le point de terminaison de l'exemple fait quatre choses :

  • Il retrouve le prix dans une table du serveur et rejette les produits inconnus.
  • Il crée votre propre commande et utilise son numéro comme id du paiement. C'est ainsi que le webhook retrouve ensuite la commande.
  • Il appelle Qvard et ne renvoie au navigateur que le redirectUrl. Une réponse 400 (« Error validation », avec un message par champ) signifie que le corps était erroné ; un 401 signifie que la clé est erronée. Aucun des deux ne doit être réessayé sans changement.
  • Il est sûr à répéter. Envoyer le même id pour le même moyen de paiement renvoie le paiement existant ; un visiteur qui clique deux fois n'en crée donc pas deux.

Ajoutez une limitation de fréquence au point de terminaison pour que personne ne puisse créer des milliers de commandes impayées, et exigez un utilisateur connecté ou un captcha si votre produit le nécessite.

Node.jscrypto-checkout.js
import express from 'express';
import crypto from 'node:crypto';

const app = express();
const PRICES_USD = { 'pro-plan': 49 };          // prices live on the server, never in the browser

app.post('/api/crypto-checkout', express.json(), async (req, res) => {
  const price = PRICES_USD[req.body.product];
  if (!price) return res.sendStatus(400);

  const orderId = await db.orders.create({ product: req.body.product, amountUsd: price }); // your own order number

  const response = await fetch('https://api.qvard.com/api/v1/payment', {
    method: 'POST',
    headers: { Authorization: 'Bearer ' + process.env.QVARD_API_KEY, 'Content-Type': 'application/json' },
    body: JSON.stringify({ id: String(orderId), price })
  });
  if (response.status !== 201) return res.sendStatus(502);

  const { redirectUrl } = await response.json();
  res.json({ redirectUrl });
});

Après le clic : c'est le webhook qui décide

Rediriger le visiteur vers la page de paiement démarre le paiement ; cela ne le termine pas. Lorsque le paiement est terminé, Qvard appelle la callback URL enregistrée dans votre projet avec votre id et le statut completed. Alors seulement, accordez l'accès ou marquez la commande comme payée. Le point de terminaison doit répondre exactement HTTP 200 et être sûr s'il s'exécute deux fois ; voir comment sécuriser les webhooks de paiement crypto.

Les URL de retour après paiement ne sont pas encore disponibles ; le visiteur revient donc sur votre site de lui-même. Donnez-lui une page qui affiche l'état réel de la commande et se rafraîchit pendant l'attente, et non une page de remerciement qui suppose le succès.

Prix fixes, montants variables et la suite

  • Les prix fixes (forfaits, produits) sont le cas facile : la table du serveur les contient.
  • Les montants variables (dons, recharges) demandent une validation côté serveur : un minimum, un maximum et un contrôle numérique. Un montant inférieur au minimum du moyen de paiement choisi est rejeté avec un 400.
  • Plusieurs boutons partagent le même point de terminaison ; seul l'identifiant du produit change.

Le parcours complet est dans comment accepter les paiements crypto sur un site web, et l'API dans API de paiement crypto pour les développeurs. Une facture de démonstration montre la page vers laquelle mène le bouton ; les conditions commerciales sont sur la page des tarifs.

FAQ

Puis-je mettre la clé API de Qvard dans le code du bouton ?

Non. La clé peut créer des paiements pour votre projet et doit rester sur votre serveur. Le bouton doit appeler votre propre point de terminaison, qui appelle Qvard.

Existe-t-il un widget intégrable ou un bouton sans code ?

Oui, la caisse intégrée est prête comme widget pour votre site. Pas encore de bouton sans code : les liens de paiement sont en développement. Les SDK sont prêts. Aujourd'hui l'intégration utilise l'API avec un petit point de terminaison serveur.

D'où doit venir le prix ?

De votre serveur, jamais du navigateur. Le bouton n'envoie que ce qui est acheté, et le serveur décide du prix en dollars américains.

Comment savoir que le client a payé ?

Par le webhook que Qvard envoie lorsque le paiement est terminé. Le retour du visiteur sur le site n'est pas une preuve de paiement.

Articles similaires

Articles similaires