## Goal

Ensure Stripe events reach Beacon with cryptographic validation, deduplication, and safe replay.

## Recommended procedure

<Steps>
  <Step title="1) Define a stable endpoint">Use the canonical Beacon endpoint without redirects and with the correct `org` query parameter.</Step>
  <Step title="2) Store the signing secret">Keep the secret in your secrets manager, never in source code.</Step>
  <Step title="3) Validate required events">Confirm Stripe is sending the minimum checkout and subscription events Beacon expects.</Step>
  <Step title="4) Configure safe replay">Keep manual replay by `webhookEventId` and an audit trail per event.</Step>
</Steps>

<Tip title="Best practice">Add alerts for event backlog growth per organization and repeated signature failures.</Tip>

## Canonical endpoints by environment

- General `test`: `https://test.beacon.pt/api/webhooks/stripe?org=<organization_slug>&mode=test`
- General `live`: `https://app.beacon.pt/api/webhooks/stripe?org=<organization_slug>&mode=live`
- Dedicated billing endpoint: same convention on `/api/webhooks/stripe/billing`

## Minimal verification sample

<Tabs>
  <Tab label="curl">
    ```bash
curl -X POST "https://test.beacon.pt/api/webhooks/stripe?org=acme&mode=test" \
  -H "Content-Type: application/json" \
  -H "Stripe-Signature: t=1710492000,v1=<real_signature>" \
  -d '{"id":"evt_123","type":"checkout.session.completed"}'
```
  </Tab>
  <Tab label="node">
    ```ts
const signature = request.headers.get("stripe-signature");
const payload = await request.text();
const event = stripe.webhooks.constructEvent(payload, signature ?? "", process.env.STRIPE_WEBHOOK_SECRET!);
await processEvent(event);
```
  </Tab>
</Tabs>

## Definition of done

- Error rate under 1% per rolling 15-minute window.
- Event reprocessing available by `webhookEventId`.
- Logs correlate event, organization, and fiscal pipeline.
