Accepter les paiements crypto

Comment accepter des paiements crypto sur un site web

Pas à pas : créer un paiement depuis votre serveur, envoyer le client vers la page de paiement, traiter le webhook et le tester. Avec du code Node.js fonctionnel.

Pour accepter la crypto sur un site web, il vous faut deux choses sur votre serveur : un appel qui crée un paiement pour une commande et un endpoint qui reçoit le résultat. Ce guide parcourt les deux avec du code fonctionnel, puis aborde les tests, les cas limites et les erreurs qui coûtent de l’argent aux commerçants.

Ce qu’il vous faut avant de commencer

Vous n’avez pas besoin d’exploiter un nœud de blockchain ni de conserver des portefeuilles clients. Il vous faut :

  • un compte sur la passerelle avec un projet, une clé API et, si vous voulez fixer vous-même le moyen de paiement, l’ID de ce moyen dans votre projet ;
  • un endpoint HTTPS public sur votre serveur pour le webhook, enregistré dans le projet comme callback URL ;
  • un emplacement dans votre système de commandes pour stocker l’état du paiement, associé à votre propre numéro de commande.

Décidez tôt d’un point : le client choisit-il l’actif et le réseau sur la page de paiement, ou les présélectionnez-vous ? Laisser le client choisir est plus simple et convient à la plupart des boutiques. Si vous transmettez un moyen de paiement, la page s’ouvre avec celui-ci déjà sélectionné.

Comment l’ensemble du flux s’articule

Voici le parcours d’une commande, de votre caisse jusqu’au statut payé :

  1. Le client choisit « Payer en crypto » à la caisse et votre serveur crée un paiement pour cette commande.
  2. La passerelle renvoie un lien vers sa page de paiement hébergée.
  3. Vous redirigez le client vers cette page. Il choisit un actif et un réseau et envoie le montant exact depuis son propre portefeuille.
  4. La passerelle surveille la blockchain et, quand le paiement est définitif, appelle votre webhook.
  5. Votre webhook marque la commande comme payée et lance son traitement.

Remarquez ce qui n’arrive jamais de votre côté : vous ne générez pas d’adresses, vous ne scannez pas de blocs et vous ne comparez pas de montants. Votre code accomplit deux petites tâches : créer le paiement et réagir au statut final.

Étape 1 : créez le paiement depuis votre serveur

Appelez la passerelle depuis votre backend, jamais depuis le navigateur, car la requête porte votre clé API secrète. Avec Qvard, il s’agit d’un seul POST vers https://api.qvard.com/api/v1/payment avec votre clé dans l’en-tête x-api-key et un corps JSON :

  • id : votre propre numéro de commande, sous forme de chaîne. Il vous est renvoyé plus tard dans le webhook ; utilisez donc quelque chose que vous pouvez retrouver.
  • price : le montant en dollars américains. Le client paie l’équivalent dans l’actif qu’il choisit.
  • paymentSystemId (facultatif) : l’ID d’un moyen de paiement de votre projet, pour présélectionner l’actif et le réseau.

En cas de succès, la réponse est 201 avec un id de paiement et un redirectUrl. Renvoyer le même id avec le même moyen de paiement renvoie le paiement existant au lieu d’en créer un en double ; réessayer après un délai d’attente dépassé est donc sans risque.

Si la requête est incorrecte, vous recevez 400 avec le texte Error validation et un message par champ ; un montant inférieur au minimum du moyen choisi est rejeté de la même façon. Une clé absente ou fausse renvoie 401.

Node.jscreate-payment.js
// Called from your checkout handler when the customer chooses "Pay with crypto".
async function createQvardPayment(order) {
  const res = await fetch('https://api.qvard.com/api/v1/payment', {
    method: 'POST',
    headers: {
      'x-api-key': process.env.QVARD_API_KEY,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      id: String(order.id),        // your order number, also used to match the webhook
      price: order.totalUsd        // amount in US dollars
    })
  });

  if (!res.ok) throw new Error('Qvard ' + res.status + ' ' + (await res.text()));

  const { redirectUrl } = await res.json();
  return redirectUrl;              // send the customer to this page
}

Étape 2 : envoyez le client vers la page de paiement

Redirigez le client vers redirectUrl, de la forme https://my.qvard.com/pay/<id du paiement>. Sur cette page, il choisit l’actif et le réseau, voit le montant exact et l’adresse, et paie depuis son portefeuille. Le taux de change est figé pendant une heure ; le montant ne change donc pas pendant qu’il paie.

Deux points à anticiper :

  • Le retour. Les URL de retour après paiement ne sont pas encore disponibles ; le client revient donc sur votre site de lui-même. Donnez-lui une page de commande qui affiche l’état actuel et se met à jour quand votre webhook arrive.
  • Ne prenez pas le retour pour un paiement. Un client revenu sur votre site n’a pas forcément payé. Seul le webhook vous dit que l’argent est arrivé.

Étape 3 : recevez le webhook

Quand un paiement est terminé, Qvard envoie un POST à la callback URL de votre projet avec un petit JSON : l’id que vous avez envoyé et le status du paiement. La requête porte votre clé API dans l’en-tête x-api-key. C’est un en-tête d’authentification, pas une signature cryptographique : comparez-le à votre clé et rejetez tout le reste.

