Überblick
Ein Webhook ist eine Internetadresse (eine URL), die Ihrer Organisation gehört: die Ihres Servers, Ihres CRM oder eines Tools wie Make oder Zapier. Sobald auf Donoor ein Ereignis eintritt, sendet Donoor an diese Adresse eine HTTPS-POST-Anfrage, die das Ereignis im JSON-Format beschreibt.
Jede Nachricht wird mit einem Secret signiert, das nur Sie kennen: So kann Ihr Server prüfen, dass sie wirklich von Donoor stammt und nicht verändert wurde. Antwortet Ihr Server nicht, versucht Donoor es automatisch rund 28 Stunden lang erneut.
Ein Ereignis tritt ein
Spende, Mitgliedschaft, Ticket…
Donoor sendet eine signierte Nachricht
POST · Donoor-Signature
Ihr Server
prüft, antwortet 200, verarbeitet
Werbung — jede Spende als Conversion an Google Ads, GA4 oder Meta übermitteln, zusammen mit der Ursprungskampagne.
CRM — den Datensatz des Spenders, Mitglieds oder Käufers anlegen oder aktualisieren.
Buchhaltung — Zahlungen, Erstattungen, Spendenquittungen und Bankauszahlungen erfassen.
Automatisierung — Ihr Team benachrichtigen, eine Tabelle befüllen, eine Willkommens-E-Mail auslösen.
Schnellstart
Rechnen Sie mit etwa fünfzehn Minuten, bis Sie Ihre erste Nachricht erhalten.
- 1
Bereiten Sie eine Empfangsadresse vor
Eine aus dem Internet erreichbare https-Adresse, auf Ihrem Server oder in einem Tool wie Make oder Zapier. Zum Ausprobieren ohne Installation genügt eine kostenlose Adresse von webhook.site.
- 2
Fügen Sie sie in Ihrem Dashboard hinzu
Einstellungen › Webhooks › Adresse hinzufügen. Geben Sie ihr eine Beschreibung und wählen Sie die Ereignisse aus, die Sie empfangen möchten (standardmäßig alle).
- 3
Kopieren Sie das Secret
Es beginnt mit whsec_. Bewahren Sie es in der Konfiguration Ihres Servers auf, niemals in einer Webseite oder einem öffentlichen Code-Repository.
- 4
Prüfen Sie die Signatur und antworten Sie mit 200
Ihr Server prüft den Header Donoor-Signature und antwortet dann innerhalb von 10 Sekunden mit einem 2xx-Code. Kopierfertiger Code in Node.js, PHP und Python steht weiter unten.
- 5
Senden Sie eine Testnachricht
Schaltfläche Test senden, oder Ereignis simulieren, um jedes der 28 Ereignisse mit fiktiven Daten zu erhalten. Prüfen Sie das Ergebnis anschließend im Zustellprotokoll.
Gesendet werden nur Ereignisse, die nach dem Hinzufügen Ihrer ersten Adresse eintreten: Frühere Ereignisse werden nicht nachgeliefert. Die Nachrichten enthalten die E-Mail-Adresse und den Namen der Spender: Nur der Verantwortliche und die Administratoren der Organisation können Webhooks verwalten, und der Verantwortliche wird bei jeder hinzugefügten oder geänderten Adresse per E-Mail benachrichtigt.
Liste der Ereignisse
Jede Adresse empfängt die Ereignisse, die Sie ausgewählt haben. Die Spalte „Inhalt“ gibt an, welche Objekte in data enthalten sind; sie werden im Abschnitt Objekte beschrieben.
Zahlungen
| Typ | Gesendet, wenn… | Inhalt |
|---|---|---|
payment.succeeded | Eine Zahlung wird bestätigt: einmalige oder monatliche Spende (erste Zahlung und jede Verlängerung), Mitgliedschaft, Ticket, Shop-Bestellung, QR-Code, Spendenaktion, Tap to Pay. | paymentattribution |
payment.failed | Eine Karte oder Lastschrift wird abgelehnt, zum Beispiel bei der Verlängerung einer monatlichen Spende. | paymentattribution |
payment.refunded | Eine Zahlung wird ganz oder teilweise erstattet. Eine Nachricht pro Erstattung. | paymentrefundattribution |
dispute.opened | Ein Spender widerspricht einer Zahlung bei seiner Bank. | paymentdisputeattribution |
dispute.closed | Die Zahlungsanfechtung ist abgeschlossen, gewonnen oder verloren. | paymentdisputeattribution |
Monatliche Spenden
| Typ | Gesendet, wenn… | Inhalt |
|---|---|---|
subscription.created | Ein Spender startet eine monatliche Spende. | subscriptionattribution |
subscription.past_due | Die Abbuchung dieses Monats ist fehlgeschlagen: Die monatliche Spende wartet auf Zahlung. | subscriptionattribution |
subscription.reactivated | Eine unbezahlte monatliche Spende ist wieder beglichen. | subscriptionattribution |
subscription.canceled | Eine monatliche Spende wird beendet. | subscriptionattribution |
Bestellungen (Mitgliedschaften, Ticketverkauf, Shop)
| Typ | Gesendet, wenn… | Inhalt |
|---|---|---|
order.confirmed | Eine Mitgliedschaft, Tickets oder ein Shop-Kauf sind bestätigt, auch wenn sie kostenlos sind. | order |
order.pending_approval | Ein Mitgliedsantrag wartet auf Ihre Freigabe. | order |
order.rejected | Sie haben einen Mitgliedsantrag abgelehnt. | order |
order.canceled | Eine Bestellung wird storniert. | order |
order.expired | Eine Bestellung wurde nicht rechtzeitig bezahlt und ist abgelaufen. | order |
order.fulfillment_updated | Eine Shop-Bestellung wechselt den Schritt: in Vorbereitung, versendet (mit Sendungsnummer), zugestellt oder abgeholt. | order |
Mitglieder und Tickets
| Typ | Gesendet, wenn… | Inhalt |
|---|---|---|
membership.created | Ein Mitgliedsausweis wird aktiv. | membership |
membership.canceled | Eine Mitgliedschaft wird storniert. | membership |
ticket.checked_in | Ein Ticket wird am Eingang Ihrer Veranstaltung gescannt. | ticket |
ticket.canceled | Ein Ticket wird storniert. | ticket |
Erstattungsanfragen
| Typ | Gesendet, wenn… | Inhalt |
|---|---|---|
refund_request.created | Ein Spender oder Käufer bittet Sie um eine Erstattung. | refund_request |
refund_request.updated | Eine Erstattungsanfrage ändert ihren Status: beantwortet, erstattet oder abgelehnt. | refund_request |
Spendenquittungen
| Typ | Gesendet, wenn… | Inhalt |
|---|---|---|
fiscal_receipt.issued | Für einen Spender wird eine Spendenquittung ausgestellt. | fiscal_receipt |
fiscal_receipt.voided | Eine Spendenquittung wird storniert, zum Beispiel nach einer Erstattung. | fiscal_receipt |
Bankauszahlungen
| Typ | Gesendet, wenn… | Inhalt |
|---|---|---|
payout.paid | Stripe oder PayPal hat Geld auf das Bankkonto der Organisation überwiesen. | payout |
payout.failed | Eine Überweisung auf das Bankkonto der Organisation ist fehlgeschlagen. | payout |
Formulare und Spendenaktionen
| Typ | Gesendet, wenn… | Inhalt |
|---|---|---|
form.created | Eine Spendenaktion, eine Veranstaltung, ein Mitgliedschaftstarif, ein Shop, ein Zahlungslink oder ein QR-Code wird erstellt. | form |
campaign.goal_reached | Eine Spendenaktion erreicht ihr Ziel. | campaign |
Konto der Organisation
| Typ | Gesendet, wenn… | Inhalt |
|---|---|---|
organization.payment_account_updated | Das Stripe- oder PayPal-Konto der Organisation wird aktiviert oder gesperrt. | payment_account |
Test
| Typ | Gesendet, wenn… | Inhalt |
|---|---|---|
test.ping | Testnachricht, vom Dashboard aus gesendet. | message |
Eine bezahlte Bestellung löst zwei Ereignisse aus: order.confirmed (die Bestellung) und payment.succeeded (das Geld). Um Ihre Conversions zu messen, verwenden Sie nur payment.succeeded; um Ihre Anmeldungen zu verwalten, nur order.confirmed. Abonnieren Sie für jede Adresse nur die Ereignisse, die sie benötigt.
Nachrichten werden in der Regel weniger als zwei Minuten nach dem Ereignis gesendet: Donoor wartet, bis alle Angaben endgültig sind (ausgezahlter Betrag, Gebühren…), bevor gesendet wird.
Aufbau einer Nachricht
Jede Nachricht ist eine POST-Anfrage, deren UTF-8-kodierter JSON-Inhalt immer dieselbe Hülle hat. Nur der Inhalt von data ändert sich je nach Ereignistyp. Die Feldnamen sind englisch, wie bei Stripe oder HelloAsso.
| Feld | Typ | Beschreibung |
|---|---|---|
id | string | Eindeutige Kennung des Ereignisses (evt_…). Sie bleibt bei jeder Wiederholung und jedem erneuten Senden gleich: Damit können Sie ein Duplikat ignorieren. |
object | string | Immer event. |
type | string | Typ des Ereignisses, zum Beispiel payment.succeeded. |
api_version | string | Version des Nachrichtenformats. Sie ändert sich nur bei einer inkompatiblen Änderung. |
created | string (ISO 8601) | Erstellungsdatum des Ereignisses, in UTC. |
livemode | boolean | true für ein echtes Ereignis; false für eine Simulation oder in der Testumgebung. Zählen Sie eine Nachricht mit livemode false niemals als echte Zahlung. |
organization | object | Die betroffene Organisation: id (Donoor-Nummer) und name. |
data | object | Die ereignisspezifischen Objekte: payment, order, ticket… (siehe Objekte). |
Beispielnachrichten
{
"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
}
}
}Objekte
Die Objekte, die in data vorkommen können. Ein Feld ohne Wert ist null. Datumsangaben sind im Format ISO 8601, in UTC.
Alle Beträge sind in Euro mit zwei Dezimalstellen angegeben; die Felder …_cents enthalten denselben Betrag in Cent. Die Beträge sind die der Organisation: Die freiwillige Unterstützung, die ein Spender Donoor gibt, ist nie enthalten.
idinteger | Donoor-Kennung der Zahlung. |
conversion_idstring | Conversion-Kennung, die an Google und Meta übermittelt wird. Entspricht id bei einer Spende und der Bestellnummer bei einer Mitgliedschaft, einem Ticket oder einem Shop-Kauf. Sie ist auch die transaction_id, die das Widget in den dataLayer schreibt. |
order_idstring | null | Kennung der zugehörigen Bestellung (Mitgliedschaft, Ticketverkauf, Shop), sonst null. |
statusstring | succeeded, failed, refunded, partially_refunded oder disputed. |
amountnumber | Für die Organisation gezahlter Betrag, einschließlich der vom Spender übernommenen Gebühren. Dies ist der Wert, der als Conversion gesendet wird. |
amount_centsinteger | Derselbe Betrag, in Cent. |
net_amountnumber | null | Betrag, den Stripe oder PayPal nach Abzug ihrer Gebühren tatsächlich an die Organisation auszahlen. null, solange der Anbieter ihn nicht mitgeteilt hat. |
fees_covered_amountnumber | Anteil der Gebühren, den der Spender übernehmen wollte (sonst 0). |
provider_fee_amountnumber | null | Von Stripe oder PayPal einbehaltene Gebühren, wie von ihnen angegeben. |
currencystring | Währung, ISO-4217-Code in Großbuchstaben (EUR). |
refunded_amountnumber | Bereits erstatteter Gesamtbetrag dieser Zahlung. |
kindstring | Art der Zahlung: donation, membership, ticket oder shop. |
channelstring | Kanal: online (Spendenseite, Widget), campaign (Spendenaktion), qr_code, tap_to_pay oder offline (manuell erfasste Zahlung). |
formobject | null | Das Ursprungsformular: type (campaign, event, membership_plan, shop, qr_code), id und title. null bei einer Spende über die Spendenseite. |
recurringobject | null | Bei einer monatlichen Spende: interval, sequence (first für die erste Zahlung, danach renewal) und subscription_id. Sonst null. |
payment_providerstring | stripe, paypal oder manual. |
payment_methodstring | null | Vom Anbieter angegebene Zahlungsmethode: card, sepa_debit, card_present (Tap to Pay), paypal… |
walletstring | null | apple_pay oder google_pay, wenn der Spender damit bezahlt hat, sonst null. |
provider_referencestring | null | Referenz der Zahlung beim Anbieter (pi_… bei Stripe, PayPal-Bestellnummer). |
donorobject | Der Spender: email, name und anonymous (true, wenn er auf der öffentlichen Seite anonym bleiben wollte; Sie erhalten seine Kontaktdaten trotzdem). |
createdstring (ISO 8601) | Datum der Zahlung. |
HTTP-Header
Jede Anfrage enthält diese Header. Bei HTTP-Headernamen wird die Groß- und Kleinschreibung nicht beachtet: Ihr Server kann sie in Kleinbuchstaben erhalten.
| Header | Beschreibung |
|---|---|
Content-Typeapplication/json | Der Inhalt ist UTF-8-kodiertes JSON. |
User-AgentDonoor-Webhooks/1.0 (+https://donoor.org/developpeurs/webhooks) | Identifiziert Donoor. Verwenden Sie ihn nicht zur Authentifizierung: Maßgeblich ist allein die Signatur. |
Donoor-Signaturet=1792300000,v1=f0f590ea41b7… | Zeitstempel und Signatur der Nachricht (siehe Signatur prüfen). |
Donoor-Event-Idevt_9mK2xQpL4vR8sT1w | Identisch mit dem Feld id des Inhalts: praktisch, um ein Duplikat schon vor dem Lesen des JSON zu verwerfen. |
Donoor-Event-Typepayment.succeeded | Identisch mit dem Feld type des Inhalts. |
Donoor-Delivery-Attempt1 | Nummer des Versuchs: 1 für die erste Zustellung, bis zu 8. |
Signatur prüfen
Jeder kann eine Anfrage an Ihre Adresse senden: Prüfen Sie daher immer die Signatur, bevor Sie einer Nachricht vertrauen. Der Header Donoor-Signature enthält den Zeitstempel des Versands (t, in Sekunden) und eine oder zwei v1-Signaturen. Jede Signatur ist ein hexadezimal kodierter HMAC-SHA256 des Textes „Zeitstempel + Punkt + roher Inhalt“, berechnet mit Ihrem Secret.
Donoor-Signature: t=1792300000,v1=f0f590ea41b7f691921bb57c47f593d785d4e4d7d6c14f947848cb9d2d471bdf- 1
Lesen Sie den ROHEN Inhalt der Anfrage Byte für Byte, vor jeder JSON-Dekodierung.
- 2
Lesen Sie t und alle v1-Werte aus dem Header Donoor-Signature aus.
- 3
Berechnen Sie HMAC-SHA256 mit Ihrem Secret (einschließlich whsec_) über t + „.“ + Inhalt und vergleichen Sie das Ergebnis mit jedem v1-Wert über einen zeitkonstanten Vergleich. Nur einer muss übereinstimmen.
- 4
Lehnen Sie die Nachricht ab, wenn t mehr als 5 Minuten von Ihrer Uhr abweicht: So kann eine abgefangene Nachricht später nicht erneut abgespielt werden.
// Node.js (Express) — der ROHE Inhalt ist für die Signatur unerlässlich
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(); // schnell antworten, danach verarbeiten
traiter(evenement); // Ereignis verarbeiten; ignorieren, wenn seine id bereits bekannt ist
});Prüfbeispiel
Um Ihren Code zu testen, ohne auf eine echte Nachricht zu warten: Mit diesen Werten müssen Sie genau diese Signatur erhalten.
| Secret | whsec_5wQpK9mZ2vX7rT4yN8bH3jL6fD1sA0cE |
| Zeitstempel (t) | 1792300000 |
| Roher Inhalt | {"id":"evt_doc0exemple0signature","object":"event","type":"test.ping"} |
| Erwartete v1-Signatur | f0f590ea41b7f691921bb57c47f593d785d4e4d7d6c14f947848cb9d2d471bdf |
Der häufigste Fehler: das JSON zu signieren, nachdem es dekodiert und erneut kodiert wurde. Schon ein Leerzeichen oder eine andere Reihenfolge der Schlüssel ändert die Signatur. Signieren Sie den Inhalt immer genau so, wie er empfangen wurde.
Secret ändern
Falls Ihr Secret von jemand anderem gesehen worden sein könnte, ersetzen Sie es: Einstellungen › Webhooks › Secret › Secret ändern.
24 Stunden lang werden die Nachrichten mit dem alten UND dem neuen Secret signiert: Der Header enthält dann zwei v1-Werte. Hinterlegen Sie das neue Secret in diesem Zeitraum auf Ihrem Server; danach funktioniert nur noch das neue.
Donoor speichert das Secret verschlüsselt. Es wird nur den Verantwortlichen und Administratoren der Organisation angezeigt.
Zulässige Adressen
- Nur https-Adressen mit gültigem Zertifikat.
- Port 443 (der Standard) oder 8443.
- Die Adresse muss aus dem Internet erreichbar sein: Lokale oder private Adressen (localhost, internes Netzwerk) werden abgelehnt.
- Weiterleitungen werden nicht verfolgt: Eine 3xx-Antwort gilt als Fehlschlag. Geben Sie die endgültige Adresse an.
- Donoor sendet nicht von einer festen Liste von IP-Adressen: Filtern Sie nicht nach IP, sondern prüfen Sie die Signatur.
Auf eine Nachricht antworten
Antworten Sie innerhalb von 10 Sekunden mit einem 2xx-Code (200, 201, 204…). Der Inhalt Ihrer Antwort wird nicht ausgewertet, aber ihr Anfang wird zur Fehlersuche in Ihrem Zustellungsprotokoll angezeigt.
Erst antworten, dann verarbeiten: Speichern Sie die Nachricht, antworten Sie mit 200 und führen Sie lange Verarbeitungen (Aufruf von Google Ads, E-Mail-Versand…) anschließend im Hintergrund aus.
| Antwort Ihres Servers | Was Donoor tut |
|---|---|
| 2xx | Erfolg: Die Nachricht wird im Protokoll als erfolgreich markiert. |
| 3xx | Fehlschlag (Weiterleitung nicht verfolgt): neuer Versuch später. |
| 4xx, 5xx | Fehlschlag: neuer Versuch später. |
| keine Antwort | Mehr als 10 Sekunden, Verbindung abgelehnt oder ungültiges Zertifikat: Fehlschlag, neuer Versuch später. |
Wiederholungen und Pausieren
Schlägt eine Zustellung fehl, versucht Donoor es automatisch erneut: insgesamt 8 Versuche über rund 28 Stunden.
- 1. Zustellung
- +1 min
- +5 min
- +30 min
- +2 h
- +5 h
- +10 h
- +10 h
- Nach dem 8. Versuch wird die Nachricht aufgegeben und die Organisation per E-Mail benachrichtigt (höchstens eine E-Mail pro Adresse und Tag).
- Eine Adresse, die 3 Tage lang keine Nachricht annimmt, wird automatisch pausiert, mit einer E-Mail. Sie lässt sich im Dashboard mit einem Klick wieder aktivieren.
- Jede Nachricht im Protokoll kann 30 Tage lang manuell erneut gesendet werden: Schaltfläche Erneut senden.
Duplikate und Reihenfolge
Dasselbe Ereignis kann mehr als einmal eintreffen: Ihr Server hat die Nachricht verarbeitet, aber seine Antwort ging verloren, oder jemand hat auf Erneut senden geklickt. Das Ereignis behält dann dieselbe id: Speichern Sie die bereits verarbeiteten id und ignorieren Sie die, die Sie schon kennen.
Die Reihenfolge des Eintreffens ist nicht garantiert: Bei einer Wiederholung kann eine Erstattung vor der ursprünglichen Zahlung eintreffen. Verlassen Sie sich auf das Feld created und den Status der Objekte, nicht auf die Reihenfolge des Empfangs.
Für eine Werbe-Conversion genügt conversion_id: Google und Meta ignorieren selbst eine Conversion, die bereits mit derselben Kennung empfangen wurde.
Limits
| Adressen pro Organisation | 5 |
| Maximale Antwortzeit | 10 Sekunden |
| Versuche pro Nachricht | 8, über rund 28 Std. |
| Automatisches Pausieren | nach 3 Tagen ohne Erfolg |
| Testnachrichten | 20 pro Stunde |
| Simulationen | 60 pro Stunde |
| Manuelles erneutes Senden | 100 pro Stunde |
| Nachrichten pro Tag | 20.000 pro Organisation |
| Aufbewahrung des Zustellungsprotokolls | 30 Tage |
| Aufbewahrung der Herkunftsdaten | 400 Tage |
Ihre Kampagnen messen
Die Nachricht payment.succeeded liefert Ihnen den Betrag, die Währung, die Conversion-Kennung und die Parameter der ursprünglichen Anzeige. Ihr Server gibt die Conversion anschließend an die Werbeplattform weiter: Das ist auch dann zuverlässig, wenn der Browser Cookies oder Tracker blockiert.
Google Analytics 4
Senden Sie ein purchase-Ereignis über das Measurement Protocol: transaction_id = conversion_id, value = amount, currency = currency.
Google Ads
Mit gclid (oder gbraid / wbraid) in attribution.parameters: Importieren Sie eine Offline-Conversion über die Google Ads API, mit order_id = conversion_id, um Duplikate zu vermeiden. Erweiterte Conversions können die mit SHA-256 gehashte E-Mail-Adresse des Spenders verwenden.
Meta (Facebook, Instagram)
Über die Conversions API: event_name = Purchase, event_id = conversion_id, value und currency; fbc wird aus fbclid gebildet. Die E-Mail-Adresse des Spenders wird mit SHA-256 gehasht gesendet.
Ohne Entwickler
Fügen Sie die Adresse eines Make- oder Zapier-Szenarios ein (Modul „Benutzerdefinierter Webhook“): Anschließend verbinden Sie es mit Google Ads, GA4, Meta, Google Sheets oder Ihrem CRM, ohne Code zu schreiben.
Widget auf Ihrer Website
Erfolgt die Spende im Donoor-Widget, das in Ihre Website eingebunden ist, erhält die Seite zusätzlich das Ereignis donoor_payment im dataLayer von Google Tag Manager, ohne personenbezogene Daten und mit derselben transaction_id wie conversion_id: Browser und Server zählen nur eine Conversion.
CRM und interne Tools
Verwenden Sie donor.email als Schlüssel, um den Datensatz zu finden, kind, um zu erkennen, ob es sich um eine Spende, eine Mitgliedschaft, ein Ticket oder einen Kauf handelt, und recurring, um Ihre monatlichen Spender zu erkennen.
Beispiel: eine an GA4 übermittelte Spende
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
}
}]
}Herkunft der Zahlungen
Fügen Sie Ihre Tracking-Parameter dem Link Ihrer Anzeigen hinzu, ob er auf Ihre Donoor-Seite oder auf die Seite Ihrer Website mit dem Donoor-Widget führt:
https://donoor.org/pay/mon-association?utm_source=google&utm_campaign=ramadan-2027&gclid=Cj0KCQjw…- Alle Parameter des Links bleiben bis zur Zahlung erhalten, auch wenn der Spender die Zahlungsseite in einem neuen Tab öffnet.
- Sie erscheinen in data.attribution von payment.succeeded sowie der übrigen Ereignisse derselben Zahlung (Erstattung, Zahlungsanfechtung, monatliche Spende).
- Bei der Verlängerung einer monatlichen Spende ist die Herkunft die der ersten Zahlung.
- Parameter, die wie sensible Daten aussehen (E-Mail-Adresse, Passwort, Token, Telefonnummer, IBAN…), sowie die technischen Parameter von Donoor werden verworfen. Höchstens 25 Parameter, 300 Zeichen pro Wert.
- attribution ist null, wenn der Spender nicht über einen Link mit Parametern gekommen ist.
Einwilligung
attribution.marketing_consent gibt an, ob der Spender Werbe-Cookies auf Donoor akzeptiert hat: true, false oder null, wenn unbekannt.
In Europa verlangen Google und Meta, diese Entscheidung zu respektieren (Google-Einwilligungsmodus, DSGVO). Ihre Organisation bleibt für die Verwendung dieser Daten verantwortlich: Senden Sie nicht die E-Mail-Adresse eines Spenders, der abgelehnt hat, und erwähnen Sie diese Verarbeitung in Ihrer Datenschutzerklärung.
Tests, Simulationen und Protokoll
Die Schaltfläche Test senden bei jeder Adresse sendet sofort ein Ereignis test.ping, das wie alle anderen signiert ist. Damit prüfen Sie, ob Ihr Server erreichbar und Ihre Signaturprüfung korrekt ist.
Die Schaltfläche Ereignis simulieren an jeder Adresse sendet ein beliebiges der 28 Ereignisse im exakten Format, mit fiktiven Daten und livemode auf false, nur an diese Adresse. Eine Vorschau zeigt die Nachricht vor dem Senden. Es findet keine Zahlung statt und es werden keine echten Daten gesendet.
Um in Ruhe zu entwickeln, aktivieren Sie im Fenster der Adresse die Option Testadresse: Sie empfängt dann nur Simulationen und Testnachrichten, niemals echte Ereignisse. Verbinden Sie den Entwicklungsserver Ihres Teams damit und behalten Sie eine andere Adresse für die Produktion.
Das Zustellungsprotokoll zeigt jede Nachricht der letzten 30 Tage: Ereignis, Status, Anzahl der Versuche, HTTP-Code und Anfang der Antwort Ihres Servers sowie den genauen gesendeten Inhalt. Filtern Sie nach erfolgreich, fehlgeschlagen oder ausstehend, und senden Sie eine Nachricht mit einem Klick erneut.
Testumgebung
Der Simulator genügt, um Ihre Webhooks zu entwickeln. Um auch den vollständigen Zahlungsablauf zu testen (Spendenseite, Testkarte, Beleg), stellt Donoor unter sandbox.donoor.org eine getrennte Testumgebung bereit. Ihre Seiten werden von Suchmaschinen nicht indexiert.
| Produktion | Test | |
|---|---|---|
| Website | donoor.org | sandbox.donoor.org |
| Dashboard | dashboard.donoor.org | dashboard-sandbox.donoor.org |
| Zahlungen | echt | fiktiv, Karte 4242 4242 4242 4242 |
| livemode | true | false |
| E-Mails | normal | Betreff mit dem Präfix „[TEST]“ |
- Erstellen Sie über sandbox.donoor.org ein Organisationskonto (Schaltfläche „Meine Organisation registrieren“): Es enthält keine echten Daten.
- Verbinden Sie Stripe unter Einstellungen › Spendenprozess. Im Testmodus akzeptiert Stripe fiktive Angaben (SMS-Code: 000000): Ein echtes Bankkonto ist nicht nötig.
- Ihre Test-Zahlungsseite ist sofort online, zum Beispiel sandbox.donoor.org/pay/ihre-organisation, ebenso Ihre Test-Spendenaktionen, -Ticketverkäufe und -Shops.
- Fügen Sie Ihre Webhook-Adresse unter Einstellungen › Webhooks hinzu, genau wie in der Produktion.
- Spenden Sie auf dieser Seite mit der Testkarte 4242 4242 4242 4242 (beliebiges zukünftiges Datum, beliebiger Code): Sie erhalten echte signierte Nachrichten mit livemode auf false. Das Test-Secret unterscheidet sich von dem der Produktion.
Formatversionen
Das Feld api_version gibt die Version des Nachrichtenformats an. Sie ändert sich nur bei einer inkompatiblen Änderung (ein umbenanntes oder entferntes Feld, eine geänderte Bedeutung), die im Voraus angekündigt wird.
Ohne die Version zu ändern, kann Donoor neue Ereignisse und neue Felder hinzufügen: Ihr Code muss alles ignorieren, was er nicht kennt.
| Version | Änderungen |
|---|---|
| 2026-10-17 | Erste öffentliche Version: 28 Ereignisse, HMAC-SHA256-Signatur, Herkunft der Zahlungen. |
Fehlerbehebung
Ich erhalte keine Nachrichten
Prüfen Sie im Dashboard, dass die Adresse Aktiv ist und das erwartete Ereignis ausgewählt ist, und senden Sie dann eine Testnachricht: Das Protokoll zeigt anschließend die Antwort Ihres Servers oder den aufgetretenen Fehler an (Zertifikat, Zeitüberschreitung, nicht erreichbare Adresse). Ihre Firewall muss eingehende Anfragen aus dem Internet zulassen.
Die Signatur stimmt nie überein
In 9 von 10 Fällen wurde der Inhalt vor der Berechnung dekodiert und erneut kodiert: Verwenden Sie den rohen Inhalt. Prüfen Sie außerdem, dass Sie das vollständige Secret verwenden, einschließlich des Präfixes whsec_, und zwar das der richtigen Adresse (jede Adresse hat ihr eigenes Secret). Mit dem Prüfbeispiel oben können Sie Ihren Code testen.
Das Protokoll zeigt eine Antwort 301 oder 302
Ihr Server leitet die Anfrage weiter (oft von http zu https oder zu einer Adresse mit oder ohne abschließenden Schrägstrich). Weiterleitungen werden nicht verfolgt: Geben Sie die genaue endgültige Adresse an.
Ich erhalte dieselbe Zahlung zweimal
Das ist bei einer Wiederholung oder einem erneuten Senden normal: Das Ereignis hat dieselbe id, ignorieren Sie es. Sind die id unterschiedlich, handelt es sich um zwei verschiedene Ereignisse, zum Beispiel order.confirmed und payment.succeeded für dieselbe Bestellung.
Ich erhalte keine Zahlungen aus der Zeit vor dem Hinzufügen meiner Adresse
Das ist so gewollt: Gesendet werden nur Ereignisse, die nach dem Hinzufügen der ersten Adresse eintreten. Für frühere Daten verwenden Sie die Exporte im Dashboard.
Der Betrag entspricht nicht dem, was der Spender gezahlt hat
amount ist der Betrag für die Organisation: Die freiwillige Unterstützung für Donoor ist nicht enthalten, die vom Spender übernommenen Gebühren dagegen schon. Was tatsächlich auf Ihrem Bankkonto ankommt, ist net_amount, nach Abzug der Gebühren von Stripe oder PayPal.
Eine Frage?
Unser Team unterstützt Ihr technisches Team während der Integration.
Schreiben Sie uns