Documentation / Intégration

Webhooks

Coinetic informe votre serveur de chaque changement d'une facture par une requête POST. Un webhook est un signal « allez consulter la facture », pas une preuve de paiement.

Configuration

  • Tableau de bord → « Clés et webhooks » → « Ajouter ». L'URL doit être en https://, vers une adresse publique sur le port 443 (en sandbox, http://localhost est aussi accepté).
  • Le secret de l'endpoint n'est affiché qu'une seule fois. Jusqu'à 5 endpoints actifs : chaque événement est envoyé à tous.

Requête

HTTP
POST /webhooks/coinetic HTTP/1.1
Content-Type: application/json
User-Agent: cryptopay-webhooks/1
X-Webhook-Id: evt_3f9c…
X-Webhook-Timestamp: 1760000000
X-Webhook-Signature: v1=5d1e…

{"id":"evt_3f9c…","type":"invoice.paid","created_at":"2026-10-12T15:04:05Z","livemode":true,"data":{"invoice_id":"inv_x7k2…","order_id":"ORDER-1001","status":"paid","paid_amount":"49990000"}}

X-Webhook-Id reste identique d'une relance à l'autre. Pendant une rotation du secret, X-Webhook-Signature contient deux signatures séparées par une virgule. Les noms techniques (cryptopay-webhooks/1) sont historiques : inutile de les modifier de votre côté.

Vérification de la signature

text
expected = "v1=" + hex(HMAC-SHA256(webhook_secret, X-Webhook-Timestamp + "." + raw_body))
  1. Prenez le corps brut, c'est-à-dire les octets avant tout parsing JSON.
  2. Vérifiez que X-Webhook-Timestamp ne s'écarte pas de l'heure actuelle de plus de 5 minutes.
  3. Découpez X-Webhook-Signature sur la virgule. La signature est valide si l'une quelconque des parties correspond à la valeur attendue (comparaison en temps constant).
  4. Aucune correspondance ? Répondez 401 et ne faites rien.

Valeurs de référence : secret whsec-0123456789abcdef0123456789abcdef, timestamp 1760000000, corps {"id":"evt_1","type":"invoice.paid"} → v1=aceeb56215ba09e7a2923d48f89afb8331f422f2d0a8cf60f76fef69fe06a6a4.

Traitement

text
vérifier la signature → dédupliquer par X-Webhook-Id → GET /v1/invoices/{invoice_id}
→ mettre à jour la commande selon le statut de l'API (livraison une seule fois) → répondre 2xx
  • Déduplication. Un même événement peut arriver plusieurs fois. Conservez les X-Webhook-Id déjà traités ; positionnez l'indicateur « livré » dans la même transaction que la livraison.
  • Répondez vite : en moins de 10 secondes. Placez les traitements longs dans une file d'attente.
  • Codes de réponse : 2xx = reçu ; 410 Gone = ne pas relancer cette livraison ; tout autre code (y compris 3xx : les redirections ne sont pas suivies) ou un délai dépassé = relance.
  • Ignorez les champs et types d'événements inconnus : la liste va s'allonger.

Des handlers prêts à l'emploi en quatre langages sont disponibles dans le démarrage rapide.

Relances

10 s → 30 s → 2 min → 10 min → 30 min → 1 h → 3 h ×7 → 1 h, avec une légère variation aléatoire. La dernière tentative a lieu environ 24 heures plus tard. Une livraison échouée peut être renvoyée manuellement : tableau de bord → « Webhooks » → « Renvoyer ».

Ordre de livraison

Les événements d'une même facture sont livrés à un endpoint dans l'ordre : le suivant ne part pas tant que la livraison précédente attend une relance. Qu'elle aboutisse ou échoue, les suivants partent ensuite. Fiez-vous donc au statut renvoyé par GET /v1/invoices/{id}, et non à l'enchaînement des événements. Les événements de factures différentes sont indépendants.

Types d'événements

ÉvénementQuand
invoice.detectedLe paiement est visible sur le réseau
invoice.confirmingLe paiement est inclus dans un bloc, les confirmations sont en cours
invoice.paidPayé et confirmé : vous pouvez livrer (après revérification). data.late: true : un stablecoin est arrivé après expiration et a été crédité automatiquement
invoice.overpaidPayé avec un excédent
invoice.underpaidMontant confirmé inférieur au montant dû
invoice.awaiting_paymentLa facture attend de nouveau un paiement (par exemple après le réorg de son unique paiement)
invoice.expiredDélai écoulé sans paiement
invoice.late_paymentPaiement en actif volatil reçu après expiration
invoice.manual_reviewPaiement en cours de contrôle AML
invoice.payment_heldPaiement bloqué par le contrôle AML (quarantaine)
invoice.reorgedLe bloc contenant le paiement a été annulé, le statut a été recalculé (par exemple paid → confirming)
invoice.payment_after_closePaiement reçu sur une facture déjà clôturée : il ne règle pas la commande et peut être remboursé
invoice.cancelledFacture clôturée sans paiement, par exécution d'un remboursement
refund.sentRemboursement exécuté ; data.refund contient le montant, l'adresse et le tx_hash

Les événements de facturation (billing.*) concernent les factures de commission de la plateforme : émission, paiement, retard, suspension et levée de la suspension.

Biens numériques et invoice.reorgedUn réorg après paid est rare, mais il arrive. Si vous livrez instantanément, abonnez-vous à cet événement et transmettez ces cas à votre support.

Rotation du secret

Tableau de bord → « Changer le secret » : Coinetic se met à signer avec les deux secrets.

  1. Ajoutez le nouveau secret sur votre serveur (acceptez les deux).
  2. Cliquez sur « Terminer la rotation » : l'ancien est supprimé.
  3. Retirez l'ancien secret de votre serveur.