Webhook receiver
Billing
Webhook receiver
Stripe-to-Lavendly webhook ingest. Verifies signature, dedupes, credits the user.
POST
Webhook receiver
This endpoint is called by Stripe, not by your client. It receives
events for the user-account configured as What gets granted on
The session carries
STRIPE_WEBHOOK_SECRET.
Required Stripe configuration
In your Stripe dashboard → Developers → Webhooks, add:- Endpoint URL:
https://your-domain/api/v1/stripe/webhook - Events to send:
checkout.session.completedcustomer.subscription.deletedcustomer.subscription.pausedinvoice.payment_failed
- Copy the Signing secret into
STRIPE_WEBHOOK_SECRET.
What gets granted on checkout.session.completed
The session carries metadata.lavendly_kind and either
lavendly_plan (subscription) or lavendly_credits (pack). The
handler dispatches:
| Kind | Action |
|---|---|
subscription | setUserPlan(user_id, plan) |
credit_pack | topUpCredits(user_id, credits) |
Dedupe
Stripe delivers events at least once. We persist a marker per event id at/data/storage/_billing/_events/<event_id>.json; a re-delivery
returns { "received": true, "deduped": true } without re-running
the handler.
Errors
| Status | Meaning |
|---|---|
| 400 | Missing or invalid signature → Stripe stops retrying. |
| 200 | Processed (or deduped). |
| 500 | Handler crashed, Stripe will retry with exponential backoff. |
| 503 | STRIPE_SECRET_KEY not configured, Stripe will retry. |