Documentation technique

Webhooks

Les webhooks envoient automatiquement à votre serveur un message signé à chaque événement de votre association sur Donoor : don reçu, remboursement, adhésion, billet scanné, commande, reçu fiscal, versement… Votre système est prévenu en quelques secondes, sans que personne n'ait à exporter quoi que ce soit.

api_version 2026-10-17HTTPS · JSON · HMAC-SHA25628 événements

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. 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. 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. 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. 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. 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.

Préférez une vidéo ?La formation Webhooks montre chaque étape en vidéo, du premier réglage au suivi 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

TypeEnvoyé quand…Contenu
payment.succeededUn 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.failedUne carte ou un prélèvement est refusé, par exemple le renouvellement d'un don mensuel.paymentattribution
payment.refundedUn paiement est remboursé, en totalité ou en partie. Un message par remboursement.paymentrefundattribution
dispute.openedUn donateur conteste un paiement auprès de sa banque.paymentdisputeattribution
dispute.closedLe litige est clos, gagné ou perdu.paymentdisputeattribution

Dons mensuels

TypeEnvoyé quand…Contenu
subscription.createdUn donateur démarre un don mensuel.subscriptionattribution
subscription.past_dueLe prélèvement du mois n'est pas passé : le don mensuel attend son paiement.subscriptionattribution
subscription.reactivatedUn don mensuel impayé est de nouveau réglé.subscriptionattribution
subscription.canceledUn don mensuel est arrêté.subscriptionattribution

Commandes (adhésions, billetterie, boutique)

TypeEnvoyé quand…Contenu
order.confirmedUne adhésion, des billets ou un achat en boutique sont confirmés, y compris quand ils sont gratuits.order
order.pending_approvalUne demande d'adhésion attend votre validation.order
order.rejectedVous avez refusé une demande d'adhésion.order
order.canceledUne commande est annulée.order
order.expiredUne commande n'a pas été payée à temps et a expiré.order
order.fulfillment_updatedUne 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

TypeEnvoyé quand…Contenu
membership.createdUne carte d'adhérent devient active.membership
membership.canceledUne adhésion est annulée.membership
ticket.checked_inUn billet est scanné à l'entrée de votre événement.ticket
ticket.canceledUn billet est annulé.ticket

Demandes de remboursement

TypeEnvoyé quand…Contenu
refund_request.createdUn donateur ou un acheteur vous demande un remboursement.refund_request
refund_request.updatedUne demande de remboursement change d'état : répondue, remboursée ou refusée.refund_request

Reçus fiscaux

TypeEnvoyé quand…Contenu
fiscal_receipt.issuedUn reçu fiscal est émis pour un donateur.fiscal_receipt
fiscal_receipt.voidedUn reçu fiscal est annulé, par exemple après un remboursement.fiscal_receipt

Versements bancaires

TypeEnvoyé quand…Contenu
payout.paidStripe ou PayPal a viré de l'argent sur le compte bancaire de l'association.payout
payout.failedUn virement vers le compte bancaire de l'association a échoué.payout

Formulaires et collectes

TypeEnvoyé quand…Contenu
form.createdUne cagnotte, un événement, une formule d'adhésion, une boutique, un lien de paiement ou un QR code est créé.form
campaign.goal_reachedUne cagnotte atteint son objectif.campaign

Compte de l'association

TypeEnvoyé quand…Contenu
organization.payment_account_updatedLe compte Stripe ou PayPal de l'association est activé ou suspendu.payment_account

Essai

TypeEnvoyé quand…Contenu
test.pingMessage 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.

ChampTypeDescription
idstringIdentifiant 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.
objectstringToujours event.
typestringType de l'événement, par exemple payment.succeeded.
api_versionstringVersion du format du message. Elle ne change que pour une évolution incompatible.
createdstring (ISO 8601)Date de création de l'événement, en UTC.
livemodebooleantrue 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.
organizationobjectL'association concernée : id (numéro Donoor) et name.
dataobjectLes 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.

