Webhook URL
Aperçu
Cette fonction remet les données d'une facture payée au serveur du marchand. Elle existe pour que la boutique du marchand traite le paiement automatiquement et livre le produit ou le service à votre client.
Le Webhook URL se définit individuellement pour chaque projet et pointe vers les scripts du gestionnaire de paiement à l'intérieur de la boutique du marchand. L'adresse doit utiliser HTTPS et un nom de domaine : les adresses IP ne sont pas acceptées, et le certificat est vérifié à chaque remise.
Chaque fois que le statut d'une facture passe à Payée (Paid), le service envoie une requête POST vers cette URL au format suivant :
{
"wallet":{
"id":"47aa71e2-07a0-482e-9172-7114d7376ba0",
"name":"usdt-tron",
"blockchain":"tron",
"cryptocurrency":"usdt",
"address":"TKbstUwMzLrfTAGL4erYb7gc7ghmHQ9zG7"
},
"project":{
"id":"9deea1e2-0c08-41a3-bdc2-a34eada3892d",
"name":"My project",
"commissionPayer":"seller",
"commissionRate":1
},
"invoice":{
"id":"a4c9e2ee-9a03-43e5-a1a1-00caf679d16a",
"uid":"AFhygKX21ecd",
"createDatetime":"2024-02-26 13:29:24",
"timeToPayDatetime":"2024-02-27 01:29:24",
"commissionFiatUSD":0.05,
"amountFiatUSD":5.02,
"amountFiat":5,
"calcAmountFiat":5.02,
"currencyFiat":"USD",
"description":null,
"serviceData":null,
"status":"paid"
},
"payment":{
"id":"f986ad8d-2298-473d-982a-efbc817b975d",
"amount":5.02,
"hash":"74763b65e43bcc9492a6ce9a7f26fbfdbd7635aecd3454420b5e9534cba50ee6",
"transactionDatetime":"2024-02-26 13:32:57"
}
}
La notification est envoyée à chaque passage au statut Payée — aussi bien quand le service a trouvé le paiement automatiquement que quand le marchand a associé le paiement à la facture manuellement.
Paramètres de la requête
| Paramètre | Description |
|---|---|
wallet.id | ID du portefeuille au format UUID |
wallet.name | Nom du portefeuille |
wallet.blockchain | La blockchain du portefeuille crypto |
wallet.cryptocurrency | La cryptomonnaie du portefeuille |
wallet.address | L'adresse du portefeuille crypto |
project.id | ID du projet au format UUID |
project.name | Nom du projet |
project.commissionPayer | Qui paie la commission du service |
project.commissionRate | Tarif en % |
invoice.id | ID de la facture au format UUID |
invoice.uid | ID de la facture (pour le client) |
invoice.createDatetime | Date et heure de création de la facture (UTC) |
invoice.timeToPayDatetime | Date et heure de fin de validité de la facture pour le client (UTC). La recherche du paiement continue pendant encore une heure après ce repère — pour tenir compte des réseaux lents. Une notification peut donc arriver pour une facture déjà affichée comme expirée |
invoice.commissionFiatUSD | Montant de la commission du service. Calculé à partir du montant invoice.amountFiatUSD |
invoice.amountFiatUSD | Montant en USD. À la création de la facture, il est calculé à partir de invoice.amountFiat au taux de change actuel. Au moment du paiement, il est remplacé par le montant réellement reçu, converti en USD au taux de ce moment. La commission dans invoice.commissionFiatUSD est elle aussi recalculée à partir de ce montant |
invoice.amountFiat | Le montant d'origine de la facture en devise fiat. Ne change pas |
invoice.calcAmountFiat | Le montant calculé dans la devise invoice.currencyFiat au taux de change de la crypto au moment du paiement. Il peut différer de invoice.amountFiat parce que le client peut avoir payé la facture quelque temps après la création plutôt que tout de suite. Pendant ce temps, le taux de la crypto face à invoice.currencyFiat a pu bouger dans un sens ou dans l'autre |
invoice.currencyFiat | Devise fiat |
invoice.description | La description définie à la création de la facture |
invoice.serviceData | Les données de service définies à la création de la facture |
invoice.status | Statut de la facture |
payment.id | ID du paiement au format UUID |
payment.amount | Montant du paiement en cryptomonnaie |
payment.hash | Le hash de la transaction on-chain |
payment.transactionDatetime | Date et heure de la transaction on-chain (UTC) |
Signature de la notification
Chaque requête est signée avec le secret du webhook. La signature voyage dans les en-têtes X-Timestamp et X-Signature et permet de s'assurer que la notification vient du service, pas d'un tiers qui aurait appris l'adresse de votre gestionnaire.
Vérifiez la signature avant de traiter la commande. La mécanique et des exemples prêts à l'emploi sont dans Vérification de la signature du webhook.
Conseils de traitement
Ne rejetez pas une notification parce que le délai de paiement est passé. Un contrôle du type « la facture est expirée, donc le paiement est invalide » semble logique mais écarte une part de paiements réels : sur les réseaux lents, une transaction peut se confirmer après le délai, et le marchand peut associer manuellement un paiement à une facture expirée. La notification elle-même confirme le paiement.
Vérifiez le montant par rapport au champ d'origine invoice.amountFiat. C'est le montant de la facture telle qu'émise, et il ne change pas. Le champ amountFiatUSD reflète le montant réellement reçu et peut différer du montant émis — à cause des mouvements du taux comme de l'association manuelle d'un paiement.
Analysez les montants comme des nombres. Les zéros finaux sont supprimés : un montant de 10.00 arrive comme 10 ; formatez-le de votre côté pour l'affichage. Les montants sous 0.0001 arrivent en notation exponentielle, par exemple 1.0e-6 — l'analyse JSON standard renvoie le bon nombre ; seule l'analyse manuelle de la chaîne casse.
Traitez les notifications de façon idempotente. La même notification peut arriver à nouveau — par exemple, si votre script a traité le paiement avec succès mais a renvoyé un code non-2xx. Avant de livrer la commande, vérifiez si cet invoice.id a déjà été traité.
Échappez les valeurs à l'affichage. Les champs invoice.description et invoice.serviceData reviennent exactement tels que le marchand les a soumis. Si vous les affichez en HTML, échappez-les de votre côté.
Calendrier de remise
Le serveur au Webhook URL doit répondre avec un code HTTP 2xx. Tout autre code, un dépassement de délai ou une connexion coupée compte comme une remise échouée.
Les redirections ne sont pas suivies : une réponse 301 ou 302 est une remise échouée, pas un saut vers la nouvelle adresse. Indiquez l'adresse finale du gestionnaire.
La connexion dispose de 5 secondes, la requête entière de 10 secondes. Si le gestionnaire ne tient pas dans ce délai, la remise compte comme échouée.
Après une remise échouée, le service refait une tentative selon le calendrier suivant :
- 5 minutes après la dernière remise échouée
- Après 15 minutes
- Après 30 minutes
- Après 1 heure
- Après 3 heures
- Après 6 heures
- Après 12 heures
- Après 24 heures
Ensuite, les tentatives de remise s'arrêtent.
Désactivation du Webhook URL
Il arrive que le script webhook d'une boutique traite le paiement correctement mais renvoie un code HTTP non-2xx. Cela entraîne de fréquentes nouvelles tentatives de notre serveur selon le calendrier ci-dessus, avec une charge supplémentaire pour notre serveur comme pour le vôtre.
Pour prévenir ces cas, nous avons un mécanisme qui désactive le Webhook URL d'un projet. Pour l'éviter, procédez ainsi :
- Modifiez le code de votre gestionnaire de webhook pour qu'il renvoie un code 2xx, habituellement 200, quand le paiement est traité avec succès. Testez-le avec n'importe quel émulateur, par exemple Postman.
- Contactez l'assistance technique pour corriger les réglages.
- Réactivez le Webhook URL dans les réglages du projet et enregistrez le projet.