Skip to Content
ReferenceWebhooks

Webhooks

Unchurn receives inbound Stripe webhooks to reconcile subscription events with session outcomes. This page documents those inbound webhooks.


Scope

app/app/api/webhooks/stripe/ handles inbound Stripe webhooks — events Stripe sends to the Unchurn backend (not merchant-outbound webhooks delivered to the merchant’s server).

The webhook handler is internal to the Unchurn platform. Merchants do not configure this endpoint; it is wired during Stripe Connect onboarding.

Merchant-outbound webhooks (outcomes delivered to the merchant’s server) are referenced in the architecture overview but are not yet exposed as a configurable merchant surface. They will be documented here when the outbound webhook dispatcher is released.


Inbound Stripe webhook endpoints

PathModeDescription
/api/webhooks/stripe/liveliveReceives live-mode Stripe Connect events
/api/webhooks/stripe/testtestReceives test-mode Stripe Connect events
/api/webhooks/stripe/platformplatformReceives platform-level Stripe events

Signature verification

All inbound Stripe webhooks are verified using stripe.webhooks.constructEvent:

// app/app/api/webhooks/stripe/_shared/handler.ts const SIGNATURE_HEADER = 'stripe-signature'; event = verifier.webhooks.constructEvent(rawBody, signature, webhookSecretForMode(mode));
HeaderValue
stripe-signatureStripe-generated HMAC signature (also accepted as Stripe-Signature)

Secrets are environment-specific:

  • STRIPE_CONNECT_WEBHOOK_SECRET_LIVE — live mode
  • STRIPE_CONNECT_WEBHOOK_SECRET_TEST — test mode

Requests missing the stripe-signature header are rejected with HTTP 400. Invalid signatures are rejected with HTTP 400 { "error": "invalid_signature" }.


Mode enforcement

Every Stripe event carries a livemode boolean. The handler cross-checks this against the expected mode for the endpoint:

  • A live-mode event received at /api/webhooks/stripe/test is rejected with HTTP 400 { "error": "mode_mismatch" }
  • A test-mode event received at /api/webhooks/stripe/live is rejected with HTTP 400 { "error": "mode_mismatch" }

Response codes

StatusCondition
200 { "ok": true }Event handled successfully
400 { "error": "invalid_signature" }Stripe signature verification failed
400 { "error": "mode_mismatch" }Event livemode does not match the endpoint’s expected mode
400Missing stripe-signature header

Stripe interprets any non-2xx response as a delivery failure and retries.


Last updated on