idintegerIdentifiant Donoor du paiement.
conversion_idstringIdentifiant 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 | nullIdentifiant de la commande liée (adhésion, billetterie, boutique), sinon null.
statusstringsucceeded, failed, refunded, partially_refunded ou disputed.
amountnumberMontant payé pour l'association, frais couverts par le donateur compris. C'est la valeur à envoyer comme conversion.
amount_centsintegerLe même montant, en centimes.
net_amountnumber | nullMontant 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_amountnumberPart des frais que le donateur a choisi de prendre en charge (0 sinon).
provider_fee_amountnumber | nullFrais retenus par Stripe ou PayPal, tels qu'ils les indiquent.
currencystringDevise, code ISO 4217 en majuscules (EUR).
refunded_amountnumberTotal déjà remboursé sur ce paiement.
kindstringNature du paiement : donation, membership, ticket ou shop.
channelstringCanal : online (page de don, widget), campaign (cagnotte), qr_code, tap_to_pay ou offline (paiement saisi à la main).
formobject | nullLe formulaire d'origine : type (campaign, event, membership_plan, shop, qr_code), id et title. null pour un don sur la page de don.
recurringobject | nullPour un don mensuel : interval, sequence (first pour le premier paiement, renewal ensuite) et subscription_id. null sinon.
payment_providerstringstripe, paypal ou manual.
payment_methodstring | nullMoyen de paiement indiqué par le prestataire : card, sepa_debit, card_present (Tap to Pay), paypal…
walletstring | nullapple_pay ou google_pay quand le donateur a payé avec, sinon null.
provider_referencestring | nullRéférence du paiement chez le prestataire (pi_… chez Stripe, numéro de commande PayPal).
donorobjectLe 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êteDescription
Content-Typeapplication/jsonLe 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_9mK2xQpL4vR8sT1wIdentique au champ id du corps : pratique pour écarter un doublon avant même de lire le JSON.
Donoor-Event-Typepayment.succeededIdentique au champ type du corps.
Donoor-Delivery-Attempt1Numé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. 1

    Lisez le corps BRUT de la requête, octet pour octet, avant tout décodage JSON.

  2. 2

    Récupérez t et toutes les valeurs v1 de l'en-tête Donoor-Signature.

  3. 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. 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.

Secretwhsec_5wQpK9mZ2vX7rT4yN8bH3jL6fD1sA0cE
Horodatage (t)1792300000
Corps brut{"id":"evt_doc0exemple0signature","object":"event","type":"test.ping"}
Signature v1 attenduef0f590ea41b7f691921bb57c47f593d785d4e4d7d6c14f947848cb9d2d471bdf

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 serveurCe que fait Donoor
2xxSuccè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éponsePlus 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.

  1. 1er envoi
  2. +1 min
  3. +5 min
  4. +30 min
  5. +2 h
  6. +5 h
  7. +10 h
  8. +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 association5
Temps de réponse maximal10 secondes
Tentatives par message8, sur environ 28 h
Mise en pause automatiqueaprès 3 jours sans succès
Messages d'essai20 par heure
Simulations60 par heure
Renvois manuels100 par heure
Messages par jour20 000 par association
Conservation du journal des envois30 jours
Conservation de la provenance400 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.

ProductionTest
Sitedonoor.orgsandbox.donoor.org
Tableau de borddashboard.donoor.orgdashboard-sandbox.donoor.org
Paiementsréelsfictifs, carte 4242 4242 4242 4242
livemodetruefalse
E-mailsnormauxobjet préfixé « [TEST] »
  1. Créez un compte d'association depuis sandbox.donoor.org (bouton Inscrire mon association) : aucune donnée réelle n'y figure.
  2. 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.
  3. 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.
  4. Ajoutez votre adresse de webhook dans Paramètres › Webhooks, comme en production.
  5. 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.

VersionChangements
2026-10-17Premiè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