Paiements crypto sur WooCommerce
Comment ajouter la crypto comme moyen de paiement WooCommerce : une classe de passerelle sur mesure, la création du paiement Qvard, le webhook qui termine la commande et les pièges propres à WooCommerce.

WooCommerce offre un point d'extension propre pour les moyens de paiement, et Qvard n'en demande que deux choses : un appel qui crée un paiement quand le client paie, et un point de terminaison qui termine la commande quand le paiement est fait. Il n'existe pas encore de plugin Qvard prêt à l'emploi ; ce guide montre donc le code sur mesure, morceau par morceau, et les détails de WooCommerce qui tournent souvent mal.
Avant de commencer
Il vous faut un compte Qvard avec un projet, une clé API et une callback URL enregistrée dans le projet. Côté WooCommerce, il vous faut un moyen d'ajouter du code, idéalement un petit plugin sur mesure ou un plugin d'extraits de code, et non un fichier de thème qui disparaît à la prochaine mise à jour du thème.
Deux décisions préalables :
- Devise. Qvard fixe les paiements en dollars américains. La passerelle de ce guide accepte les commandes en USD et refuse les autres devises, ce qui est le choix sûr par défaut. Si votre boutique vend dans une autre devise, convertissez le total de la commande en dollars avant de créer le paiement et dites-le à la caisse.
- Où vit la clé. Définissez la clé API comme constante dans
wp-config.php(define( 'QVARD_API_KEY', '...' );), pas dans les réglages de la base de données, où les exports et d'autres plugins peuvent la lire.
Si vous voulez seulement l'idée de base sans la classe WooCommerce, commencez par paiements crypto sur WordPress.
Les pièces, et comment avance une commande
Trois pièces forment l'intégration :
- Une classe de passerelle de paiement qui apparaît à la caisse WooCommerce comme « Payer en crypto ».
- Un appel à Qvard dans la passerelle, qui crée un paiement pour la commande et renvoie l'adresse de la page de paiement hébergée.
- Un point de terminaison webhook que Qvard appelle lorsque le paiement est terminé.
Une commande avance ainsi : le client choisit le moyen de paiement et appuie sur payer ; la passerelle crée le paiement Qvard, met la commande en attente et redirige le client vers la page de paiement ; le client paie depuis un portefeuille ; Qvard appelle votre point de terminaison ; le point de terminaison termine la commande et WooCommerce envoie ses e-mails habituels et la fait avancer. L'id du paiement que vous envoyez à Qvard est le numéro de commande WooCommerce, et c'est ainsi que le webhook retrouve la commande.
La classe de la passerelle
La classe étend WC_Payment_Gateway. Son constructeur définit l'identifiant et le titre du moyen de paiement et charge les réglages, et process_payment fait le travail. Elle refuse les commandes qui ne sont pas en USD, puis envoie un POST vers https://api.qvard.com/api/v1/payment avec votre clé dans l'en-tête Authorization: Bearer et un JSON : id (le numéro de commande sous forme de chaîne) et price (le total en dollars américains). Une réponse 201 porte un redirectUrl.
En cas de succès, la passerelle enregistre l'identifiant du paiement Qvard dans la commande, met le statut à on-hold (« en attente de paiement »), vide le panier et renvoie le redirectUrl comme redirection. En cas d'échec, elle ajoute un avis d'erreur et renvoie failure, de sorte que le client reste à la caisse et peut choisir un autre moyen.
Envoyer le même id pour le même moyen de paiement renvoie le paiement existant ; un client qui appuie deux fois sur le bouton ne crée donc pas deux paiements.
<?php
// A minimal WooCommerce payment method that sends the customer to the Qvard payment page.
add_filter( 'woocommerce_payment_gateways', function ( $gateways ) {
$gateways[] = 'WC_Gateway_Qvard';
return $gateways;
} );
add_action( 'plugins_loaded', function () {
if ( ! class_exists( 'WC_Payment_Gateway' ) ) {
return;
}
class WC_Gateway_Qvard extends WC_Payment_Gateway {
public function __construct() {
$this->id = 'qvard';
$this->method_title = 'Qvard (crypto)';
$this->method_description = 'Accept USDT and other crypto through Qvard.';
$this->has_fields = false;
$this->init_form_fields();
$this->init_settings();
$this->title = $this->get_option( 'title', 'Pay with crypto' );
add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
}
public function init_form_fields() {
$this->form_fields = array(
'enabled' => array( 'title' => 'Enable', 'type' => 'checkbox', 'default' => 'no' ),
'title' => array( 'title' => 'Title', 'type' => 'text', 'default' => 'Pay with crypto' ),
);
}
public function process_payment( $order_id ) {
$order = wc_get_order( $order_id );
// Qvard prices payments in US dollars: refuse other shop currencies instead of charging a wrong amount.
if ( 'USD' !== $order->get_currency() ) {
wc_add_notice( 'Crypto payment is available for orders in USD only.', 'error' );
return array( 'result' => 'failure' );
}
$response = wp_remote_post( 'https://api.qvard.com/api/v1/payment', array(
'timeout' => 15,
'headers' => array( 'Authorization' => 'Bearer ' . QVARD_API_KEY, 'Content-Type' => 'application/json' ),
'body' => wp_json_encode( array( 'id' => (string) $order->get_id(), 'price' => (float) $order->get_total() ) ),
) );
if ( is_wp_error( $response ) || 201 !== wp_remote_retrieve_response_code( $response ) ) {
wc_add_notice( 'Could not start the payment. Please try again.', 'error' );
return array( 'result' => 'failure' );
}
$data = json_decode( wp_remote_retrieve_body( $response ), true );
if ( empty( $data['redirectUrl'] ) ) {
wc_add_notice( 'Could not start the payment. Please try again.', 'error' );
return array( 'result' => 'failure' );
}
$order->update_meta_data( '_qvard_payment_id', sanitize_text_field( $data['id'] ?? '' ) );
$order->update_status( 'on-hold', 'Waiting for the crypto payment.' );
WC()->cart->empty_cart();
return array( 'result' => 'success', 'redirect' => $data['redirectUrl'] );
}
}
} );Le webhook qui termine la commande
Enregistrez une route REST et sauvegardez son adresse dans votre projet Qvard comme callback URL. Lorsqu'un paiement est terminé, Qvard envoie un POST avec l'id et le status, signé dans l'en-tête X-Qvard-Signature. Le gestionnaire de l'exemple :
- vérifie la signature (HMAC-SHA256 avec votre clé secrète) avec le SDK de Qvard et répond
401si elle ne correspond pas ; - retrouve la commande par
idet ignore les commandes qui n'existent pas ou n'ont pas été payées avec cette passerelle, en répondant tout de même 200 pour que Qvard cesse de réessayer ; - appelle
payment_complete()seulement sur le statutcompletedet seulement si la commande n'est pas déjà payée, ce qui le rend sûr s'il s'exécute deux fois ; - répond exactement HTTP 200. Tout autre statut, un délai dépassé ou une redirection compte comme une livraison échouée et est réessayé, cinq tentatives en environ six minutes.
Autorisez la route dans tout plugin de sécurité ou pare-feu et assurez-vous que le cache ne touche pas à /wp-json/. Les règles plus larges sont dans comment sécuriser les webhooks de paiement crypto.
<?php
// Callback URL to save in the Qvard project: https://your-shop.com/wp-json/qvard/v1/webhook
add_action( 'rest_api_init', function () {
register_rest_route( 'qvard/v1', '/webhook', array(
'methods' => 'POST',
'permission_callback' => '__return_true', // authenticated below by the X-Qvard-Signature header
'callback' => function ( WP_REST_Request $request ) {
try {
$payload = ( new Qvard\Qvard( QVARD_API_KEY ) )->webhooks->constructEvent( $request->get_body(), $request->get_header( 'x-qvard-signature' ), QVARD_API_KEY );
} catch ( \Exception $e ) {
return new WP_REST_Response( null, 401 );
}
$order = wc_get_order( (int) ( $payload['id'] ?? 0 ) );
// Unknown order or not ours: nothing to retry, answer 200.
if ( ! $order || 'qvard' !== $order->get_payment_method() ) {
return new WP_REST_Response( null, 200 );
}
if ( 'completed' === ( $payload['status'] ?? '' ) && ! $order->is_paid() ) {
$order->payment_complete( (string) $order->get_meta( '_qvard_payment_id' ) );
$order->add_order_note( 'Qvard: payment completed.' );
}
return new WP_REST_Response( null, 200 ); // must be exactly 200
},
) );
} );Les détails WooCommerce qui mordent
- Stock. WooCommerce réduit le stock lorsqu'une commande passe en traitement ou en attente ; les commandes crypto impayées peuvent donc retenir du stock. Annulez les commandes en attente périmées après un délai de votre choix avec une tâche planifiée à vous (le réglage de rétention du stock de WooCommerce s'applique aux commandes en attente de paiement, pas à celles en attente) ; sinon le stock reste réservé.
- Paiements partiels. Si moins que le montant complet arrive, le statut du paiement est
partialet aucun webhook de fin n'est envoyé. La commande reste en attente ; ajoutez une note, demandez le reste au client ou annulez et remboursez. - Remboursements. Un paiement crypto ne peut pas être récupéré. Créez l'enregistrement de remboursement dans WooCommerce pour votre comptabilité, mais envoyez vous-même l'argent à une adresse que le client vous donne.
- E-mails de commande. L'e-mail « en attente » part lors de la commande ; assurez-vous que son texte dise au client que le paiement est en attente et où payer.
- Le retour sur le site. Les URL de retour après paiement ne sont pas encore disponibles ; le client revient donc dans votre boutique de lui-même. La page de commande standard affiche le statut réel, ce qui est correct.
- Caisse en blocs. La caisse WooCommerce basée sur des blocs a aussi besoin d'une passerelle enregistrée pour les blocs ; testez le moyen de paiement dans la caisse que vous utilisez réellement.
Testez avant la mise en production
- Ouvrez une facture de démonstration pour voir la page de paiement que recevra votre client.
- Passez une commande de test avec le moyen crypto et vérifiez que vous êtes redirigé vers la page de paiement et que la commande est en attente.
- Payez un petit montant réel et confirmez que le webhook arrive et que la commande passe en traitement.
- Faites échouer le point de terminaison une fois, confirmez que Qvard réessaie et que la commande n'est pas terminée deux fois.
- Retirez un petit montant de votre solde vers votre portefeuille pour savoir que tout le parcours fonctionne.
Il n'y a pas encore de sandbox séparé ; utilisez donc de petits montants réels.
Ce que cela coûte et ce qui est prêt
Il n'y a pas d'abonnement pour la passerelle. La commission est individuelle pour votre projet et, selon la page des tarifs, part de 1 % et peut descendre jusqu'à 0,1 %. Les fonds restent sur votre solde Qvard et vous les retirez vers votre propre portefeuille pour les frais de réseau ; le retrait vers un compte bancaire en monnaie fiat n'est pas disponible.
Qvard fonctionne via son API ; l'intégration demande donc un développeur et des tests ; il n'existe pas de plugin WooCommerce prêt à l'emploi, et les liens de paiement et un sandbox séparé sont en développement. L'API elle-même est décrite dans API de paiement crypto pour les développeurs et le côté boutique dans paiements crypto pour l'e-commerce.
FAQ
Existe-t-il un plugin Qvard pour WooCommerce ?
Pas encore. L'intégration passe par l'API : une classe de passerelle qui crée le paiement et un webhook qui termine la commande. Le code de ce guide est un point de départ pour un développeur.
Ma boutique est en euros. Les clients peuvent-ils quand même payer en crypto ?
Qvard fixe les paiements en dollars américains. Convertissez le total de la commande en dollars avant de créer le paiement et indiquez au client le montant en dollars à la caisse ; la passerelle de l'exemple refuse les commandes qui ne sont pas en USD comme choix sûr par défaut.
Quand la commande devient-elle payée ?
Lorsque le webhook arrive avec le statut completed. Un client revenu dans la boutique n'est pas une preuve de paiement, et le statut partial signifie que moins que requis est arrivé.
Et si mon site était arrêté quand le paiement s'est terminé ?
La notification est réessayée cinq fois en environ six minutes. Ensuite, renvoyez-la pour le paiement depuis l'espace client Qvard ; le gestionnaire est sûr s'il s'exécute deux fois.
