Early bird discounts live! Claim your offer

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.redeemed can be trusted as revenue and a "code applied" signal could not.

Required ability

project-coupon:view — token must carry this at mint time to subscribe an endpoint to this event.

Payload

{
  "id": "evt_01HX...",
  "type": "coupon.redeemed",
  "created_at": "2026-11-28T14:07:52Z",
  "api_version": "2026-05-01",
  "project_id": "prj_01HX...",
  "data": {
    "coupon_id": "cpn_01HX...",
    "code": "BLACKFRIDAY",
    "subscription_id": "sub_01HX...",
    "subscriber_id": "usr_01HX...",
    "plan_id": "pln_01HX...",
    "original_amount": "40.0000",
    "discount_amount": "10.0000",
    "final_amount": "30.0000",
    "currency_id": "cur_01HX...",
    "redemptions_count": 137,
    "max_redemptions": 500
  }
}

Field reference

FieldTypeNotes
idstring ULIDUnique event id, prefixed evt_. Use for idempotent processing.
typestringAlways coupon.redeemed for this event.
created_atISO 8601 timestampServer-side emission time.
api_versionstringWebhook API contract version.
project_idstring ULIDProject the coupon belongs to.
data.coupon_idstring ULIDThe coupon that was redeemed.
data.codestringThe code as stored — uppercase.
data.subscription_idstring ULIDThe subscription the discounted payment bought.
data.subscriber_idstring ULIDThe subscriber. Resolve name and contact from the API — no payload carries them.
data.plan_idstring ULIDThe plan bought.
data.original_amountdecimal stringList price before the discount, in currency_id.
data.discount_amountdecimal stringWhat came off.
data.final_amountdecimal stringWhat was actually charged. original_amount − discount_amount.
data.currency_idstring ULIDCurrency all three amounts are in.
data.redemptions_countintegerTotal settled redemptions of this coupon, read fresh at emission.
data.max_redemptionsinteger | nullThe total cap. null means unlimited.

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.created 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_amount forward into MRR.
  • redemptions_count is 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_amount is the rounded figure that actually moved, not a raw percentage of original_amount.

How is this guide?

On this page

Subscriby is a product designed by you — for you.

No boardroom full of executives deciding what we ships next. Our roadmap always shaped by you with your feedback.

Share feedback or a request