Playbooks

What Should a Payment Alert Include?

A great payment alert answers who paid, how much you actually keep, what it means for MRR, and what to do next. Here's the field-by-field anatomy — and why raw Stripe webhooks can't give you it.

The ChargeBell TeamUpdated July 6, 20269 min read

What a payment alert should include, at minimum, is five things: how much came in and how much you actually keep after fees, who paid (name and email, not an ID), what happened (the event type), what it means for MRR, and what to do next (a deep link plus an urgency cue). Miss any of those and you have a notification you still have to investigate. The catch is that a raw Stripe webhook physically can't give you most of them — the net amount and the customer's name live somewhere else.

Short answer

A great payment alert reads like a sentence a human wrote: $249.00 ($241.02 net after $7.98 fee) from Acme Corp — Pro plan, MRR +$249 — view in Stripe. A bad one is a wall of JSON with an amount in cents and a cus_… ID. The difference isn't formatting; it's real enrichment — fee math, ID-to-identity resolution, and MRR classification.

Good alert vs bad alert

Here is the same event two ways. First, a raw Stripe webhook forwarded straight to Slack. An engineer can decode it; a founder or ops teammate sees an integer in cents, a customer ID with no name, and no idea what the payment is worth after fees:

#stripe-raw
🧩
ChargeBellApp

🧩 payment_intent.succeeded

{ "amount": 24900, "currency": "usd", "status": "succeeded",

"customer": "cus_Qx9aB2c" }

Now the same payment as an alert a person can act on without opening a tab. Plain English, gross and net, a real customer, the plan, the MRR delta, and a link straight to the record:

#payments
🔔
ChargeBellApp

🔔 New payment — $249.00 from Acme Corp

Net after fees: $241.02 ($7.98 Stripe fee)

billing@acme.com · Pro plan, monthly · MRR +$249

View in Stripe →

The second one is not just prettier. To produce it you have to do work the raw payload doesn't do for you: compute the net, turn a customer ID into a name and email, classify the subscription movement, and attach a deep link. That's the whole anatomy of a good alert — so let's take it field by field.

The anatomy: what a payment alert should include, field by field

Every actionable payment alert answers five questions in order: how much, who, what, so what, and what next. Map each to a concrete field and you have a template that works for a sale, a failed charge, a refund, or a churn.

1. Amount — and net after fees

Gross alone is a vanity number. A raw charge.succeeded or payment_intent.succeeded event carries the gross amount, currency, and status — but not the processing fee or the net that actually lands in your balance. Stripe exposes those on a separate balance_transaction object, which you have to fetch or expand to read the fee and the net. There is no webhook for the balance transaction itself.

Why it matters: US card pricing is 2.9% + $0.30 per successful charge, so a $100 sale nets about $96.80 — a raw alert saying "$100.00" overstates real revenue by roughly 3.2%. And you can't just hardcode 2.9%: international cards add 1.5%, currency conversion adds another 1%, and ACH is 0.8% capped at $5. The fee varies per payment, so a correct alert reads the actual fee off the balance transaction rather than guessing.

Show both numbers

Always display gross and net ("$249.00 · $241.02 net after $7.98 fee"). Gross tells you the sale size; net tells you what you can spend. Founders reconcile against net, so that's the number that belongs in the alert.

2. Who — customer name and email, not an ID

The raw event gives you a bare customer ID like cus_Qx9aB2c — no name, no email. A cus_… string tells you nothing you can act on; you can't recognize a key account, spot a churned whale, or reply to support without resolving it first. A good alert has already done that lookup and shows the customer's name and email inline. This is basic to any Stripe payment notification in Slack worth reading.

3. What — the event type, in plain English

"Something happened in Stripe" is not an alert. The reader needs to know instantly whether this is a new sale, a failed charge, a refund, a dispute, or a cancellation — because each one routes to a different person and a different response. Lead with a labeled event type and an emoji marker so the category is legible at a glance, before anyone reads a single number.

4. So what — the MRR impact

