Inhaltsverzeichnis
- Die Events, die eine Unterbrechung wirklich verdienen
- Was du brauchst
- Schritt 1 — Ein Kanal pro Event-Typ
- Schritt 2 — Stripe auf den Kanal richten
- Schritt 3 — Was tatsächlich ankommt
- Schritt 4 — Mit Bedingungen filtern, nicht mit Disziplin
- Schritt 5 — Halte den Alarmweg außerhalb dessen, was kaputtgeht
- Optional — Erst die Signatur prüfen
- Was dieser Aufbau nicht leistet
- Fehlersuche
- Häufige Fragen
- Kann Stripe mich anrufen, wenn ein Chargeback eröffnet wird?
- Muss ich Code schreiben, um Stripe mit Echobell zu verbinden?
- Ist es sicher, Stripe eine Drittanbieter-Webhook-URL zu geben?
- Warum zeigt mein Alarm 4900 statt 49,00 $?
- Wie verhindere ich, dass Testmodus-Events mich wecken?
- Kann mein Mitgründer dieselben Alarme ohne bezahlten Sitzplatz bekommen?
- Sollte ich auf erfolgreiche Zahlungen alarmieren?
- Fazit
- Verwandte Beiträge
Stripe weiß längst, wann ein Chargeback eröffnet wird, eine Abo-Zahlung scheitert oder eine Auszahlung zurückkommt. Es sagt dir per E-Mail Bescheid. Wenn du es lauter brauchst, registrierst du in Stripe einen zweiten Webhook-Endpunkt, der auf eine Echobell-Kanal-URL zeigt, abonnierst eine Handvoll Event-Typen und wählst den Benachrichtigungstyp passend zur Frist, die an jedem Event hängt. Bei Chargebacks und Early Fraud Warnings läuft eine Uhr; bei einer gescheiterten Verlängerung meistens nicht.
Dieser Leitfaden behandelt, welche Stripe-Events eine Unterbrechung verdienen, wie du Stripe in etwa fünf Minuten mit Echobell verbindest, welche Template-Felder auf welchem Objekt tatsächlich existieren — und welchen Kompromiss du eingehst, wenn du die Signaturprüfung überspringst.
Die Events, die eine Unterbrechung wirklich verdienen
Payment-Alerting geht fast immer auf dieselbe Weise schief: Jemand abonniert payment_intent.succeeded, weil es sich gut anfühlt, das Telefon vibriert vierzigmal am Tag, und sechs Wochen später scrollt eine Chargeback-Benachrichtigung ungelesen vorbei. Fang stattdessen bei der Frist an. Wenn es nichts kostet, das Event acht Stunden lang zu verpassen, muss es dich nicht in acht Sekunden erreichen.
| Event | Warum es zählt | Empfohlener Typ |
|---|---|---|
charge.dispute.created | Du hast ein begrenztes Zeitfenster zur Reaktion — meist 7 bis 21 Tage, je nach Kartennetzwerk. Verpasst du es, verlierst du automatisch. | Anruf |
radar.early_fraud_warning.created | Die kartenausgebende Bank hat Stripe gemeldet, dass eine Zahlung betrügerisch sein könnte. Eine Rückerstattung, bevor daraus ein förmliches Chargeback wird, ist die Handlung, die dir noch bleibt — und das Fenster ist kurz. | Anruf |
payout.failed | Geld, das Stripe eingezogen hat, erreicht deine Bank nicht. Alles Nachgelagerte — Gehälter, Runway-Rechnung — stimmt jetzt nicht mehr. | Anruf |
invoice.payment_failed | Unfreiwillige Abwanderung. Löst sich oft von selbst, ein Anruf ist übertrieben — aber die größten Accounts lohnen noch am selben Tag einen Blick. | Zeitkritisch |
customer.subscription.deleted | Freiwillige Abwanderung. Heute wissenswert, kein Grund aufzuwachen. | Normal |
payment_intent.succeeded | Nichts ist kaputt. Genau dieses Event trainiert dir an, die anderen fünf zu ignorieren. | Nichts |
Die Stufen entsprechen Echobells drei Benachrichtigungstypen: Normal ist ein gewöhnlicher Push, Zeitkritisch durchbricht die meisten Fokus-Modi, und Anruf erscheint als eingehender Anruf und klingelt damit durch „Nicht stören". Jeder Abonnent wählt pro Kanal seine eigene Stufe — die Mitgründerin nimmt Chargebacks als Anruf, der Support-Kollege dieselben als Push.
Was du brauchst
- Einen Stripe-Account mit Zugriff auf den Webhooks-Tab in Workbench
- Echobell installiert (App Store / Google Play)
- Fünf Minuten. Kein Server, kein Deploy, kein Code — es sei denn, du willst Signaturprüfung, und die steht im letzten Abschnitt.
Schritt 1 — Ein Kanal pro Event-Typ
Es ist verlockend, einen einzigen Kanal namens „Stripe" zu bauen und alles dorthin zu schicken. Tu es nicht. Body-Template und Dashboard-Link unterscheiden sich zwischen Chargeback, Rechnung und Auszahlung, weil jedes ein anderes Objekt transportiert — und der ganze Sinn des Aufbaus ist, dass die Benachrichtigung dir sagt, was passiert ist, ohne dass du irgendetwas öffnest.
Lege einen Kanal an, benannt nach dem Event: Stripe Disputes. Setze Titel- und Body-Template so, dass sie sich auf dem Sperrbildschirm sauber lesen:
Title: 🔴 Dispute opened — {{data.object.reason}}
Body: Amount: {{data.object.amount}} {{data.object.currency}}
Charge: {{data.object.charge}}
Status: {{data.object.status}}
Setze in den erweiterten Einstellungen das Link-Template, damit der Benachrichtigungseintrag die richtige Seite öffnet:
https://dashboard.stripe.com/disputes/{{data.object.id}}
Abonniere dich dann selbst mit Typ Anruf und kopiere die Webhook-URL aus der Kanalansicht. Sie sieht aus wie https://hook.echobell.one/t/<channel-token>.
Schritt 2 — Stripe auf den Kanal richten
Öffne im Stripe-Dashboard den Webhooks-Tab und lege ein Event-Ziel an:
Klicke auf Create an event destination, wähle Your account und belasse die API-Version auf dem Standard deines Accounts.
Wähle genau einen Event-Typ — für diesen Kanal charge.dispute.created. Stripe empfiehlt selbst, nur die Events zu abonnieren, die deine Integration braucht; hier hält es zusätzlich das Template ehrlich, weil jedes ankommende Payload dieselbe Form hat.
Wähle Webhook endpoint als Zieltyp und füge die Echobell-Kanal-URL ein.
Speichere, nutze dann Send test event — oder stripe trigger charge.dispute.created aus der CLI — und prüfe, ob dein Telefon klingelt.
Wiederhole das für jeden angelegten Kanal. Stripe erlaubt bis zu 16 Webhook-Endpunkte pro Account, mehr als genug für einen pro Alarmstufe.
Schritt 3 — Was tatsächlich ankommt
Stripe sendet das Event-Objekt als JSON. Echobell liest den Body unverändert, also ist jedes Feld in Templates und Bedingungen per Punktnotation erreichbar:
{
"id": "evt_1P...",
"type": "charge.dispute.created",
"livemode": true,
"created": 1757548800,
"data": {
"object": {
"id": "dp_1P...",
"amount": 4900,
"currency": "usd",
"reason": "fraudulent",
"status": "needs_response",
"charge": "ch_3P...",
"evidence_details": { "due_by": 1759449600 }
}
}
}
Drei Dinge an diesem Payload überraschen regelmäßig:
Beträge sind Ganzzahlen in der kleinsten Währungseinheit. Ein amount von 4900 sind 49,00 $. Echobell-Templates interpolieren und vergleichen Werte, rechnen aber nicht, also rendert {{data.object.amount}} als 4900. Beschrifte es entweder ehrlich (Amount: 4900 (cents)) oder teile im Forwarder aus dem letzten Abschnitt vor dem Senden durch 100.
Zeitstempel sind Unix-Sekunden. {{data.object.evidence_details.due_by}} rendert als 1759449600, nicht als Datum. Wenn die Frist an sich wichtiger ist als die genaue Stunde, lass sie aus dem Template — die Chargeback-Seite zeigt sie an — und lass das Link-Template die Arbeit machen.
Feldnamen unterscheiden sich je Objekt. Ein Chargeback hat amount; eine Rechnung hat amount_due, customer_email, attempt_count und hosted_invoice_url; eine Auszahlung hat failure_message und arrival_date; eine Early Fraud Warning hat fraud_type, actionable und charge als reine String-ID. Eine fehlende Variable rendert als leerer String statt als Fehler, also scheitert ein aus dem falschen Kanal kopiertes Template lautlos. Das ist der praktische Grund für einen Kanal pro Event-Typ.
Schritt 4 — Mit Bedingungen filtern, nicht mit Disziplin
Kanal-Bedingungen nutzen dieselbe Ausdruckssyntax wie Templates, nur ohne geschweifte Klammern, und laufen vor jeder Zustellung.
Die eine, die auf jeden Stripe-Kanal gehört:
livemode == true
Testmodus-Traffic — deine eigenen stripe trigger-Läufe, ein Kollege, der in einer Sandbox herumprobiert — erreicht dein Telefon nicht mehr. Füge sie hinzu, nachdem du die Verkabelung geprüft hast, nicht davor.
Für den Kanal mit fehlgeschlagenen Rechnungen hält ein Schwellenwert die kleinen Accounts aus deinem Feierabend heraus:
livemode == true && data.object.amount_due > 20000
Das liest sich als „über 200 $", in Cent. Und wenn du lieber die wirklich hängengebliebenen Wiederholungsversuche sehen willst statt jedes Erstversuchs:
livemode == true && data.object.attempt_count > 1
Falls du doch einen Endpunkt mit mehreren Event-Typen auf einen Kanal gelegt hast, trennen Bedingungen sie wieder auf:
type == "charge.dispute.created" || type == "payout.failed"
Schritt 5 — Halte den Alarmweg außerhalb dessen, was kaputtgeht
Das hier ist mehr wert als die Templates.
Dein produktiver Webhook-Endpunkt ist der Ort, an dem die Erfüllung passiert: Er schaltet Zugänge frei, schreibt in die Datenbank, verschickt die Rechnung. Er ist damit auch der Endpunkt, der ausfällt, wenn deine App ausfällt. Wenn das passiert, wiederholt Stripe bis zu drei Tage lang mit exponentiellem Backoff und schickt dir eine E-Mail — und eine E-Mail über unzustellbare Webhooks sieht genauso aus wie jede andere Stripe-Mail, weshalb sie am Montag gefunden wird.
Stiller Webhook-Tod hat banale Ursachen. Stripe wertet einen 3xx-Redirect als Fehler, also bekommt ein Endpunkt, der plötzlich http auf https umleitet oder einen Slash anhängt, keine Events mehr. Er verlangt TLS 1.2 oder höher, also genügt ein abgelaufenes oder falsch konfiguriertes Zertifikat. Ein 403 aus einer WAF-Regel, die letzte Woche jemand hinzugefügt hat, reicht ebenfalls.
Ein zweiter Endpunkt, der direkt auf Echobell zeigt, teilt nichts davon. Es ist eine andere URL auf einem anderen Host mit einem anderen Zertifikat, und sie klingelt weiter, während deine App liegt. Die Regel verallgemeinert sich: Der Weg, der dir sagt, dass etwas kaputt ist, sollte nicht durch das führen, was kaputt ist.
Der Ausfall deines eigenen Endpunkts soll trotzdem sichtbar sein. Schau in den Event deliveries-Tab in Workbench, wenn etwas komisch wirkt — er zeigt pro Event Delivered, Pending und Failed samt HTTP-Status jedes Versuchs. Stripe erlaubt das erneute Senden eines Events bis zu 15 Tage aus dem Dashboard oder 30 Tage mit stripe events resend aus der CLI; eine innerhalb von zwei Wochen entdeckte Lücke ist also reparierbar.
Stripe-Signature-Header prüft — eine geleakte URL ist also eine Fake-Alarm-Maschine, kein Datenleck. Halte sie aus Repositories und Screenshots heraus, nutze Reset Token, falls sie entwischt, und lies den nächsten Abschnitt, wenn dich der Kompromiss stört.Optional — Erst die Signatur prüfen
Wenn Stripes Signatur tatsächlich geprüft und Beträge wie Geld formatiert werden sollen, setze einen kleinen Forwarder davor. Dieser Cloudflare Worker verifiziert das Event, antwortet wie von Stripe gefordert sofort mit 200 und schickt Echobell ein flaches Payload:
import Stripe from "stripe";
export default {
async fetch(request, env, ctx) {
const stripe = new Stripe(env.STRIPE_SECRET_KEY);
const body = await request.text();
let event;
try {
event = await stripe.webhooks.constructEventAsync(
body,
request.headers.get("stripe-signature"),
env.STRIPE_WEBHOOK_SECRET,
);
} catch {
return new Response("invalid signature", { status: 400 });
}
const invoice = event.data.object;
ctx.waitUntil(
fetch(env.ECHOBELL_HOOK_URL, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
customer: invoice.customer_email || invoice.customer,
amount: (invoice.amount_due / 100).toFixed(2),
currency: invoice.currency.toUpperCase(),
attempt: invoice.attempt_count,
externalLink: invoice.hosted_invoice_url,
}),
}),
);
return new Response("ok", { status: 200 });
},
};
Das Template auf der anderen Seite wird deutlich schöner, weil das Formen im Code passiert ist:
Title: 💳 Payment failed — {{currency}} {{amount}}
Body: Customer: {{customer}}
Attempt #{{attempt}}
externalLink ist eine Spezialvariable: Ohne gesetztes Link-Template nutzt Echobell sie als Link des Benachrichtigungseintrags, sodass die gehostete Rechnungsseite einen Tipp entfernt ist.
Beachte die Form des Kompromisses: Das ist jetzt ein Stück Infrastruktur, das selbst ausfallen kann — genau wovor Schritt 5 warnt. Ein vernünftiger Mittelweg: Signaturen auf dem volumenstarken Kanal prüfen, wo falsche Alarme nerven würden, und den Chargeback-Kanal direkt verdrahtet lassen, wo ein Fehlklingeln einen verwirrten Blick kostet und ein verpasstes den strittigen Betrag.
Was dieser Aufbau nicht leistet
- Keine Rufbereitschaft, keine Eskalation. Alle Abonnenten eines Anruf-Kanals klingeln gleichzeitig. Bei vier Leuten ein Feature, bei vierzig ein Problem; bei vierzig willst du eine Incident-Plattform.
- Keine Deduplizierung. Stripe garantiert keine Event-Reihenfolge und kann dasselbe Event mehrfach zustellen. Zwei Klingeln für ein Chargeback sind möglich.
- Keine Quittierung. Nichts hält fest, dass ein Mensch es gesehen hat, und nichts eskaliert an eine zweite Person, wenn niemand reagiert.
- Kein „Zahlungen gestoppt"-Alarm. Stripe sendet Events, wenn etwas passiert, nie wenn etwas aufhört. Bricht dein Checkout, feuert überhaupt kein Event. Dafür braucht es einen Cronjob auf deiner Seite, der einen Kanal anpingt, wenn die letzte Stunde null Zahlungen hatte — ein cron-basierter Totmannschalter.
Fehlersuche
Das Testevent zeigt in Stripe 200, aber es kam keine Benachrichtigung. Echobell antwortet auch dann mit 200 und einem JSON-Body, wenn nichts zugestellt wird — sieh dir den Response-Body im Event-deliveries-Tab an. success: false bei korrekter Token-Länge heißt: falsches Kanal-Token. Ist success gleich true, liegt es meist an einer Bedingung: livemode == true blockiert jedes Testevent — so gewollt.
Stripe meldet 405 Method Not Allowed. Der Kanal hat POST Only an und etwas hat ein GET geschickt. Stripe selbst sendet immer POST, das war also eine Linkvorschau oder ein Browser-Tab, nicht Stripe.
Die Benachrichtigung kommt mit leeren Feldern an. Das Template adressiert das falsche Objekt — {{data.object.amount}} auf einem Rechnungskanal, wo das Feld amount_due heißt. Schick ein echtes Event, öffne es im Dashboard und lies das JSON.
Zustellungen scheitern, nachdem es wochenlang lief. Prüfe Zertifikat und jeden Redirect vor der URL. Bei direkt genutzter Kanal-URL ist das selten; bei einem selbst deployten Forwarder ist es der übliche Verdächtige.
Häufige Fragen
Kann Stripe mich anrufen, wenn ein Chargeback eröffnet wird?
Nicht von allein. Stripe benachrichtigt per E-Mail, im Dashboard, über das Event charge.dispute.created und per Push, falls du die Stripe-Dashboard-App nutzt. Für echtes Klingeln leitest du dieses Event an einen Kanal, dessen Abo-Typ Anruf ist.
Muss ich Code schreiben, um Stripe mit Echobell zu verbinden?
Nein. Stripe sendet JSON an jede öffentliche HTTPS-URL, und eine Echobell-Kanal-URL ist genau das. Code brauchst du nur, wenn der Stripe-Signature-Header geprüft oder Beträge umformatiert werden sollen.
Ist es sicher, Stripe eine Drittanbieter-Webhook-URL zu geben?
Es ist ein bewusster Kompromiss. Das Payload von Stripe enthält Kunden- und Zahlungs-Metadaten, und Echobell speichert rohe Webhook-Payloads nicht dauerhaft — die gerenderte Benachrichtigung liegt auf deinem Gerät. Was du aufgibst, ist die Signaturprüfung: Wer die URL kennt, kann dir eine überzeugende Fälschung schicken. Behandle sie wie einen API-Key und nutze das Forwarder-Muster für alles, was du geprüft haben willst.
Warum zeigt mein Alarm 4900 statt 49,00 $?
Stripe sendet Beträge als Ganzzahlen in der kleinsten Währungseinheit, und Echobell-Templates rechnen nicht. Beschrifte die Einheit im Template oder teile in einem Forwarder vor dem Senden durch 100.
Wie verhindere ich, dass Testmodus-Events mich wecken?
Füge dem Kanal die Bedingung livemode == true hinzu. Stripe markiert jedes Sandbox- und stripe trigger-Event als livemode: false.
Kann mein Mitgründer dieselben Alarme ohne bezahlten Sitzplatz bekommen?
Ja. Teile den Kanal-Link; jeder Abonnent wählt seinen eigenen Benachrichtigungstyp. Eine Person nimmt Chargebacks als Anruf, eine andere als normalen Push — und für Abonnenten fällt keine Pro-Sitz-Gebühr an.
Sollte ich auf erfolgreiche Zahlungen alarmieren?
Nur kurz, und nur solange das Geschäft klein genug ist, dass jede einzelne noch ein Ereignis ist. Sobald eine Erfolgsmeldung Routine wird, beginnt sie, deine Reaktion auf die wichtigen zu untergraben — der Kernmechanismus hinter Alert-Müdigkeit.
Fazit
Der gesamte Aufbau besteht aus einem Stripe-Event-Ziel pro Echobell-Kanal, einer Bedingung livemode == true und der Disziplin, die Anruf-Stufe Events mit laufender Uhr vorzubehalten. Chargebacks und Early Fraud Warnings haben eine. Eine gescheiterte Verlängerung im 9-$-Tarif nicht — und so zu tun als ob, ist genau der Weg, die eine mit Uhr zu verschlafen.
Echobell fürs iPhone laden oder bei Google Play holen, zuerst den Chargeback-Kanal anlegen und einmal stripe trigger charge.dispute.created feuern, bevor du dem Weg etwas Echtes anvertraust.