Le fonctionnement de la livraison est important pour votre gestionnaire :

  • Qvard considère le webhook comme livré uniquement quand votre endpoint répond exactement HTTP 200. Tout autre code de statut ou un dépassement de délai compte comme un échec.
  • Une livraison échouée est retentée : cinq tentatives au total, sur environ six minutes.
  • Les redirections ne sont pas suivies ; une réponse 3xx est donc aussi un échec.
  • Vous pouvez aussi renvoyer la notification d’un paiement depuis l’espace client.

À cause des relances, votre gestionnaire doit être idempotent : recevoir deux fois le même événement ne doit pas faire expédier la commande deux fois. L’exemple ci-dessous vérifie la clé, trouve la commande par votre id et ne la marque payée que si elle ne l’est pas déjà.

Node.jswebhook.js
import crypto from 'node:crypto';
import express from 'express';

const app = express();

app.post('/webhooks/qvard', express.json(), async (req, res) => {
  // Qvard sends your API key in the x-api-key header: compare it with yours.
  const received = Buffer.from(String(req.get('x-api-key') || ''));
  const expected = Buffer.from(process.env.QVARD_API_KEY);
  const valid = received.length === expected.length && crypto.timingSafeEqual(received, expected);
  if (!valid) return res.sendStatus(401);

  const { id, status } = req.body;          // id is the order number you sent
  const order = await db.orders.findById(id);
  if (!order) return res.sendStatus(200);   // unknown order: nothing to retry

  if (status === 'completed' && order.state !== 'paid') {
    await markOrderPaid(order);             // safe to run twice: the check above skips repeats
  }

  return res.sendStatus(200);               // must be exactly 200, otherwise Qvard retries
});

Gérez les paiements atypiques

Un paiement a l’un de ces quatre statuts :

  • wait : créé, en attente du client.
  • partial : le client a envoyé moins que nécessaire.
  • completed : le montant complet est arrivé ; c’est lui qui déclenche le webhook.
  • rejected : le paiement a été rejeté.

Décidez à l’avance ce que fait votre boutique dans chaque cas. Pour partial, le choix habituel est de garder la commande ouverte et de demander au client d’envoyer le reste, ou de le rembourser. Gardez une logique simple : marquez une commande comme payée uniquement avec completed et affichez au client un message clair pour tous les autres états.

Testez avant la mise en production

Un court plan de test qui détecte la plupart des problèmes :

  1. Ouvrez une facture de démonstration pour voir la page de paiement comme votre client la verra.
  2. Créez un paiement depuis votre serveur et vérifiez que vous recevez un redirectUrl.
  3. Payez un petit montant réel et confirmez que le webhook arrive et que la commande passe au statut « payé ».
  4. Faites renvoyer une erreur à votre endpoint une fois, vérifiez que Qvard retente et que votre gestionnaire ne traite pas la commande deux fois.
  5. Retirez un petit montant de votre solde vers votre portefeuille pour vérifier que tout le parcours fonctionne.

Qvard n’a pas encore d’environnement de test séparé ; un sandbox est prévu, utilisez donc de petits montants réels pour les étapes 3 à 5.

Liste de contrôle de sécurité

  • Gardez la clé API uniquement côté serveur. Ne la placez jamais dans du code front-end ni dans un dépôt public.
  • Comparez l’en-tête x-api-key à chaque webhook et rejetez toute valeur différente, avec une comparaison en temps constant.
  • Servez l’endpoint en HTTPS et gardez-le rapide ; faites le travail lent après avoir répondu.
  • Rapprochez les paiements des commandes par votre propre id et ignorez les événements de commandes inconnues.
  • Journalisez chaque webhook avec son statut afin de pouvoir résoudre les litiges plus tard.

Plus d’informations sur ce sujet dans comment sécuriser les webhooks de paiement crypto.

Et WooCommerce, Shopify ou une autre plateforme ?

Ce sont les deux mêmes appels qui s’appliquent : le code de votre plateforme crée le paiement et reçoit le webhook. Qvard n’a pas encore de plugin prêt à l’emploi ; sur une plateforme comme WooCommerce, l’intégration est donc un petit morceau de code sur mesure ou une heure de travail d’un développeur, pas une installation en un clic. Voyez les intégrations pour connaître l’état d’avancement, et la page développeurs pour la référence de l’API. Si vous voulez d’abord la vue d’ensemble, commencez par qu’est-ce qu’une passerelle de paiement crypto.

FAQ

Dois-je maîtriser le développement blockchain ?

Non. Vous faites une requête HTTP pour créer un paiement et vous traitez un webhook. Les adresses, la surveillance du réseau et les confirmations sont gérées par la passerelle.

Puis-je accepter la crypto sans écrire de code ?

Pas encore avec Qvard. Les liens de paiement et d’autres moyens d’encaisser sans code sont en développement ; aujourd’hui, l’intégration passe par l’API, ce qui demande un développeur.

Que se passe-t-il si mon serveur est en panne quand le paiement se termine ?

La notification est retentée cinq fois sur environ six minutes. Si votre serveur est resté indisponible plus longtemps, renvoyez la notification de ce paiement depuis l’espace client et faites le rapprochement à partir de là.

Dans quelle devise dois-je fixer le prix ?

En dollars américains. Le client paie l’équivalent dans l’actif et le réseau qu’il choisit sur la page de paiement, à un taux figé pendant une heure.

Articles similaires

Articles similaires