For anything subscription-related, the single most useful field is the MRR delta. MRR moves four ways — new, expansion, contraction, and churn — and "subscription updated" tells you none of them. Worse, cancellations in Stripe usually surface as a generic customer.subscription.updated event (triggered when someone cancels in the customer portal), not a dedicated "churn" event, so a useful alert has to interpret the event to classify the movement.

A good subscription alert states the movement category and the delta: "Upgrade · MRR +$40" or "Canceled · MRR −$249." In practice, movement alerts include the customer, prior MRR, current MRR, the delta, and the category (new / expansion / contraction / churn). That's the difference between a number that scrolls past and one that makes someone open Slack. If subscriptions are your lifeblood, see how to monitor Stripe subscriptions in Slack.

An actionable notification lets the reader act from the message. That means a deep link to the exact Stripe record — the specific payment or customer, not the Dashboard home page — so investigating is one click, not a search. Pair it with an urgency cue: match the interruption to the stakes. A routine sale can be quiet; a failed payment or a dispute should look and route differently, because those need a human now. A failed charge that recovers on its own doesn't warrant the same volume as one that's about to churn a key account.

Urgency and routing cues: not every alert is equal

The best notification-UX guidance is simple: the higher the risk, the stronger the interruption. A quiet acknowledgment for routine events; a loud, prominent marker for high-value or destructive ones. In alerting terms, prioritize events that combine business impact with a defined response path, route by severity to the right people, and remember that not every alert needs to wake someone at 3 a.m. Low-urgency events belong in a digest, not a ping.

So a payment alert should also carry cues that answer "how much does this matter, and who owns it?" In practice that's three things: a severity marker (color or emoji), a routing target (which channel or person), and — for failures — a reason and next step. Here's a high-urgency example, deliberately built to look different from a routine sale:

#founders
⚠️
ChargeBellApp

⚠️ Payment failed — $1,200.00 from Globex Inc

Reason: insufficient_funds · Enterprise plan

MRR at risk: −$1,200 · Stripe retries in 3 days

ap@globex.com · Open customer →

This one earns a louder marker, a decline reason you can act on, an at-risk MRR figure, the retry timeline, and a link to the customer — and it's routed to founders, not the general wins channel. That's the anatomy of a failed-payment alert done right; the full playbook is in how to send failed payment alerts to Slack, and deciding who gets what is covered in which Stripe alerts go to finance, support, and founders.

Volume is a field too

One Slack ping per webhook is how a channel becomes noise nobody reads. Grouping related events and batching low-urgency ones into a digest is a core noise-reduction technique. An alert system's design includes deciding what *doesn't* fire in real time — see how to avoid noisy Stripe notifications.

Why raw webhooks can't do this on their own

It's worth being precise about the gap, because it explains why "just forward the webhook" never produces a good alert. A raw Stripe Event wraps everything in envelope fields (id, object, api_version, created, type) and nests the real data under data.object. Amounts are integers in the smallest currency unit — amount: 2000 means $20.00 — so unformatted JSON is unreadable to a non-engineer and easy to misread.

More fundamentally, three of the five fields a good alert needs are not in the payload at all:

  • Net after fees lives on a separate balance_transaction object you must expand or fetch — the charge webhook doesn't carry the fee or the net.
  • Customer name and email aren't in the event; you get a cus_… ID and have to resolve it against the customer record.
  • MRR movement type (new vs upgrade vs downgrade vs churn) has to be *derived* by interpreting the event, since Stripe surfaces most cancellations through a generic subscription.updated.

Stripe's own default Slack app and Stripe Workflows for Slack let you pick events, choose a channel, and optionally include a Dashboard link — which is genuinely useful and costs nothing. But users describe the out-of-the-box output as "mostly a direct transformation of data": it doesn't compute net-after-fees, doesn't resolve a bare customer ID into a name, doesn't classify MRR movement, and sends one ping per event with no grouping. Raw forwarders (Zapier, direct webhooks, Hookdeck) can pass any field, but they leave every bit of that enrichment to you. If you're weighing building it yourself, ChargeBell vs custom Stripe webhook code walks through exactly what that enrichment costs to maintain.

The full checklist

