## What each one is for

| Event | What it changes |
|---|---|
| `checkout.session.completed` | Activates the subscription after a successful checkout. |
| `invoice.payment_succeeded` | Renewal succeeded. Keeps an active row active. |
| `invoice.payment_failed` | Moves the account to past due rather than cutting access instantly. |
| `customer.subscription.updated` | Plan change, trial ending, status change from Stripe's side. |
| `customer.subscription.deleted` | Cancellation took effect. Access ends. |
| `charge.refunded` | You refunded someone. Worth reacting to rather than finding later. |
| `charge.dispute.created` | A chargeback. Has a deadline attached. |
| `radar.early_fraud_warning.created` | Stripe thinks a charge is fraudulent before the dispute. |

The handler for all of them is one controller, and the route is declared in `config/routes.rb` under
the webhooks namespace.

## Enable exactly these, not everything

Stripe's dashboard offers a select-all. Taking it sends hundreds of event types, most of which your
endpoint ignores. That is not harmless: a busy endpoint that returns 2xx to noise makes the delivery
log useless for debugging the five events you care about, and it costs you the signal when one of
them starts failing.

## Verify the endpoint is actually receiving

```bash
bin/rails runner 'puts Rails.application.routes.url_helpers.webhooks_stripe_path'
```

Then check Stripe's own delivery log in the dashboard. It shows the response code for every attempt,
which is the fastest way to tell a signature problem from a routing problem.

## Signature verification is not optional

The endpoint is unauthenticated by necessity, so the signature is the only thing distinguishing
Stripe from anyone who found the URL. `STRIPE_WEBHOOK_SECRET` is what verifies it, and a mismatched
secret returns 400 for every delivery.

## Entitlement is local, and that is the point

The webhook updates a `Subscription` row. Request-time entitlement checks read that row and never
call Stripe, so a delayed webhook delays activation by seconds, and a Stripe outage does not lock
out customers who already paid.
