---
title: "Stripe Payment Alerts: Get Called When Money Is at Risk"
description: "Route Stripe webhooks to your phone with the right urgency for each event — a quiet ping for a successful charge, a call for a dispute with a deadline attached."
date: 2026-09-09
author: Nooc
authorAvatarLink: /images/avatars/nooc.webp
authorLink: https://nooc.me
tags:
  - Stripe
  - payment alerts
  - webhook notifications
  - indie hackers
  - revenue monitoring
---

# Stripe Payment Alerts: Get Called When Money Is at Risk

Stripe emails you about everything and nothing. A successful charge, a failed subscription renewal and a chargeback all arrive as the same kind of message in the same inbox, and by the time you read them you have already lost the difference between them.

The fix is not more notifications. It is giving each Stripe event the urgency it actually deserves: a quiet push when someone pays, a time-sensitive alert when a renewal fails, and a phone call when a dispute lands with a response deadline attached.

## Which Stripe events actually need you

Not every event is worth a notification, and the ones that are worth it are not equally urgent.

| Stripe event | Why it matters | Urgency |
| --- | --- | --- |
| `payment_intent.succeeded` | Someone paid. Good to know, never urgent. | Normal |
| `invoice.payment_failed` | A renewal failed. You have a retry window before the subscription lapses. | Time-sensitive |
| `charge.dispute.created` | A chargeback. Stripe gives you a response deadline set by the card network, and missing it loses the case by default. | Calling |
| `payment_intent.payment_failed` | A one-off checkout failed. Useful in volume, noisy one at a time. | Normal, or skip |

The dispute is the one that justifies a phone call. Everything else can wait until you pick up your phone; a dispute you notice a week late is money you were never going to keep.

## Step 1 — Create a channel per urgency level

Create three channels in Echobell, because urgency is a per-channel setting:

- **Stripe · Revenue** — normal notifications, for successful payments
- **Stripe · Payment failed** — time-sensitive
- **Stripe · Dispute** — calling

Copy each channel's webhook URL from its settings. You will point Stripe at all three.

Turn on **POST Only** for each of them while you are there. Stripe always posts, and it stops link previews and address-bar autocompletion from firing your channel by accident.

## Step 2 — Add the endpoints in Stripe

In the Stripe Dashboard, go to **Developers → Webhooks → Add endpoint**, paste the channel URL, and select only the events that channel should handle.

Add one endpoint per channel rather than one endpoint for everything. Stripe lets you pick events per endpoint, which means the routing happens on Stripe's side and your channels stay simple.

If you prefer a single endpoint, point it at one channel and filter with a condition instead:

```
type == "charge.dispute.created"
```

Conditions are written without the `{{ }}` wrappers that templates use.

## Step 3 — Template the payload into something readable

Stripe posts a JSON body shaped like this:

```json
{
  "type": "charge.dispute.created",
  "data": {
    "object": {
      "amount": 4900,
      "currency": "usd",
      "reason": "fraudulent",
      "status": "warning_needs_response"
    }
  }
}
```

So the channel templates reach into `data.object`:

**Title**

```
Dispute: {{data.object.reason}}
```

**Body**

```
{{data.object.amount}} {{data.object.currency}} disputed
Status: {{data.object.status}}
```

**One gotcha that bites everyone:** Stripe amounts are in the smallest currency unit. `4900` is $49.00, not $4,900. Echobell templates substitute the value as-is, so either divide it before you send it, or write the currency after it and read it as cents. If the number matters at a glance, put the division in whatever sits between Stripe and Echobell — a Worker, a Zap, your own endpoint.

For the revenue channel, the same idea with fewer words:

**Title**

```
+{{data.object.amount}} {{data.object.currency}}
```

**Body**

```
{{data.object.description}}
```

## Step 4 — Test it without waiting for a real payment

The Stripe CLI can fire real event payloads at your endpoint:

```bash
stripe trigger payment_intent.succeeded
stripe trigger charge.dispute.created
```

Do this before you rely on it. It is also the fastest way to see what your template renders when a field you assumed would be there is `null`.

## What this setup does not give you

Two limits worth knowing before you put this in front of your revenue.

**Echobell does not verify Stripe's signature.** Stripe signs every webhook with a `Stripe-Signature` header, and verifying it requires the endpoint secret. Echobell's webhook endpoint does not do that check, so the channel URL is the only thing protecting the channel. Treat it as a secret, keep POST Only enabled, and do not paste it into a public repository or a screenshot.

You can add a weak sanity check with a condition:

```
header["stripe-signature"] != ""
```

That confirms something is sending a Stripe-shaped request. It does not confirm it was Stripe. If a forged notification would cause real harm — as opposed to a moment of confusion — put your own endpoint in front, verify the signature there, and have it call Echobell.

**This is an alerting path, not a ledger.** Stripe retries failed webhook deliveries, but notifications are not a record of what happened. Reconcile against Stripe, not against your notification history.

## Frequently asked questions

### Can Stripe call my phone directly?

No. Stripe sends email, and webhooks. A phone call means routing a webhook to something that can place one.

### Will a dispute alert actually wake me up?

If the channel is set to Calling, yes — it arrives as an incoming call and rings through Focus and Do Not Disturb. See [bypassing iOS Focus Mode for critical alerts](/en/blog/how-to-bypass-ios-focus-mode-for-critical-alerts).

### Can my co-founder get the same alerts?

Yes. Share the channel and each subscriber picks their own notification type. You can take the calls while someone else gets a quiet push for the same event.

### What about test mode?

Stripe test-mode events go to endpoints registered in test mode. Register your channel URL in both if you want to see test traffic, or in test mode only until you trust the setup.

## Wrap-up

Three channels, three endpoints, one template each. The point is not that you get notified about Stripe — you already were. It is that a chargeback stops looking exactly like a receipt.

[Download Echobell for iPhone](https://apps.apple.com/app/apple-store/id6743597198?pt=128151925&ct=blog-stripe-payment-alerts-en&mt=8) or [get it on Google Play](https://play.google.com/store/apps/details?id=one.echobell.echobellandroid), then run `stripe trigger charge.dispute.created` and let your phone ring once on purpose.

---

## Related

- [Webhook trigger documentation](/en/docs/webhook)
- [Template system reference](/en/docs/template)
- [Channel conditions reference](/en/docs/conditions)
- [Bypassing iOS Focus Mode for critical alerts](/en/blog/how-to-bypass-ios-focus-mode-for-critical-alerts)
- [A developer's guide to fixing alert fatigue](/en/blog/fix-alert-fatigue-developer-guide)
