How reversal and suspension affect runtime state
Refunds, disputes, and expired checkout attempts all change billing state, but they do not all mutate entitlement state in the same way. Licenzy keeps runtime state conservative so access is not over-granted after payment reversal or failed finalization.
- A full refund on
time_passcancels the entitlement and expires access immediately. - A full refund on
usage_packcancels the entitlement and setsusage_remainingto0. - Partial refunds are audit-only and do not mutate entitlement state by themselves.
- Subscription refund or dispute handling suspends entitlement state conservatively as
past_due. checkout.session.expiredmarks the unfinalized attempt failed and creates no entitlement.
Operational flows
Use these flows when you reason about how billing reversals show up in runtime behavior:
- Full refund on
time_passorusage_pack: Stripe refund -> entitlement mutation -> access revoked -> typicallyentitlement.updated. - Subscription dispute or refund: Stripe dispute/refund -> subscription-backed runtime state suspended conservatively as
past_due-> access denied -> typicallysubscription.updatedwhen runtime state changes. - Partial refund: Stripe partial refund -> no entitlement mutation -> no runtime access change. Do not assume a runtime outbound event if state did not change.
Where the broader lifecycle still lives
Stripe subscription and invoice lifecycle remains authoritative for renewal, recovery, and final cancellation. Licenzy consumes those billing signals and keeps the runtime layer conservative.
checkout.session.expired is also part of this boundary: it creates no entitlement, enables no new access, and may emit no outbound runtime event.
Use runtime state propagation for the full trigger-to-access matrix, and outbound webhook delivery contract when you need to reason about what your receiver should do after those state changes are emitted.