> ## Documentation Index
> Fetch the complete documentation index at: https://docs.noisemaker.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhooks

> Stripe webhook endpoint, signature verification, and event handling.

ai-cmo.dev currently exposes one inbound webhook, used by Stripe billing.

## Stripe webhook

`POST /api/v1/webhooks/stripe`

Public route. Stripe sends events to this endpoint after checkout sessions complete or expire.

### Signature verification

The server verifies the Stripe signature against `STRIPE_WEBHOOK_SECRET`:

1. It reads the `stripe-signature` header from the request.
2. It calls `stripe.webhooks.constructEvent(rawBody, signature, webhookSecret)` (or the mock equivalent in local mode).
3. If verification fails, it returns `400 invalid_signature`.

<Warning>
  The endpoint fails closed when `STRIPE_WEBHOOK_SECRET` is unset, returning `503 billing_unavailable`.
</Warning>

### Events handled

| Event type                   | Action                                                                       |
| ---------------------------- | ---------------------------------------------------------------------------- |
| `checkout.session.completed` | Fulfil the top-up: record the credit grant and mark the receipt as succeeded |
| `checkout.session.expired`   | Mark the receipt as failed                                                   |
| Any other type               | Ignored (`"ignored"` status)                                                 |

### Idempotency

Each checkout session is fulfilled at most once. The webhook handler checks the receipt status and the `credit_entries` unique constraint on `(workspace, idem_scope, idempotency_key)`. Replayed events never double-credit.

### Stripe verification in local mode

When `STRIPE_MOCK_SENTINEL=enabled`, the server uses a deterministic mock client that verifies signatures with HMAC-SHA256 over the raw body using `STRIPE_WEBHOOK_SECRET` as the key. This mirrors Stripe's verification closely enough that a tampered body or wrong secret fails identically to production.

### Rate limits

The billing checkout endpoint is rate-limited to 12 requests per 60 seconds per workspace.
