Stripe webhook
const url = 'https://api.sloose.com/billing/webhook';const options = { method: 'POST', headers: {'Stripe-Signature': 'example', 'Content-Type': 'application/json'}, body: '{}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://api.sloose.com/billing/webhook \ --header 'Content-Type: application/json' \ --header 'Stripe-Signature: example' \ --data '{}'Stripe calls this; you should not. The signature is verified against STRIPE_WEBHOOK_SECRET over the raw request body, and each event is processed once, keyed on its event id, so a redelivery is harmless.
One delivery per organisation is handled at a time, and events are applied in the order Stripe made them, not the order they arrive in: Stripe does not deliver in order. Which invoice decides whether a payment is owed is asked of Stripe, since the order of events cannot say it.
A handler that fails answers 500, and an event whose organisation another delivery is still handling after a wait of a few seconds answers 503, both on purpose, so Stripe retries. Everything else is acknowledged.
Parameters
Section titled “Parameters”Header Parameters
Section titled “Header Parameters”Stripe’s signature over the raw body.
Stripe’s signature over the raw body.
Request Bodyrequired
Section titled “Request Bodyrequired”The raw Stripe event, signed with the Stripe-Signature header.
A Stripe event.
object
Examplegenerated
{}Responses
Section titled “Responses”Acknowledged.
Missing or invalid signature.
A handler failed. Answered deliberately so Stripe retries.
Another delivery for the same organisation is being handled, answered deliberately so Stripe retries; or no webhook secret is configured on this deployment. Or the restore switch is on (code: MAINTENANCE): every route but /health and /robots.txt is refused before anything is read, with Retry-After (the operator’s ADMIN_TOKEN alone is let through to POST /staff/people/{id}/delete, and to nothing else).
object
Example
{ "code": "MAINTENANCE"}Headers
Section titled “Headers”Seconds until asking again is worth it (300 while the switch is on).