Use this as a spec whether you're building alerts yourself or evaluating a tool. A payment alert should include:

  • Amount, gross and net — formatted currency, with the actual fee read from the balance transaction (not a hardcoded percentage).
  • Customer identity — name and email resolved from the ID, so the reader recognizes the account.
  • Event type — a plain-English label and marker: new payment, failed, refund, dispute, new subscriber, cancellation, payout.
  • MRR impact — for subscription events, the delta and movement category (new / upgrade / downgrade / churn).
  • A deep link — straight to the exact Stripe payment or customer record.
  • An urgency + routing cue — a severity marker and the right channel, so failures and disputes stand out and reach the right people.
  • Sensible volume — batch low-urgency events into a digest instead of one ping per webhook.

How ChargeBell builds each alert

ChargeBell is a purpose-built Stripe-to-Slack alert product, and its alerts are the anatomy above, assembled for you. Each message is plain English with the numbers already computed: the net amount after Stripe fees, the customer name and email when Stripe provides them, and the MRR impact for subscription changes — not raw webhook JSON.

The urgency and routing cues are built in too. Payment failed and dispute created are treated as critical — they bypass quiet hours and can add an @channel prefix — while routine wins can go to a #wins channel and problems to #founders via per-alert routing. Quiet hours hold low-priority alerts and combine them into one "while you were away" message, and daily and weekly digests batch the small stuff so your channel stays signal, not noise. It connects through official read-only Stripe OAuth, so it can see payment events to build these alerts but can never move money or change anything.

Net

After-fees amount computed on every payment alert

Name + email

Customer identity resolved, not a raw ID

MRR Δ

Movement classified for subscription changes

Key takeaways

  • A payment alert should answer five things: amount + net after fees, who paid, what happened, the MRR impact, and what to do next.
  • Net-after-fees and the customer's name aren't in the raw webhook — net lives on a separate balance transaction, and you get a customer ID, not a name.
  • Classify MRR movement (new / upgrade / downgrade / churn); "subscription updated" isn't actionable, and most cancellations arrive as a generic update event.
  • Match urgency to stakes: failures and disputes get a louder marker and different routing than a routine sale; batch the rest into digests.
  • Raw forwarding and Stripe's default Slack app stop at a direct transformation of data — the enrichment is the work that makes an alert actionable.

Get payment alerts that read like this — in about two minutes

Connect Stripe and Slack, pick a channel, and send a test alert. Net after fees, real customer identity, MRR impact, and deep links, out of the box. Free plan, no card needed.

Start freeFree plan · no card needed

Frequently asked questions

What fields should a payment alert include?

At minimum: the amount and net after fees, the customer's name and email, the event type in plain English, the MRR impact for subscription changes, and a deep link to the exact Stripe record. Add an urgency cue so failures and disputes stand out from routine sales.

Why doesn't a raw Stripe webhook show the net amount after fees?

A charge or payment_intent webhook only carries the gross amount, currency, and status. Stripe puts the fee and net on a separate balance_transaction object, which you have to expand or fetch — there's no webhook for the balance transaction itself, so a raw forward can't show net.

Can I just assume Stripe's fee is 2.9% + $0.30?

No. That's the US card rate, but international cards add 1.5%, currency conversion adds another 1%, and ACH is 0.8% capped at $5. The fee varies per payment, so a correct alert reads the actual fee from the balance transaction rather than hardcoding a percentage.

Why does a payment alert need the customer's name if Stripe sends a customer ID?

The raw event gives you a bare ID like cus_Qx9aB2c with no name or email. You can't recognize a key account, spot a churn risk, or reply to support from an ID. A good alert resolves the ID into a name and email so the reader can act without a lookup.

How should urgency change what an alert looks like?

Match interruption to stakes: the higher the risk, the stronger the alert. A routine sale can be quiet, but a failed payment or dispute should carry a louder marker, a reason and next step, and route to the right people. Low-urgency events belong in a digest, not a real-time ping.

Does ChargeBell compute net-after-fees and MRR impact automatically?

Yes. ChargeBell's alerts are plain English with the numbers already worked out — net after Stripe fees, the customer's name and email when Stripe provides them, and the MRR delta for subscription changes. It connects through read-only Stripe OAuth, so it can build these alerts but never touches money.