Présentation
Un webhook est une adresse internet (une URL) appartenant à votre association : celle de votre serveur, de votre CRM ou d'un outil comme Make ou Zapier. Dès qu'un événement se produit sur Donoor, Donoor envoie à cette adresse une requête HTTPS POST qui décrit l'événement au format JSON.
Chaque message est signé avec un secret que vous seul connaissez : votre serveur peut ainsi vérifier qu'il vient bien de Donoor et qu'il n'a pas été modifié. Si votre serveur ne répond pas, Donoor réessaie automatiquement pendant environ 28 heures.
Un événement a lieu
don, adhésion, billet…
Donoor envoie un message signé
POST · Donoor-Signature
Votre serveur
vérifie, répond 200, traite
Publicité — transmettre chaque don comme conversion à Google Ads, GA4 ou Meta, avec la campagne d'origine.
CRM — créer ou mettre à jour la fiche du donateur, de l'adhérent ou de l'acheteur.
Comptabilité — enregistrer paiements, remboursements, reçus fiscaux et versements bancaires.
Automatisation — prévenir votre équipe, remplir un tableur, lancer un e-mail de bienvenue.
Démarrage rapide
Comptez une quinzaine de minutes pour recevoir votre premier message.
- 1
Préparez une adresse de réception
Une adresse https joignable depuis Internet, sur votre serveur ou dans un outil comme Make ou Zapier. Pour essayer sans rien installer, une adresse gratuite de webhook.site suffit.
- 2
Ajoutez-la dans votre tableau de bord
Paramètres › Webhooks › Ajouter une adresse. Donnez-lui une description et choisissez les événements à recevoir (tous, par défaut).
- 3
Copiez le secret
Il commence par whsec_. Rangez-le dans la configuration de votre serveur, jamais dans une page web ou un dépôt de code public.
- 4
Vérifiez la signature et répondez 200
Votre serveur vérifie l'en-tête Donoor-Signature puis répond par un code 2xx en moins de 10 secondes. Le code prêt à copier est plus bas, en Node.js, PHP et Python.
- 5
Envoyez un message d'essai
Bouton Envoyer un test, ou Simuler un événement pour recevoir n'importe lequel des 28 événements avec des données fictives. Vérifiez ensuite le résultat dans le journal des envois.
Seuls les événements qui ont lieu après l'ajout de votre première adresse sont envoyés : l'historique n'est pas renvoyé. Les messages contiennent l'e-mail et le nom des donateurs : seuls le responsable et les administrateurs de l'association peuvent gérer les webhooks, et le responsable est prévenu par e-mail à chaque adresse ajoutée ou modifiée.
Liste des événements
Chaque adresse reçoit les événements que vous avez cochés. La colonne « Contenu » indique les objets présents dans data, décrits dans la partie Objets.
Paiements
| Type | Envoyé quand… | Contenu |
|---|---|---|
payment.succeeded | Un paiement est confirmé : don ponctuel ou mensuel (premier paiement et chaque renouvellement), adhésion, billet, commande de boutique, QR code, cagnotte, Tap to Pay. | paymentattribution |
payment.failed | Une carte ou un prélèvement est refusé, par exemple le renouvellement d'un don mensuel. | paymentattribution |
payment.refunded | Un paiement est remboursé, en totalité ou en partie. Un message par remboursement. | paymentrefundattribution |
dispute.opened | Un donateur conteste un paiement auprès de sa banque. | paymentdisputeattribution |
dispute.closed | Le litige est clos, gagné ou perdu. | paymentdisputeattribution |
Dons mensuels
| Type | Envoyé quand… | Contenu |
|---|---|---|
subscription.created | Un donateur démarre un don mensuel. | subscriptionattribution |
subscription.past_due | Le prélèvement du mois n'est pas passé : le don mensuel attend son paiement. | subscriptionattribution |
subscription.reactivated | Un don mensuel impayé est de nouveau réglé. | subscriptionattribution |
subscription.canceled | Un don mensuel est arrêté. | subscriptionattribution |
Commandes (adhésions, billetterie, boutique)
| Type | Envoyé quand… | Contenu |
|---|---|---|
order.confirmed | Une adhésion, des billets ou un achat en boutique sont confirmés, y compris quand ils sont gratuits. | order |
order.pending_approval | Une demande d'adhésion attend votre validation. | order |
order.rejected | Vous avez refusé une demande d'adhésion. | order |
order.canceled | Une commande est annulée. | order |
order.expired | Une commande n'a pas été payée à temps et a expiré. | order |
order.fulfillment_updated | Une commande de la boutique change d'étape : en préparation, expédiée (avec le numéro de suivi), livrée ou retirée. | order |
Adhérents et billets
| Type | Envoyé quand… | Contenu |
|---|---|---|
membership.created | Une carte d'adhérent devient active. | membership |
membership.canceled | Une adhésion est annulée. | membership |
ticket.checked_in | Un billet est scanné à l'entrée de votre événement. | ticket |
ticket.canceled | Un billet est annulé. | ticket |
Demandes de remboursement
| Type | Envoyé quand… | Contenu |
|---|---|---|
refund_request.created | Un donateur ou un acheteur vous demande un remboursement. | refund_request |
refund_request.updated | Une demande de remboursement change d'état : répondue, remboursée ou refusée. | refund_request |
Reçus fiscaux
| Type | Envoyé quand… | Contenu |
|---|---|---|
fiscal_receipt.issued | Un reçu fiscal est émis pour un donateur. | fiscal_receipt |
fiscal_receipt.voided | Un reçu fiscal est annulé, par exemple après un remboursement. | fiscal_receipt |
Versements bancaires
| Type | Envoyé quand… | Contenu |
|---|---|---|
payout.paid | Stripe ou PayPal a viré de l'argent sur le compte bancaire de l'association. | payout |
payout.failed | Un virement vers le compte bancaire de l'association a échoué. | payout |
Formulaires et collectes
| Type | Envoyé quand… | Contenu |
|---|---|---|
form.created | Une cagnotte, un événement, une formule d'adhésion, une boutique, un lien de paiement ou un QR code est créé. | form |
campaign.goal_reached | Une cagnotte atteint son objectif. | campaign |
Compte de l'association
| Type | Envoyé quand… | Contenu |
|---|---|---|
organization.payment_account_updated | Le compte Stripe ou PayPal de l'association est activé ou suspendu. | payment_account |
Essai
| Type | Envoyé quand… | Contenu |
|---|---|---|
test.ping | Message d'essai envoyé depuis le tableau de bord. | message |
Une commande payée déclenche deux événements : order.confirmed (la commande) et payment.succeeded (l'argent). Pour mesurer vos conversions, utilisez payment.succeeded seul ; pour gérer vos inscrits, order.confirmed seul. Abonnez chaque adresse aux seuls événements dont elle a besoin.
Les messages partent en général moins de deux minutes après le fait : Donoor attend que toutes les informations soient définitives (montant versé, frais…) avant d'envoyer.
Structure d'un message
Chaque message est une requête POST dont le corps JSON, encodé en UTF-8, a toujours la même enveloppe. Seul le contenu de data change selon le type d'événement. Les noms des champs sont en anglais, comme chez Stripe ou HelloAsso.
| Champ | Type | Description |
|---|---|---|
id | string | Identifiant unique de l'événement (evt_…). Il reste le même à chaque relance et à chaque renvoi : c'est lui qui permet d'ignorer un doublon. |
object | string | Toujours event. |
type | string | Type de l'événement, par exemple payment.succeeded. |
api_version | string | Version du format du message. Elle ne change que pour une évolution incompatible. |
created | string (ISO 8601) | Date de création de l'événement, en UTC. |
livemode | boolean | true pour un vrai événement ; false pour une simulation ou dans l'environnement de test. Ne comptez jamais un message livemode false comme un vrai paiement. |
organization | object | L'association concernée : id (numéro Donoor) et name. |
data | object | Les objets propres à l'événement : payment, order, ticket… (voir Objets). |
Exemples de messages
{
"id": "evt_9mK2xQpL4vR8sT1w",
"object": "event",
"type": "payment.succeeded",
"api_version": "2026-10-17",
"created": "2026-10-17T14:02:11.000Z",
"livemode": true,
"organization": {
"id": 1234,
"name": "Les Amis du Quartier"
},
"data": {
"payment": {
"id": 32631,
"conversion_id": "32631",
"order_id": null,
"status": "succeeded",
"amount": 50.6,
"amount_cents": 5060,
"net_amount": 49.3,
"fees_covered_amount": 0.6,
"provider_fee_amount": 1.3,
"currency": "EUR",
"refunded_amount": 0,
"kind": "donation",
"channel": "online",
"form": null,
"recurring": {
"interval": "month",
"sequence": "first",
"subscription_id": 812
},
"payment_provider": "stripe",
"payment_method": "card",
"wallet": "apple_pay",
"provider_reference": "pi_3UQZvoFXPodLa3BZ2HKqlaEw",
"donor": {
"email": "amina.k@exemple.fr",
"name": "Amina K.",
"anonymous": false
},
"created": "2026-10-17T14:01:02.000Z"
},
"attribution": {
"parameters": {
"utm_source": "google",
"utm_medium": "cpc",
"utm_campaign": "ramadan-2027",
"gclid": "Cj0KCQjw8eTFBhCXARIsAIkiuOz"
},
"landing_page": "https://www.mon-association.org/faire-un-don",
"marketing_consent": true
}
}
}Objets
Les objets que l'on peut trouver dans data. Un champ sans valeur vaut null. Les dates sont au format ISO 8601, en UTC.
Tous les montants sont en euros, avec deux décimales ; les champs …_cents donnent le même montant en centimes. Les montants sont ceux de l'association : le soutien facultatif qu'un donateur laisse à Donoor n'y figure jamais.
idinteger | Identifiant Donoor du paiement. |
conversion_idstring | Identifiant de conversion, à transmettre à Google et Meta. Égal à id pour un don, au numéro de commande pour une adhésion, un billet ou un achat en boutique. C'est aussi le transaction_id poussé par le widget dans le dataLayer. |
order_idstring | null | Identifiant de la commande liée (adhésion, billetterie, boutique), sinon null. |
statusstring | succeeded, failed, refunded, partially_refunded ou disputed. |
amountnumber | Montant payé pour l'association, frais couverts par le donateur compris. C'est la valeur à envoyer comme conversion. |
amount_centsinteger | Le même montant, en centimes. |
net_amountnumber | null | Montant réellement versé à l'association par Stripe ou PayPal, après leurs frais. null tant que le prestataire ne l'a pas communiqué. |
fees_covered_amountnumber | Part des frais que le donateur a choisi de prendre en charge (0 sinon). |
provider_fee_amountnumber | null | Frais retenus par Stripe ou PayPal, tels qu'ils les indiquent. |
currencystring | Devise, code ISO 4217 en majuscules (EUR). |
refunded_amountnumber | Total déjà remboursé sur ce paiement. |
kindstring | Nature du paiement : donation, membership, ticket ou shop. |
channelstring | Canal : online (page de don, widget), campaign (cagnotte), qr_code, tap_to_pay ou offline (paiement saisi à la main). |
formobject | null | Le formulaire d'origine : type (campaign, event, membership_plan, shop, qr_code), id et title. null pour un don sur la page de don. |
recurringobject | null | Pour un don mensuel : interval, sequence (first pour le premier paiement, renewal ensuite) et subscription_id. null sinon. |
payment_providerstring | stripe, paypal ou manual. |
payment_methodstring | null | Moyen de paiement indiqué par le prestataire : card, sepa_debit, card_present (Tap to Pay), paypal… |
walletstring | null | apple_pay ou google_pay quand le donateur a payé avec, sinon null. |
provider_referencestring | null | Référence du paiement chez le prestataire (pi_… chez Stripe, numéro de commande PayPal). |
donorobject | Le donateur : email, name et anonymous (true s'il a demandé à rester anonyme sur la page publique ; vous recevez quand même ses coordonnées). |
createdstring (ISO 8601) | Date du paiement. |
En-têtes HTTP
Chaque requête porte ces en-têtes. Les noms d'en-têtes HTTP ne tiennent pas compte des majuscules : votre serveur peut les recevoir en minuscules.
| En-tête | Description |
|---|---|
Content-Typeapplication/json | Le corps est du JSON encodé en UTF-8. |
User-AgentDonoor-Webhooks/1.0 (+https://donoor.org/developpeurs/webhooks) | Identifie Donoor. Ne vous en servez pas pour authentifier : seule la signature fait foi. |
Donoor-Signaturet=1792300000,v1=f0f590ea41b7… | Horodatage et signature du message (voir Vérifier la signature). |
Donoor-Event-Idevt_9mK2xQpL4vR8sT1w | Identique au champ id du corps : pratique pour écarter un doublon avant même de lire le JSON. |
Donoor-Event-Typepayment.succeeded | Identique au champ type du corps. |
Donoor-Delivery-Attempt1 | Numéro de la tentative : 1 pour le premier envoi, jusqu'à 8. |
Vérifier la signature
N'importe qui peut envoyer une requête à votre adresse : vérifiez donc toujours la signature avant de faire confiance à un message. L'en-tête Donoor-Signature contient l'horodatage d'envoi (t, en secondes) et une ou deux signatures v1. Chaque signature est un HMAC-SHA256, écrit en hexadécimal, du texte « horodatage + point + corps brut », calculé avec votre secret.
Donoor-Signature: t=1792300000,v1=f0f590ea41b7f691921bb57c47f593d785d4e4d7d6c14f947848cb9d2d471bdf- 1
Lisez le corps BRUT de la requête, octet pour octet, avant tout décodage JSON.
- 2
Récupérez t et toutes les valeurs v1 de l'en-tête Donoor-Signature.
- 3
Calculez HMAC-SHA256 avec votre secret (whsec_ compris) sur t + « . » + corps, puis comparez le résultat à chaque v1 avec une comparaison à temps constant. Une seule doit correspondre.
- 4
Refusez le message si t a plus de 5 minutes d'écart avec votre horloge : un message intercepté ne peut pas être rejoué plus tard.
// Node.js (Express) — le corps BRUT est indispensable pour la signature
import crypto from "node:crypto";
import express from "express";
const SECRET = process.env.DONOOR_WEBHOOK_SECRET; // whsec_…
const app = express();
app.post("/webhooks/donoor", express.raw({ type: "application/json" }), (req, res) => {
const entete = req.get("Donoor-Signature") ?? "";
const t = /t=(\d+)/.exec(entete)?.[1];
const signatures = [...entete.matchAll(/v1=([0-9a-f]{64})/g)].map((m) => m[1]);
const attendue = crypto.createHmac("sha256", SECRET).update(`${t}.${req.body}`).digest("hex");
const valide = signatures.some((s) =>
crypto.timingSafeEqual(Buffer.from(s, "hex"), Buffer.from(attendue, "hex")));
const recent = t && Math.abs(Date.now() / 1000 - Number(t)) < 300;
if (!valide || !recent) return res.status(400).end();
const evenement = JSON.parse(req.body.toString("utf8"));
res.status(200).end(); // répondre vite, traiter ensuite
traiter(evenement); // traiter l'événement ; l'ignorer si son id a déjà été vu
});Exemple de vérification
Pour tester votre code sans attendre un vrai message : avec ces valeurs, vous devez obtenir exactement cette signature.
| Secret | whsec_5wQpK9mZ2vX7rT4yN8bH3jL6fD1sA0cE |
| Horodatage (t) | 1792300000 |
| Corps brut | {"id":"evt_doc0exemple0signature","object":"event","type":"test.ping"} |
| Signature v1 attendue | f0f590ea41b7f691921bb57c47f593d785d4e4d7d6c14f947848cb9d2d471bdf |
Erreur la plus fréquente : signer le JSON après l'avoir décodé puis ré-encodé. Le moindre espace ou l'ordre des clés change la signature. Signez toujours le corps exactement tel que reçu.
Changer de secret
Si votre secret a pu être vu par quelqu'un d'autre, remplacez-le : Paramètres › Webhooks › Secret › Changer le secret.
Pendant 24 heures, les messages sont signés avec l'ancien ET le nouveau secret : l'en-tête contient alors deux valeurs v1. Installez le nouveau secret sur votre serveur pendant ce délai ; ensuite, seul le nouveau fonctionne.
Le secret est conservé chiffré par Donoor. Il ne s'affiche qu'aux responsables et administrateurs de l'association.
Adresses acceptées
- Uniquement des adresses https, avec un certificat valide.
- Port 443 (celui par défaut) ou 8443.
- L'adresse doit être joignable depuis Internet : les adresses locales ou privées (localhost, réseau interne) sont refusées.
- Les redirections ne sont pas suivies : une réponse 3xx compte comme un échec. Indiquez l'adresse finale.
- Donoor n'envoie pas depuis une liste d'adresses IP fixe : ne filtrez pas par IP, vérifiez la signature.
Répondre à un message
Répondez par un code 2xx (200, 201, 204…) en moins de 10 secondes. Le contenu de votre réponse n'est pas lu, mais son début est affiché dans votre journal des envois pour vous aider à déboguer.
Répondez d'abord, traitez ensuite : enregistrez le message, répondez 200, puis faites les traitements longs (appel à Google Ads, envoi d'e-mail…) en arrière-plan.
| Réponse de votre serveur | Ce que fait Donoor |
|---|---|
| 2xx | Succès : le message est marqué réussi dans le journal. |
| 3xx | Échec (redirection non suivie) : nouvelle tentative plus tard. |
| 4xx, 5xx | Échec : nouvelle tentative plus tard. |
| pas de réponse | Plus de 10 secondes, connexion refusée ou certificat invalide : échec, nouvelle tentative plus tard. |
Relances et mise en pause
Quand un envoi échoue, Donoor réessaie automatiquement : 8 tentatives au total, sur environ 28 heures.
- 1er envoi
- +1 min
- +5 min
- +30 min
- +2 h
- +5 h
- +10 h
- +10 h
- Après la 8e tentative, le message est abandonné et l'association est prévenue par e-mail (au plus un e-mail par adresse et par jour).
- Une adresse qui n'accepte aucun message pendant 3 jours est mise en pause automatiquement, avec un e-mail. Elle se réactive d'un clic dans le tableau de bord.
- Tout message du journal peut être renvoyé à la main, pendant 30 jours : bouton Renvoyer.
Doublons et ordre
Un même événement peut arriver plus d'une fois : votre serveur a traité le message mais sa réponse s'est perdue, ou quelqu'un a cliqué sur Renvoyer. L'événement garde alors le même id : enregistrez les id déjà traités et ignorez ceux que vous connaissez.
L'ordre d'arrivée n'est pas garanti : un remboursement peut, en cas de relance, arriver avant le paiement d'origine. Fiez-vous au champ created et aux statuts des objets, pas à l'ordre de réception.
Pour une conversion publicitaire, conversion_id suffit : Google et Meta ignorent eux-mêmes une conversion déjà reçue avec le même identifiant.
Limites
| Adresses par association | 5 |
| Temps de réponse maximal | 10 secondes |
| Tentatives par message | 8, sur environ 28 h |
| Mise en pause automatique | après 3 jours sans succès |
| Messages d'essai | 20 par heure |
| Simulations | 60 par heure |
| Renvois manuels | 100 par heure |
| Messages par jour | 20 000 par association |
| Conservation du journal des envois | 30 jours |
| Conservation de la provenance | 400 jours |
Mesurer vos campagnes
Le message payment.succeeded vous donne le montant, la devise, l'identifiant de conversion et les paramètres de la publicité d'origine. Votre serveur transmet ensuite la conversion à la plateforme publicitaire : c'est fiable même quand le navigateur bloque les cookies ou les traceurs.
Google Analytics 4
Envoyez un événement purchase par le Measurement Protocol : transaction_id = conversion_id, value = amount, currency = currency.
Google Ads
Avec gclid (ou gbraid / wbraid) dans attribution.parameters : importez une conversion hors ligne par l'API Google Ads, avec order_id = conversion_id pour éviter les doublons. Les conversions améliorées peuvent utiliser l'e-mail du donateur, haché en SHA-256.
Meta (Facebook, Instagram)
Par l'API Conversions : event_name = Purchase, event_id = conversion_id, value et currency ; fbc se construit avec fbclid. L'e-mail du donateur s'envoie haché en SHA-256.
Sans développeur
Collez l'adresse d'un scénario Make ou Zapier (module « Webhook personnalisé ») : vous le reliez ensuite à Google Ads, GA4, Meta, Google Sheets ou à votre CRM, sans écrire de code.
Widget sur votre site
Quand le don se fait dans le widget Donoor intégré à votre site, la page reçoit aussi l'événement donoor_payment dans le dataLayer de Google Tag Manager, sans donnée personnelle, avec le même transaction_id que conversion_id : navigateur et serveur ne comptent qu'une conversion.
CRM et outils internes
Utilisez donor.email comme clé pour retrouver la fiche, kind pour savoir s'il s'agit d'un don, d'une adhésion, d'un billet ou d'un achat, et recurring pour repérer vos donateurs mensuels.
Exemple : un don transmis à GA4
POST https://www.google-analytics.com/mp/collect?measurement_id=G-XXXXXXX&api_secret=…
{
"client_id": "donoor.32631",
"events": [{
"name": "purchase",
"params": {
"transaction_id": "32631", // data.payment.conversion_id
"value": 50.6, // data.payment.amount
"currency": "EUR", // data.payment.currency
"campaign": "ramadan-2027" // data.attribution.parameters.utm_campaign
}
}]
}Provenance des paiements
Ajoutez vos paramètres de suivi au lien de vos annonces, qu'il mène vers votre page Donoor ou vers la page de votre site qui affiche le widget Donoor :
https://donoor.org/pay/mon-association?utm_source=google&utm_campaign=ramadan-2027&gclid=Cj0KCQjw…- Tous les paramètres du lien sont conservés jusqu'au paiement, même si le donateur ouvre la page de paiement dans un nouvel onglet.
- Ils arrivent dans data.attribution de payment.succeeded, et des autres événements du même paiement (remboursement, litige, don mensuel).
- Pour un renouvellement de don mensuel, la provenance est celle du premier paiement.
- Les paramètres qui ressemblent à une donnée sensible (e-mail, mot de passe, jeton, téléphone, IBAN…) et les paramètres techniques de Donoor sont écartés. Au plus 25 paramètres, 300 caractères par valeur.
- attribution vaut null quand le donateur n'est pas arrivé par un lien avec paramètres.
Consentement
attribution.marketing_consent indique si le donateur a accepté les cookies publicitaires sur Donoor : true, false, ou null si on ne sait pas.
En Europe, Google et Meta demandent de respecter ce choix (mode Consentement de Google, RGPD). Votre association reste responsable de l'usage qu'elle fait de ces données : n'envoyez pas l'e-mail d'un donateur qui a refusé, et pensez à mentionner ce traitement dans votre politique de confidentialité.
Essais, simulations et journal
Le bouton Envoyer un test, sur chaque adresse, envoie immédiatement un événement test.ping signé comme les autres. Il sert à vérifier que votre serveur est joignable et que votre signature est juste.
Le bouton Simuler un événement, sur chaque adresse, envoie l'un des 28 événements au choix, au format exact, avec des données fictives et livemode à false, uniquement à cette adresse. Un aperçu montre le message avant l'envoi. Aucun paiement n'est fait, aucune donnée réelle n'est envoyée.
Pour développer tranquillement, cochez Adresse de test dans la fenêtre de l'adresse : elle ne reçoit alors que les simulations et les messages d'essai, jamais les vrais événements. Branchez-y le serveur de développement de votre équipe, et gardez une autre adresse pour la production.
Le journal des envois montre chaque message des 30 derniers jours : événement, statut, nombre de tentatives, code HTTP et début de la réponse de votre serveur, et le contenu exact envoyé. Filtrez par réussis, en échec ou en attente, et renvoyez un message d'un clic.
Environnement de test
Le simulateur suffit pour développer vos webhooks. Pour tester aussi le parcours de paiement complet (page de don, carte de test, reçu), Donoor met à disposition un environnement de test séparé, sur sandbox.donoor.org. Ses pages ne sont pas référencées par les moteurs de recherche.
| Production | Test | |
|---|---|---|
| Site | donoor.org | sandbox.donoor.org |
| Tableau de bord | dashboard.donoor.org | dashboard-sandbox.donoor.org |
| Paiements | réels | fictifs, carte 4242 4242 4242 4242 |
| livemode | true | false |
| E-mails | normaux | objet préfixé « [TEST] » |
- Créez un compte d'association depuis sandbox.donoor.org (bouton Inscrire mon association) : aucune donnée réelle n'y figure.
- Connectez Stripe dans Paramètres › Processus de collecte. En mode test, Stripe accepte des informations fictives (code SMS : 000000) : aucun vrai compte bancaire n'est nécessaire.
- Votre page de paiement de test est aussitôt en ligne, par exemple sandbox.donoor.org/pay/votre-association, comme vos cagnottes, billetteries et boutiques de test.
- Ajoutez votre adresse de webhook dans Paramètres › Webhooks, comme en production.
- Faites un don sur cette page avec la carte de test 4242 4242 4242 4242 (date future, n'importe quel code) : vous recevez de vrais messages signés, avec livemode à false. Le secret de test est différent de celui de production.
Versions du format
Le champ api_version indique la version du format du message. Elle change seulement en cas d'évolution incompatible (un champ renommé ou supprimé, un sens modifié), annoncée à l'avance.
Donoor peut, sans changer de version, ajouter de nouveaux événements et de nouveaux champs : votre code doit ignorer ce qu'il ne connaît pas.
| Version | Changements |
|---|---|
| 2026-10-17 | Première version publique : 28 événements, signature HMAC-SHA256, provenance des paiements. |
Dépannage
Je ne reçois aucun message
Vérifiez dans le tableau de bord que l'adresse est Active et que l'événement attendu est coché, puis envoyez un message d'essai : le journal affiche alors la réponse de votre serveur ou l'erreur rencontrée (certificat, délai, adresse injoignable). Votre pare-feu doit accepter les requêtes entrantes depuis Internet.
La signature ne correspond jamais
Dans 9 cas sur 10, le corps a été décodé puis ré-encodé avant le calcul : utilisez le corps brut. Vérifiez aussi que vous utilisez le secret complet, préfixe whsec_ compris, et celui de la bonne adresse (chaque adresse a son propre secret). L'exemple de vérification ci-dessus permet de tester votre code.
Le journal indique une réponse 301 ou 302
Votre serveur redirige la requête (souvent de http vers https, ou vers une adresse avec ou sans barre finale). Les redirections ne sont pas suivies : indiquez l'adresse finale exacte.
Je reçois deux fois le même paiement
C'est normal en cas de relance ou de renvoi : l'événement a le même id, ignorez-le. Si les id sont différents, il s'agit de deux événements distincts, par exemple order.confirmed et payment.succeeded pour la même commande.
Je ne reçois pas les paiements d'avant l'ajout de mon adresse
C'est voulu : seuls les événements qui ont lieu après l'ajout de la première adresse sont envoyés. Pour l'historique, utilisez les exports du tableau de bord.
Le montant ne correspond pas à ce qu'a payé le donateur
amount est le montant pour l'association : le soutien facultatif laissé à Donoor n'y figure pas, les frais couverts par le donateur si. Ce qui arrive réellement sur votre compte bancaire est net_amount, après les frais de Stripe ou PayPal.
Une question ?
Notre équipe accompagne votre équipe technique pendant l'intégration.
Nous écrire