Inbound Stripe event (server-to-server)
Stripe posts billing events to https://rrmacademy.org/api/stripe-webhook . The handler verifies the Stripe-Signature header (HMAC-SHA256 over the raw request body, prefixed with a timestamp, per https://docs.stripe.com/webhooks/signatures) before processing. Requests with a missing or invalid signature are rejected with 400. The handler is idempotent: replayed events with the same id short-circuit on a dedup KV record. Accepted event types: checkout.session.completed, checkout.session.expired, customer.subscription.updated, customer.subscription.deleted, invoice.payment_failed, charge.refunded. This is the only inbound webhook surface; rrmacademy.org does not currently emit outbound webhooks to consumers.
Headers
Stripe HMAC-SHA256 signature over the raw POST body. Format: t=<unix_ts>,v1=<hex_hmac>. Verified by stripe.webhooks.constructEventAsync using the rotating webhook signing secret. See https://docs.stripe.com/webhooks/signatures.
Payload
Example payload
{
"id": "evt_1NkFh82eZvKYlo2C0w6cVHaJ",
"type": "checkout.session.completed"
}Response
Event accepted (verified, dispatched to the matching handler, or idempotently skipped).
Changes
Webhooks have no change history: a webhook is keyed by its event name rather than a path and method, so no recorded change can name it.