Stripe webhook receiver (server-to-server)
POST/api/billing/webhook/stripe
Inbound Stripe webhook endpoint (Faz 3 Dilim B). Called by Stripe
server-to-server — NOT by the SPA. No session, no Sanctum, no tenant slug;
trust is established solely by verifying the Stripe-Signature HMAC against
the configured webhook signing secret. The tenant is resolved from the
verified event's metadata.tenant_id, and the local subscription's status /
period / Stripe ids are reconciled. Idempotent on the Stripe event id (a
retried delivery is a no-op).
Handled events: checkout.session.completed, payment_intent.succeeded,
payment_method.attached|updated|automatically_updated|detached,
customer.subscription.updated|deleted, invoice.paid,
invoice.payment_failed, and - for money going back - charge.refunded,
charge.dispute.created and charge.dispute.closed. A refunded or
disputed plan payment drops the workspace to Free; a refunded or disputed
wallet top-up is taken back from the wallet (never below zero). Every such
event is recorded in the platform billing event log.
This endpoint is documented for completeness; it is not part of the SPA's client surface and requires no authentication header.
Request
Responses
- 200
- 400
The event was received (processed, ignored, or a duplicate).
The signature could not be verified; the payload is rejected.