# Stripe webhook endpoint rotation runbook

Owner-executed production procedure. This document makes no Stripe API calls and writes no secrets.

## Endpoints

- Current registered endpoint: `https://www.multideal.co.il/api/payments/stripe/webhook` — currently returns 404 because the application moved to `app.multideal.co.il`.
- Target endpoint: `https://app.multideal.co.il/api/payments/stripe/webhook`

## Strict execution order

Do not delete current endpoint until target delivery returns 2xx after production secret replacement.

1. Create a new endpoint in Stripe Dashboard, or create it through the Stripe API. API command:

   ```sh
   stripe webhook_endpoints create --url https://app.multideal.co.il/api/payments/stripe/webhook
   ```

   In Dashboard: Developers → Webhooks → Add endpoint; enter the target endpoint above and select the event types listed below. Ensure this is created as a separate endpoint; do not edit or delete the current endpoint yet.

2. Copy the new endpoint's signing secret from Stripe. Do not paste it into chat, shell history, source control, or logs.

3. From `apps/web`, replace the production Worker secret. Wrangler prompts for the secret; paste the value copied in step 2 only at that prompt:

   ```sh
   wrangler secret put STRIPE_WEBHOOK_SECRET --env production
   ```

4. From `apps/web`, start the production tail, then trigger one test delivery for the new Stripe endpoint in Stripe Dashboard:

   ```sh
   wrangler tail --env production
   ```

   Confirm the delivery returns HTTP 2xx and the tail shows successful webhook handling. Stop the tail only after this verification.

5. Delete the old endpoint in Stripe Dashboard, or use its endpoint ID in this API command:

   ```sh
   stripe webhook_endpoints delete OLD_ENDPOINT_ID
   ```

   Replace `OLD_ENDPOINT_ID` with the old endpoint's ID; never place a secret in the command.

## Silent-failure warning

Skipping step 3 leaves production verifying signatures with the old signing secret. Skipping step 4 can leave the new endpoint unverified or misconfigured. In either case, Stripe may show successful payments while the application never learns about them: purchases remain unfinalized, and downstream fulfillment, notifications, and balances do not run.

## Why the production-secret script cannot rotate this endpoint

`apps/web/scripts/put-production-secrets.mjs:112-113` returns `process.env.STRIPE_WEBHOOK_SECRET` immediately when it already contains a webhook signing secret. Otherwise, `:118-120` searches for the target URL and returns that endpoint's existing `secret` when present. It therefore reuses an existing secret instead of creating a new endpoint/secret for rotation. Its create branch (`:122-146`) is bootstrap behavior and does not delete the old endpoint or verify delivery. Run the ordered procedure above.

## Handler event types

The handler at `apps/web/src/pages/api/payments/stripe/webhook.ts` consumes:

- `payment_intent.succeeded` (`:154`)
- `payment_intent.payment_failed` (`:176`)
- `payment_intent.canceled` (`:204`)
- `payment_intent.amount_capturable_updated` (`:230`)
- `account.updated` (`:233`)
- `account.application.deauthorized` (`:291`)
- `charge.succeeded` (`:306`)
- `charge.dispute.created` (`:403`)
- `charge.dispute.closed` (`:428`)
- `charge.refunded` (`:523`)
- `payout.failed` (`:610`)
- `payout.paid` (`:622`)
- `transfer.failed` (handled by the default branch at `:625-633`)

## Second required rotation

Repeat this full rotation at the `www` launch flip, when the marketing site moves off `www` and the application takes `www`.

## Validation

- `typecheck skipped: no TypeScript-affecting change`.
- Deferred items: none.
