Spis treści
- Zdarzenia, które naprawdę zasługują na przerwanie
- Czego potrzebujesz
- Krok 1 — Jeden kanał na typ zdarzenia
- Krok 2 — Skieruj Stripe na kanał
- Krok 3 — Co faktycznie przychodzi
- Krok 4 — Filtruj warunkami, nie siłą woli
- Krok 5 — Trzymaj ścieżkę alertu poza tym, co się psuje
- Opcjonalnie — Najpierw zweryfikuj podpis
- Czego ta konfiguracja nie daje
- Rozwiązywanie problemów
- Najczęstsze pytania
- Czy Stripe może zadzwonić do mnie, gdy otworzy się spór?
- Czy muszę pisać kod, żeby połączyć Stripe z Echobell?
- Czy bezpiecznie jest dawać Stripe zewnętrzny adres webhooka?
- Dlaczego mój alert pokazuje 4900 zamiast 49,00 $?
- Jak sprawić, żeby zdarzenia z trybu testowego mnie nie budziły?
- Czy mój współzałożyciel może dostawać te same alerty bez opłaty za stanowisko?
- Czy powinienem alarmować o udanych płatnościach?
- Podsumowanie
- Powiązane
Stripe już wie, kiedy otwarto spór, kiedy nie przeszła płatność za subskrypcję i kiedy wypłata wróciła. Informuje cię o tym e-mailem. Jeśli chcesz czegoś głośniejszego, zarejestruj w Stripe drugi endpoint webhooka wskazujący na adres kanału Echobell, zasubskrybuj kilka typów zdarzeń i dobierz typ powiadomienia do terminu, który wisi nad każdym z nich. Przy sporach i wczesnych ostrzeżeniach o oszustwie zegar już tyka; przy nieudanym odnowieniu zwykle nie.
Ten przewodnik obejmuje: które zdarzenia Stripe zasługują na przerwanie ci dnia, jak w około pięć minut skierować Stripe do Echobell, które pola szablonów faktycznie istnieją na poszczególnych obiektach oraz jaki kompromis akceptujesz, pomijając weryfikację podpisu.
Zdarzenia, które naprawdę zasługują na przerwanie
Alerty o płatnościach psują się zawsze tak samo: ktoś subskrybuje payment_intent.succeeded, bo to miłe, telefon wibruje czterdzieści razy dziennie, a sześć tygodni później powiadomienie o sporze przelatuje nieprzeczytane. Zacznij od terminu. Jeśli przeoczenie zdarzenia przez osiem godzin nic nie kosztuje, nie musi ono docierać do ciebie w osiem sekund.
| Zdarzenie | Dlaczego jest ważne | Sugerowany typ |
|---|---|---|
charge.dispute.created | Masz ograniczone okno na odpowiedź — zwykle od 7 do 21 dni, zależnie od organizacji kartowej. Przegapisz — przegrywasz automatycznie. | Połączenie |
radar.early_fraud_warning.created | Wydawca karty zgłosił Stripe, że obciążenie może być oszustwem. Zwrot środków zanim stanie się to formalnym sporem to działanie, które wciąż masz, a okno jest krótkie. | Połączenie |
payout.failed | Pieniądze zebrane przez Stripe nie docierają do twojego banku. Wszystko dalej — wypłaty, wyliczenia finansowe — jest teraz błędne. | Połączenie |
invoice.payment_failed | Mimowolna rezygnacja. Dość często rozwiązuje się sama, więc telefon to przesada, ale największe konta warto sprawdzić tego samego dnia. | Pilne |
customer.subscription.deleted | Dobrowolna rezygnacja. Warto wiedzieć dziś, nie warto budzić się w nocy. | Zwykłe |
payment_intent.succeeded | Nic się nie zepsuło. To właśnie to zdarzenie uczy cię ignorować pozostałe pięć. | Nic |
Poziomy odpowiadają trzem typom powiadomień Echobell: Zwykłe to normalny push, Pilne przebija się przez większość trybów skupienia, a Połączenie pojawia się jako połączenie przychodzące, więc dzwoni mimo trybu Nie przeszkadzać. Każdy subskrybent wybiera własny poziom dla każdego kanału, więc współzałożycielka może odbierać spory jako telefon, a kolega z supportu te same zdarzenia jako push.
Czego potrzebujesz
- Konta Stripe z dostępem do zakładki Webhooks w Workbench
- Zainstalowanego Echobell (App Store / Google Play)
- Pięciu minut. Bez serwera, bez wdrożenia, bez kodu — chyba że chcesz weryfikację podpisu, o której jest ostatnia sekcja.
Krok 1 — Jeden kanał na typ zdarzenia
Kusi, żeby zrobić jeden kanał „Stripe" i wysyłać tam wszystko. Nie rób tego. Szablon treści i link do panelu różnią się dla sporu, faktury i wypłaty, bo każde niesie inny obiekt — a cały sens tej konfiguracji polega na tym, żeby powiadomienie samo mówiło, co się stało, bez otwierania czegokolwiek.
Utwórz kanał nazwany od zdarzenia: Stripe Disputes. Napisz szablony tytułu i treści tak, by dały się przeczytać na ekranie blokady:
Title: 🔴 Dispute opened — {{data.object.reason}}
Body: Amount: {{data.object.amount}} {{data.object.currency}}
Charge: {{data.object.charge}}
Status: {{data.object.status}}
W ustawieniach zaawansowanych ustaw szablon linku, żeby wpis powiadomienia otwierał właściwą stronę:
https://dashboard.stripe.com/disputes/{{data.object.id}}
Następnie zasubskrybuj się z typem Połączenie i skopiuj adres webhooka z widoku szczegółów kanału. Wygląda tak: https://hook.echobell.one/t/<channel-token>.
Krok 2 — Skieruj Stripe na kanał
W panelu Stripe otwórz zakładkę Webhooks i utwórz cel zdarzeń:
Kliknij Create an event destination, wybierz Your account i zostaw wersję API na domyślnej dla twojego konta.
Wybierz dokładnie jeden typ zdarzenia — dla tego kanału charge.dispute.created. Sam Stripe radzi, by subskrybować wyłącznie zdarzenia potrzebne twojej integracji; tutaj dodatkowo utrzymuje to szablon w ryzach, bo każdy przychodzący ładunek ma ten sam kształt.
Jako typ celu wybierz Webhook endpoint i wklej adres kanału Echobell.
Zapisz, a potem użyj Send test event — albo stripe trigger charge.dispute.created z CLI — i sprawdź, czy telefon dzwoni.
Powtórz dla każdego utworzonego kanału. Stripe pozwala na maksymalnie 16 endpointów webhooków na konto, czyli z nadmiarem na jeden na poziom alertu.
Krok 3 — Co faktycznie przychodzi
Stripe wysyła obiekt Event jako JSON. Echobell czyta treść bez zmian, więc każde pole jest dostępne w szablonach i warunkach przez notację kropkową:
{
"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 }
}
}
}
Trzy rzeczy w tym ładunku regularnie zaskakują:
Kwoty to liczby całkowite w najmniejszej jednostce waluty. amount równe 4900 to 49,00 $. Szablony Echobell wstawiają i porównują wartości, ale nie wykonują działań arytmetycznych, więc {{data.object.amount}} wyświetli 4900. Albo opisz jednostkę uczciwie (Amount: 4900 (cents)), albo użyj przekaźnika z ostatniej sekcji, żeby podzielić przez 100 przed wysłaniem.
Znaczniki czasu są w sekundach uniksowych. {{data.object.evidence_details.due_by}} wyświetli 1759449600, a nie datę. Jeśli ważniejsze jest istnienie terminu niż dokładna godzina, usuń to z szablonu — strona sporu i tak pokazuje termin — i niech pracuje szablon linku.
Nazwy pól różnią się między obiektami. Spór ma amount; faktura ma amount_due, customer_email, attempt_count i hosted_invoice_url; wypłata ma failure_message i arrival_date; wczesne ostrzeżenie o oszustwie ma fraud_type, actionable oraz charge jako zwykły identyfikator tekstowy. Brakująca zmienna renderuje się jako pusty ciąg, a nie błąd, więc szablon skopiowany z niewłaściwego kanału psuje się po cichu. To praktyczny powód zasady „jeden kanał na typ zdarzenia".
Krok 4 — Filtruj warunkami, nie siłą woli
Warunki kanału używają tej samej składni wyrażeń co szablony, tylko bez nawiasów klamrowych, i działają przed jakąkolwiek dostawą.
Ten, który powinien być na każdym kanale Stripe:
livemode == true
Ruch w trybie testowym — twoje własne stripe trigger, kolega grzebiący w piaskownicy — przestaje docierać do telefonu. Dodaj go po potwierdzeniu, że połączenie działa, a nie wcześniej.
W kanale nieudanych faktur próg trzyma małe konta z dala od twoich wieczorów:
livemode == true && data.object.amount_due > 20000
Czyta się to jako „powyżej 200 $", w centach. A jeśli wolisz widzieć ponowienia, które naprawdę utknęły, zamiast każdej pierwszej próby:
livemode == true && data.object.attempt_count > 1
Jeśli jednak skierowałeś jeden endpoint z kilkoma typami zdarzeń do jednego kanału, warunki rozdzielą je z powrotem:
type == "charge.dispute.created" || type == "payout.failed"
Krok 5 — Trzymaj ścieżkę alertu poza tym, co się psuje
To fragment wart więcej niż szablony.
Twój produkcyjny endpoint webhooka to miejsce, gdzie dzieje się realizacja: przyznaje dostęp, zapisuje do bazy, wysyła potwierdzenie. Jest więc również tym endpointem, który pada, gdy pada twoja aplikacja. Kiedy tak się stanie, Stripe ponawia próby nawet przez trzy dni z wykładniczym odczekiwaniem i wysyła ci e-mail — a e-mail o niedostarczonych webhookach wygląda identycznie jak każdy inny e-mail od Stripe, dlatego znajduje się go w poniedziałek.
Ciche umieranie webhooka ma nudne przyczyny. Stripe traktuje przekierowanie 3xx jako niepowodzenie, więc endpoint, który zaczyna przekierowywać http na https albo dokleja końcowy ukośnik, przestaje odbierać zdarzenia. Wymaga TLS 1.2 lub nowszego, więc wystarczy wygasły albo źle skonfigurowany certyfikat. 403 z reguły WAF, którą ktoś dodał w zeszłym tygodniu, też wystarczy.
Drugi endpoint wskazujący wprost na Echobell nie dzieli z tym niczego. To inny adres na innym hoście z innym certyfikatem — i dzwoni dalej, kiedy twoja aplikacja leży. Zasada uogólnia się: ścieżka, która mówi ci, że coś jest zepsute, nie powinna prowadzić przez to, co jest zepsute.
Awaria twojego własnego endpointu też ma być widoczna. Kiedy coś wydaje się nie tak, zajrzyj do zakładki Event deliveries w Workbench — pokazuje Delivered, Pending i Failed dla każdego zdarzenia wraz ze statusem HTTP każdej próby. Stripe pozwala wysłać zdarzenie ponownie do 15 dni z panelu albo do 30 dni poleceniem stripe events resend z CLI, więc lukę wychwyconą w ciągu dwóch tygodni da się załatać.
Stripe-Signature, więc wyciek adresu to maszyna do fałszywych alertów, a nie wyciek danych. Trzymaj go poza repozytoriami i zrzutami ekranu, użyj Reset Token, jeśli się wymknie, i przeczytaj następną sekcję, jeśli ten kompromis ci przeszkadza.Opcjonalnie — Najpierw zweryfikuj podpis
Jeśli chcesz, żeby podpis Stripe był naprawdę sprawdzany, a kwoty formatowane jak pieniądze, postaw z przodu mały przekaźnik. Ten Cloudflare Worker weryfikuje zdarzenie, natychmiast zwraca 200, jak wymaga Stripe, i wysyła do Echobell płaski ładunek:
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 });
},
};
Szablon po drugiej stronie robi się dużo przyjemniejszy, bo formowanie odbyło się w kodzie:
Title: 💳 Payment failed — {{currency}} {{amount}}
Body: Customer: {{customer}}
Attempt #{{attempt}}
externalLink to zmienna specjalna: bez ustawionego szablonu linku Echobell użyje jej jako linku wpisu powiadomienia, więc hostowana strona faktury jest jedno dotknięcie dalej.
Zwróć uwagę na kształt kompromisu: to teraz kawałek infrastruktury, który sam może paść — dokładnie to, przed czym ostrzega krok 5. Rozsądny środek to weryfikować podpisy na kanale o dużym wolumenie, gdzie fałszywe alerty byłyby uciążliwe, a kanał sporów zostawić podpięty bezpośrednio: tam koszt fałszywego dzwonka to jedno zdziwione spojrzenie, a koszt przegapionego — kwota sporu.
Czego ta konfiguracja nie daje
- Żadnych dyżurów ani eskalacji. Wszyscy subskrybenci kanału z połączeniem dzwonią jednocześnie. Przy czterech osobach to zaleta, przy czterdziestu problem; przy czterdziestu chcesz platformy do zarządzania incydentami.
- Brak deduplikacji. Stripe nie gwarantuje kolejności zdarzeń i może dostarczyć to samo zdarzenie więcej niż raz. Dwa dzwonki na jeden spór są możliwe.
- Brak potwierdzenia. Nic nie zapisuje, że człowiek to zobaczył, i nic nie eskaluje do drugiej osoby, jeśli nikt nie zareaguje.
- Brak alertu „płatności się zatrzymały". Stripe emituje zdarzenia, kiedy coś się dzieje, nigdy kiedy przestaje. Jeśli zepsuje się kasa, nie wystrzeli żadne zdarzenie. To wymaga zadania cyklicznego po twojej stronie, które pinguje kanał, gdy liczba obciążeń z ostatniej godziny wynosi zero — wyłącznika bezpieczeństwa opartego na cronie.
Rozwiązywanie problemów
Zdarzenie testowe pokazuje w Stripe 200, ale powiadomienie nie dotarło. Echobell odpowiada 200 z treścią JSON nawet wtedy, gdy nic nie dostarcza — sprawdź treść odpowiedzi w zakładce Event deliveries. success: false przy tokenie o poprawnej długości oznacza zły token kanału. Jeśli success to true, najbardziej prawdopodobną przyczyną jest warunek: livemode == true z założenia blokuje każde zdarzenie testowe.
Stripe zgłasza 405 Method Not Allowed. Kanał ma włączone POST Only, a coś wysłało GET. Sam Stripe zawsze wysyła POST, więc to podgląd linku albo karta przeglądarki, nie Stripe.
Powiadomienie przychodzi z pustymi polami. Szablon sięga po zły obiekt — {{data.object.amount}} na kanale faktur, gdzie pole nazywa się amount_due. Wyślij jedno prawdziwe zdarzenie, otwórz je w panelu i przeczytaj JSON.
Dostawy zaczynają zawodzić po tygodniach działania. Sprawdź certyfikat i wszelkie przekierowania przed adresem. Przy adresie kanału używanym bezpośrednio to rzadkość; przy przekaźniku, który sam wdrożyłeś, to zwykły podejrzany.
Najczęstsze pytania
Czy Stripe może zadzwonić do mnie, gdy otworzy się spór?
Sam z siebie nie. Stripe powiadamia e-mailem, w panelu, zdarzeniem charge.dispute.created oraz pushem, jeśli korzystasz z aplikacji Stripe Dashboard. Żeby telefon naprawdę zadzwonił, skieruj to zdarzenie na kanał, którego typ subskrypcji to Połączenie.
Czy muszę pisać kod, żeby połączyć Stripe z Echobell?
Nie. Stripe wysyła JSON na dowolny publiczny adres HTTPS, a adres kanału Echobell nim jest. Kod jest potrzebny tylko wtedy, gdy chcesz weryfikować nagłówek Stripe-Signature albo przeformatować kwoty.
Czy bezpiecznie jest dawać Stripe zewnętrzny adres webhooka?
To świadomy kompromis. Ładunek wysyłany przez Stripe zawiera metadane klienta i płatności, a Echobell nie przechowuje trwale surowych ładunków webhooków — wyrenderowane powiadomienie żyje na twoim urządzeniu. Rezygnujesz z weryfikacji podpisu: kto pozna adres, może wysłać ci przekonującą podróbkę. Traktuj go jak klucz API, a dla wszystkiego, co wolisz weryfikować, użyj wzorca z przekaźnikiem.
Dlaczego mój alert pokazuje 4900 zamiast 49,00 $?
Stripe wysyła kwoty jako liczby całkowite w najmniejszej jednostce waluty, a szablony Echobell nie liczą. Opisz jednostkę w szablonie albo podziel przez 100 w przekaźniku przed wysłaniem.
Jak sprawić, żeby zdarzenia z trybu testowego mnie nie budziły?
Dodaj do kanału warunek livemode == true. Stripe oznacza każde zdarzenie z piaskownicy i z stripe trigger jako livemode: false.
Czy mój współzałożyciel może dostawać te same alerty bez opłaty za stanowisko?
Tak. Udostępnij link do kanału; każdy subskrybent wybiera własny typ powiadomienia. Jedna osoba odbiera spory jako telefon, druga jako zwykły push, a za subskrybentów nie ma opłaty za stanowisko.
Czy powinienem alarmować o udanych płatnościach?
Tylko przez chwilę i tylko dopóki biznes jest na tyle mały, że każda z nich wciąż jest wydarzeniem. W chwili, gdy powiadomienie o udanej płatności staje się rutyną, zaczyna psuć twoją reakcję na te, które mają znaczenie — to podstawowy mechanizm stojący za zmęczeniem alertami.
Podsumowanie
Cała konfiguracja to jeden cel zdarzeń Stripe na kanał Echobell, warunek livemode == true i dyscyplina rezerwowania poziomu połączenia dla zdarzeń z tykającym zegarem. Spory i wczesne ostrzeżenia o oszustwie go mają. Nieudane odnowienie planu za 9 $ nie ma — a udawanie, że jest inaczej, to dokładnie sposób, w jaki przesypia się to jedno, które miało.
Pobierz Echobell na iPhone'a albo weź go z Google Play, utwórz najpierw kanał sporów i odpal raz stripe trigger charge.dispute.created, zanim powierzysz tej ścieżce cokolwiek prawdziwego.