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:
- It reads the
stripe-signature header from the request.
- It calls
stripe.webhooks.constructEvent(rawBody, signature, webhookSecret) (or the mock equivalent in local mode).
- If verification fails, it returns
400 invalid_signature.
The endpoint fails closed when STRIPE_WEBHOOK_SECRET is unset, returning 503 billing_unavailable.
Events handled
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.