subscription.cancelled
The subscription ended: because you cancelled it, because its paid period ran out, or after the last failed retry. `data.cancellation_reason` says which. Sent to your endpoint as a signed POST. Answer with any 2xx within 10 seconds; a delivery that fails is retried after 5 seconds, 5 minutes, 30 minutes, and 2, 5, 10 and 10 hours — eight attempts in all, spanning a little more than a day. Verify the signature before trusting the body.
The subscription ended: because you cancelled it, because its paid period ran out, or after the last failed retry. data.cancellation_reason says which.
Sent to your endpoint as a signed POST. Answer with any 2xx within 10 seconds; a delivery that fails is retried after 5 seconds, 5 minutes, 30 minutes, and 2, 5, 10 and 10 hours — eight attempts in all, spanning a little more than a day. Verify the signature before trusting the body.
Header Parameters
Unique per event; use it to ignore duplicates.
^evt_[0-9a-f]{32}$Unix seconds. Reject deliveries older than a few minutes.
v1, + base64 HMAC-SHA256 of {webhook-id}.{webhook-timestamp}.{raw body}, keyed with the base64-decoded part of your whsec_ secret.
Request Body
application/json
The event. Read the raw bytes before parsing them: the signature covers exactly what was sent.
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
Example Requests
/subscription.cancelledsubscription.active Webhook
A subscription started, after its first payment. Sent to your endpoint as a signed POST. Answer with any 2xx within 10 seconds; a delivery that fails is retried after 5 seconds, 5 minutes, 30 minutes, and 2, 5, 10 and 10 hours — eight attempts in all, spanning a little more than a day. Verify the signature before trusting the body.
subscription.on_hold Webhook
A renewal failed. When Utopia charges the renewals, it retries on the schedule in `next_retry_at` and emails the customer a payment link; when the card processor charges them, it retries on its own schedule and `next_retry_at` stays null. Sent to your endpoint as a signed POST. Answer with any 2xx within 10 seconds; a delivery that fails is retried after 5 seconds, 5 minutes, 30 minutes, and 2, 5, 10 and 10 hours — eight attempts in all, spanning a little more than a day. Verify the signature before trusting the body.