coupon.redeemed
A subscriber's discounted payment settled and the redemption was recorded.
When this fires
A payment that carried a coupon settled. The reservation taken at checkout has been converted into a recorded redemption, and the money has actually moved.
This is the money event in the family. It is the only coupon.* event that carries amounts, and the only one that tells you the code was really used rather than merely offered.
It fires on settlement, not on apply. A subscriber typing a code into checkout does not emit anything. If they abandon the payment, the hold expires and no event ever fires, which is exactly why a
coupon.redeemedcan be trusted as revenue and a "code applied" signal could not.
This is the amount your reporting should use
final_amount is what the payment provider charged and what Subscriby's own transaction fee is calculated from. If you mirror revenue into a spreadsheet or a warehouse, use final_amount: not the plan's list price, and not original_amount.
Fires alongside payment.succeeded and subscription.activated for the same purchase. All three describe one checkout from three angles; only this one knows a discount was involved.
Caveats
- Only the first payment is discounted. Coupons are first-payment-only today, so a renewal on the same subscription charges list price and emits no coupon event. Do not carry
discount_amountforward into MRR. redemptions_countis read fresh, so it can jump. Under concurrent checkouts two events may report counts that are not consecutive. Treat it as a gauge, not a sequence number, and never derive ordering from it.- Amounts are decimal strings in the coupon redemption's currency, which is the plan's currency, not necessarily your dashboard's display currency. Convert before summing across plans.
- A redemption can arrive after the code was switched off, because a checkout already in flight is allowed to complete. This is expected, not a leak.
- Percentage and fixed discounts are both rounded to the currency's precision before charging, so
discount_amountis the rounded figure that actually moved, not a raw percentage oforiginal_amount.
Related events
coupon.exhausted: emitted immediately after this one when the redemption takes the last use.payment.succeeded: the payment itself.subscription.activated: the subscription it bought.
Header Parameters
t=<unix seconds>,v1=<hex>: the HMAC-SHA256 of "<t>.<raw body>" under the endpoint's secret. Verify it before acting, and refuse a t more than 300 seconds from now. During a secret rotation a v0= signature under the previous secret may precede v1=.
The event's ULID, bare. The envelope's id is the same ULID prefixed evt_, so strip the prefix before comparing. Deduplicate on it: a retry carries the same id.
The event name, the same as the envelope's type.
Always application/json.
Always Subscriby-Webhooks/1.0.
Request Body
application/json
The signed JSON envelope posted to your endpoint.
TypeScript Definitions
Use the request body type in TypeScript.
The envelope every event is delivered in.
Response Body
Example Requests
/coupon.redeemedHow is this guide?