Webhooks
QuantaPay envoie des requêtes HTTP POST à l'URL de webhook configurée lorsque des événements de paiement surviennent. Cela permet à votre serveur de réagir aux paiements en temps réel.
QuantaPay envoie des requêtes HTTP POST à l'URL de webhook configurée lorsque des événements de paiement surviennent. Cela permet à votre serveur de réagir aux paiements en temps réel.
Configuration
Configurez votre webhook dans Paramètres → Paiements → Webhook :
- Webhook URL : Votre endpoint HTTPS (ex. : https://votresite.com/webhook/quantapay)
- Webhook Secret Key : Clé générée automatiquement pour la vérification du payload
Payload du Webhook
Lorsqu'un paiement est complété, QuantaPay envoie une requête POST avec Content-Type: application/json :
{
"key": "your-webhook-secret-key",
"transaction": {
"id": "197",
"biz_id": "QP-20260408-560BF",
"title": "",
"description": "",
"from": "0xCustomerWalletAddress",
"to": "0xYourWalletAddress",
"hash": "0xBlockchainTransactionHash",
"amount": "0.025",
"amount_fiat": "49.99000000",
"cryptocurrency": "eth",
"currency": "usd",
"external_reference": "your-order-id-123",
"creation_time": "2026-03-08 10:00:00",
"status": "C",
"webhook": "1",
"vat": "0",
"billing": "",
"checkout_id": null,
"type": "2"
}
}
Champs de la transaction
| Champ | Type | Description |
|---|---|---|
id | string | ID interne de la transaction QuantaPay. |
biz_id | string | Référence de commande QuantaPay (ex. : QP-20260408-560BF). |
title | string | Titre de la transaction. |
from | string | Adresse de portefeuille du client (expéditeur). |
to | string | Votre adresse de portefeuille (destinataire). |
hash | string | Hash de la transaction blockchain. |
amount | string | Montant en cryptomonnaie. |
amount_fiat | string | Montant en monnaie fiduciaire (8 décimales, ex. : "49.99000000"). |
cryptocurrency | string | Code de la cryptomonnaie (ex. : btc, eth, usdt). |
currency | string | Code de la devise fiduciaire (ex. : usd, eur, hkd). |
external_reference | string | Votre ID de commande — fourni lors de la création de la Checkout Session. Utilisez-le pour retrouver votre commande. |
creation_time | string | Horodatage de création de la transaction (UTC). |
status | string | Statut de la transaction : C (complétée). |
checkout_id | string|null | ID de la Checkout Session associée, ou null. |
type | string | Type de transaction : 1 = paiement direct, 2 = Checkout Session. |
Associer les commandes avec external_reference
C'est la méthode recommandée pour lier un paiement QuantaPay à votre propre commande.
Lors de la création d'une Checkout Session, passez l'ID de votre commande dans le champ external_reference :
{
"order_id": "your-order-id-123",
"external_reference": "your-order-id-123",
"price": 49.99,
"currency": "usd"
}
QuantaPay stocke cette valeur et la retourne inchangée dans le payload du webhook sous transaction.external_reference. Utilisez-la pour retrouver et exécuter la commande correcte.
Vérification de la signature
Le champ key du payload contient votre Webhook Secret Key. Si aucune clé n'est configurée, le système utilise la clé de chiffrement du compte. Configurez toujours une Webhook Secret Key dédiée.
Exemple PHP
$payload = json_decode(file_get_contents('php://input'), true);
$webhook_secret = 'your-webhook-secret-key'; // From Settings
// 1. Verify webhook authenticity
if ($payload['key'] !== $webhook_secret) {
http_response_code(401);
die('Invalid webhook signature');
}
$transaction = $payload['transaction'];
// 2. Check payment is complete
if ($transaction['status'] !== 'C') {
http_response_code(200);
die('Not completed');
}
// 3. Match your order using external_reference
$your_order_id = $transaction['external_reference'];
$order = find_order($your_order_id);
if (!$order) {
http_response_code(200);
die('Order not found');
}
// 4. Verify amount using float comparison (amount_fiat has 8 decimal places)
$paid_amount = floatval($transaction['amount_fiat']);
$expected_amount = floatval($order->total);
if (abs($paid_amount - $expected_amount) > 0.01 || $transaction['currency'] !== $order->currency) {
http_response_code(200);
die('Amount mismatch');
}
// 5. Idempotency check — use biz_id as dedup key
if (order_already_fulfilled($transaction['biz_id'])) {
http_response_code(200);
die('Already processed');
}
// 6. Mark order as paid
fulfill_order($your_order_id);
http_response_code(200);
echo 'OK';
Exemple Node.js
const express = require('express');
const app = express();
app.use(express.json());
const WEBHOOK_SECRET = 'your-webhook-secret-key';
app.post('/webhook/quantapay', (req, res) => {
const { key, transaction } = req.body;
// 1. Verify webhook authenticity
if (key !== WEBHOOK_SECRET) {
return res.status(401).send('Invalid signature');
}
// 2. Only process completed payments
if (transaction.status !== 'C') {
return res.status(200).send('OK');
}
// 3. Match your order using external_reference
const yourOrderId = transaction.external_reference;
const bizId = transaction.biz_id; // use as dedup key
console.log(`Payment completed: ${transaction.amount_fiat} ${transaction.currency}`);
console.log(`Your order: ${yourOrderId}, QuantaPay ref: ${bizId}`);
console.log(`TX Hash: ${transaction.hash}`);
// Fulfill order logic here (use biz_id for idempotency)
res.status(200).send('OK');
});
app.listen(3000);
Test cURL
curl -X POST https://yoursite.com/webhook/quantapay \
-H "Content-Type: application/json" \
-d '{
"key": "your-webhook-secret-key",
"transaction": {
"id": "197",
"biz_id": "QP-20260408-560BF",
"status": "C",
"amount": "0.025",
"amount_fiat": "49.99000000",
"cryptocurrency": "eth",
"currency": "usd",
"external_reference": "your-order-id-123",
"hash": "0xabc123..."
}
}'
Types d'événements
| Statut | Événement | Description |
|---|---|---|
C | Paiement complété | Le paiement a été confirmé sur la blockchain avec suffisamment de confirmations. |
Remarque : Les webhooks ne sont envoyés que pour les transactions complétées (statut C). Les transactions expirées et en attente ne déclenchent pas de webhooks.
Bonnes pratiques
1. Répondre rapidement
Retournez HTTP 200 dès la réception du webhook. Traitez les tâches lourdes de manière asynchrone.
2. Traitement idempotent
Votre gestionnaire doit être idempotent — traiter le même webhook deux fois ne doit pas entraîner de doublons. Utilisez biz_id comme clé de déduplication.
if (order_already_fulfilled($transaction['biz_id'])) {
http_response_code(200);
die('Already processed');
}
3. Vérifier la clé
Vérifiez toujours que le champ key correspond à votre Webhook Secret Key avant traitement.
4. Utiliser HTTPS
Utilisez toujours un endpoint HTTPS pour votre URL de webhook.
5. Tout journaliser
Journalisez tous les webhooks entrants à des fins de débogage et d'audit.
error_log('QuantaPay Webhook: ' . json_encode($payload));
6. Gérer les échecs avec élégance
QuantaPay ne retente pas automatiquement les webhooks échoués. Utilisez l'API get-checkout-session ou get-transactions comme solution de repli pour vérifier le statut du paiement si votre serveur était temporairement indisponible.