subscription.* events
Every transition across the subscription statuses, plus upgrade / downgrade.
Every transition across the subscription statuses, plus upgrade / downgrade. The busiest event family. Subscribe to these to drive CRM timelines, revenue dashboards, churn-risk pipelines, and Slack alerts.
Background
Example payload
subscription.* payloads carry flat identifier fields, not nested subscription / plan / subscriber objects. Every event in the family includes subscription_id and subscriber_id. All of them except subscription.upgraded and subscription.downgraded also include plan_id; those two carry from_plan_id and to_plan_id instead. The remaining keys vary per event, so check the individual event.
{
"id": "evt_01HX...",
"type": "subscription.activated",
"created_at": "2026-05-18T10:05:00Z",
"api_version": "2026-05-01",
"project_id": "7f3d1c92-8b45-4e6a-9d21-5c8e0a4b6f13",
"data": {
"subscription_id": "5b7e2d40-1a86-4c39-97f2-e83d0b16c5a4",
"plan_id": "c4e82f16-93a7-4d5b-b81c-6e0f27a94d3b",
"subscriber_id": "2a91c4e7-6f38-4b52-8e0d-9c1a7b3f5d80",
"provider": "stripe"
}
}Plan pricing, subscriber identity, and period boundaries are not embedded. Resolve them with the subscription endpoint and the member endpoint.
Guarantees
- Every acquisition emits exactly one of
subscription.activated(paid) orsubscription.created(access code, cardless trial), never both. Subscribe to both and de-duplicate ondata.subscription_idto cover all acquisition paths. subscription.activatedfires at most once per subscription. Renewals emitsubscription.renewedinstead.- Out-of-order delivery is possible during retries. Use
SB-Event-Idto de-dupe andcreated_atto sequence.
Required abilities
Tokens subscribing to subscription.* events must carry project-subscription:view.
Events
subscription.createdNew subscription created via access-code redemption or cardless trial.subscription.activatedA paid subscription is acquired. Fires once, at first activation.subscription.trial_startedTrial-enabled plan starts free window.subscription.trial_convertingTrial about to convert. Fires 24h before `trial_ends_at`.subscription.trial_expiredTrial ended without conversion.subscription.renewedRecurring billing successfully charged the subscriber.subscription.reactivatedCancelled subscription re-activated before `ends_at`.subscription.pausedA member's access was suspended. Billing is unaffected and continues on schedule.subscription.unpausedPaused subscription resumes; resource invite links re-issued.subscription.past_dueBilling fails but grace period is active.subscription.unpaidBilling permanently failed; grace expired.subscription.cancelledCancellation recorded; access continues until `ends_at`.subscription.expired`ends_at` reached; access revoked.subscription.refundedRefund recorded against a subscription.subscription.upgradedSubscriber moved to a higher-priced plan.subscription.downgradedSubscriber moved to a lower-priced plan.subscription.created
WEBHOOKNew subscription created via access-code redemption or cardless trial.
When this fires
Exactly two paths emit this event:
- Access-code redemption: a subscriber redeems a code against a plan.
- Cardless trial start: a subscriber begins a trial that took no payment method.
Both are zero-payment acquisitions. Every paid acquisition (every payment provider, both recurring subscriptions and one-time passes) emits subscription.activated instead, and never emits subscription.created.
This event does not fire for paid checkouts. A card, wallet, or crypto purchase emits
subscription.activatedinstead. If you are building access control for a paying audience, subscribe to both.
The data keys differ by path. Absent keys are omitted entirely, not sent as null.
access_codecarries the complete code. It is already consumed and cannot be redeemed again, but treat it as you would any other customer identifier and avoid logging it into systems you do not control.
Caveats
- Do not treat this as the universal "a subscription exists" signal. For paid projects it never fires. The reliable pattern is to subscribe to both
subscription.createdandsubscription.activatedand de-duplicate ondata.subscription_id. - The access-code path also emits
access_code.redeemedand eithermember.joinedormember.trial_joinedfor the same subscription. - The cardless-trial path also emits
subscription.trial_startedandmember.trial_joined. - The
POST /v1/webhook-endpoints/{endpoint}/testendpoint sends a syntheticsubscription.createdpayload regardless of your project's payment configuration. A successful test does not prove this event will fire in production.
Related events
subscription.activated: the paid-checkout equivalent.access_code.redeemed: fires alongside on the access-code path.subscription.trial_started: fires alongside on the cardless-trial path.
Ability to subscribe
A token needs this to subscribe an endpoint to the event.
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.
Payload
JSONWhat Subscriby posts to your endpointapplication/json
The signed JSON envelope posted to your endpoint.
The envelope every event is delivered in.
Responses
2XXAny success status
Your endpoint acknowledged the delivery. Any 2xx status within 30 seconds marks it delivered; the response body is ignored.
defaultAny other status
Any other status, a connection failure, or no answer within 30 seconds counts as a failed attempt. The delivery is retried 8 times, after 10 seconds, 30 seconds, 2 minutes, 10 minutes, 1 hour, 6 hours, 1 day, 3 days; the last failure dead-letters it, and it can be retried from the dashboard or POST /v1/webhook-deliveries/{delivery}/retry. After 20 consecutive failures the endpoint is paused until it is resumed.
subscription.activated
WEBHOOKA paid subscription is acquired. Fires once, at first activation.
When this fires
On the first successful payment for a subscription, across every payment provider: Stripe, PayPal, Paystack, Razorpay, Skrill, CeyPay, and CoinPayments. It covers both recurring subscriptions and one-time (non-recurring) passes.
It fires once per subscription, at acquisition. It is not a general "became active" signal:
| Transition | Event actually emitted |
|---|---|
| First paid checkout | subscription.activated |
| Recurring renewal charge | subscription.renewed |
| Paused → resumed | subscription.unpaused |
Cancelled → reinstated before ends_at | subscription.reactivated |
| Past-due → collected | subscription.renewed |
| Trial → paying | member.converted |
| Access code / cardless trial | subscription.created |
A Stripe subscription that begins in a trial still emits subscription.activated at acquisition, because the provider creates the subscription at that moment. The later trial-to-paid transition emits member.converted only.
This is the paid-acquisition event. If you only subscribe to one subscription event for a paying audience, subscribe to this one, not
subscription.created, which never fires for paid checkouts.
data.provider is never access_code on this event; code redemptions emit subscription.created instead.
Caveats
- Once per subscription. Stripe and PayPal de-duplicate with a persistent guard key; the remaining providers emit only on the non-renewal branch of their payment handler. Renewals never re-emit it.
- To capture every acquisition path (paid, comped code, and cardless trial) subscribe to both
subscription.activatedandsubscription.created, then de-duplicate ondata.subscription_id. - Paid acquisitions do not emit
member.joined. That event is access-code-only. Usesubscription.activatedas the paid-audience join signal. payment.succeededfires for the same charge and carries the amount, currency, and external payment id, which this event does not.- The
POST /v1/webhook-endpoints/{endpoint}/testendpoint sends a syntheticsubscription.createdpayload, neversubscription.activated. Testing an endpoint does not exercise this event.
Related events
subscription.created: the zero-payment acquisition equivalent.payment.succeeded: the charge behind this activation.subscription.renewed: every subsequent cycle.member.converted: trial-to-paying transition.
Ability to subscribe
A token needs this to subscribe an endpoint to the event.
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.
Payload
JSONWhat Subscriby posts to your endpointapplication/json
The signed JSON envelope posted to your endpoint.
The envelope every event is delivered in.
Responses
2XXAny success status
Your endpoint acknowledged the delivery. Any 2xx status within 30 seconds marks it delivered; the response body is ignored.
defaultAny other status
Any other status, a connection failure, or no answer within 30 seconds counts as a failed attempt. The delivery is retried 8 times, after 10 seconds, 30 seconds, 2 minutes, 10 minutes, 1 hour, 6 hours, 1 day, 3 days; the last failure dead-letters it, and it can be retried from the dashboard or POST /v1/webhook-deliveries/{delivery}/retry. After 20 consecutive failures the endpoint is paused until it is resumed.
subscription.trial_started
WEBHOOKTrial-enabled plan starts free window.
When this fires
A subscriber starts a trial on a trial-enabled plan. Three paths emit it: a cardless trial, an access-code redemption against a trial plan, or a Stripe checkout that begins in a trial window.
Trial checkouts through the other providers (PayPal, Paystack, Razorpay, Skrill, CeyPay, CoinPayments) do not currently emit this event; only Stripe reports the trialing status transition back to Subscriby.
Pairs with
member.trial_joined: both fire together when a subscriber starts a trial on the cardless-trial and access-code paths.
The data keys differ by path. Absent keys are omitted entirely, not sent as null.
Caveats
- On the cardless-trial and access-code paths this is paired with
subscription.createdandmember.trial_joinedfor the samesubscription_id. On the Stripe path it is paired withsubscription.activatedinstead, and nomember.*join event fires. - Plans with
trial_days = 0skip this event entirely.
Related events
subscription.trial_converting: fires 24h beforetrial_ends_at.subscription.trial_expired: fires if no conversion occurs.
Ability to subscribe
A token needs this to subscribe an endpoint to the event.
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.
Payload
JSONWhat Subscriby posts to your endpointapplication/json
The signed JSON envelope posted to your endpoint.
The envelope every event is delivered in.
Responses
2XXAny success status
Your endpoint acknowledged the delivery. Any 2xx status within 30 seconds marks it delivered; the response body is ignored.
defaultAny other status
Any other status, a connection failure, or no answer within 30 seconds counts as a failed attempt. The delivery is retried 8 times, after 10 seconds, 30 seconds, 2 minutes, 10 minutes, 1 hour, 6 hours, 1 day, 3 days; the last failure dead-letters it, and it can be retried from the dashboard or POST /v1/webhook-deliveries/{delivery}/retry. After 20 consecutive failures the endpoint is paused until it is resumed.
Trial about to convert. Fires 24h before `trial_ends_at`.
When this fires
Fires 24 hours before trial_ends_at to give consumers a window to send conversion-reminder messaging. Emitted once per trial, by the hourly trial-conversion notifier.
Fires exactly once per trial, 24 hours before
trial_ends_at.
Caveats
- Idempotency is enforced server-side: each trial receives this event at most once.
- If
trial_ends_atis moved closer than 24h after the trial has already started, the notice may not fire.
Related events
subscription.trial_started: predecessor.subscription.activated,member.converted: fire on successful conversion.subscription.trial_expired: alternative path if conversion fails.
Ability to subscribe
A token needs this to subscribe an endpoint to the event.
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.
Payload
JSONWhat Subscriby posts to your endpointapplication/json
The signed JSON envelope posted to your endpoint.
The envelope every event is delivered in.
Responses
2XXAny success status
Your endpoint acknowledged the delivery. Any 2xx status within 30 seconds marks it delivered; the response body is ignored.
defaultAny other status
Any other status, a connection failure, or no answer within 30 seconds counts as a failed attempt. The delivery is retried 8 times, after 10 seconds, 30 seconds, 2 minutes, 10 minutes, 1 hour, 6 hours, 1 day, 3 days; the last failure dead-letters it, and it can be retried from the dashboard or POST /v1/webhook-deliveries/{delivery}/retry. After 20 consecutive failures the endpoint is paused until it is resumed.
subscription.trial_expired
WEBHOOKTrial ended without conversion.
When this fires
A trial ends without conversion. Emitted alongside subscription.expired for the same subscription.
Caveats
- Successful conversions fire
subscription.activatedandmember.convertedinstead. - Expect
subscription.expiredandmember.churnedto follow for the same subscriber.
Related events
subscription.trial_started: predecessor.subscription.expired: fires alongside.
Ability to subscribe
A token needs this to subscribe an endpoint to the event.
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.
Payload
JSONWhat Subscriby posts to your endpointapplication/json
The signed JSON envelope posted to your endpoint.
The envelope every event is delivered in.
Responses
2XXAny success status
Your endpoint acknowledged the delivery. Any 2xx status within 30 seconds marks it delivered; the response body is ignored.
defaultAny other status
Any other status, a connection failure, or no answer within 30 seconds counts as a failed attempt. The delivery is retried 8 times, after 10 seconds, 30 seconds, 2 minutes, 10 minutes, 1 hour, 6 hours, 1 day, 3 days; the last failure dead-letters it, and it can be retried from the dashboard or POST /v1/webhook-deliveries/{delivery}/retry. After 20 consecutive failures the endpoint is paused until it is resumed.
subscription.renewed
WEBHOOKRecurring billing successfully charged the subscriber.
When this fires
Recurring billing successfully charges the subscriber and the subscription is renewed for another period.
Caveats
- A
subscription.renewedis always paired with apayment.succeededfor the same charge. - Currency may differ from the plan's nominal currency for providers that auto-convert at the gateway.
Related events
payment.succeeded: paired payment event.subscription.past_due,subscription.unpaid: failure paths.
Ability to subscribe
A token needs this to subscribe an endpoint to the event.
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.
Payload
JSONWhat Subscriby posts to your endpointapplication/json
The signed JSON envelope posted to your endpoint.
The envelope every event is delivered in.
Responses
2XXAny success status
Your endpoint acknowledged the delivery. Any 2xx status within 30 seconds marks it delivered; the response body is ignored.
defaultAny other status
Any other status, a connection failure, or no answer within 30 seconds counts as a failed attempt. The delivery is retried 8 times, after 10 seconds, 30 seconds, 2 minutes, 10 minutes, 1 hour, 6 hours, 1 day, 3 days; the last failure dead-letters it, and it can be retried from the dashboard or POST /v1/webhook-deliveries/{delivery}/retry. After 20 consecutive failures the endpoint is paused until it is resumed.
subscription.reactivated
WEBHOOKCancelled subscription re-activated before `ends_at`.
When this fires
A previously cancelled subscription is reactivated before its ends_at. The subscription returns to the active state and the next billing cycle resumes.
Caveats
- Reactivation is only possible while
ends_atis in the future. After expiration, a new subscription must be created instead. - Pairs with a renewed provider subscription for paid plans; the next charge will follow normal cadence.
Related events
subscription.cancelled: predecessor.subscription.expired: alternative path if reactivation does not occur.
Ability to subscribe
A token needs this to subscribe an endpoint to the event.
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.
Payload
JSONWhat Subscriby posts to your endpointapplication/json
The signed JSON envelope posted to your endpoint.
The envelope every event is delivered in.
Responses
2XXAny success status
Your endpoint acknowledged the delivery. Any 2xx status within 30 seconds marks it delivered; the response body is ignored.
defaultAny other status
Any other status, a connection failure, or no answer within 30 seconds counts as a failed attempt. The delivery is retried 8 times, after 10 seconds, 30 seconds, 2 minutes, 10 minutes, 1 hour, 6 hours, 1 day, 3 days; the last failure dead-letters it, and it can be retried from the dashboard or POST /v1/webhook-deliveries/{delivery}/retry. After 20 consecutive failures the endpoint is paused until it is resumed.
subscription.paused
WEBHOOKA member's access was suspended. Billing is unaffected and continues on schedule.
When this fires
A creator suspended a member's access. payment_status becomes paused, paused_at is stamped, and the member is removed from every linked resource.
This is an access pause, not a billing pause. The member's payment provider keeps charging them on schedule. Subscriby does not pause collection, suspend the PayPal agreement, or otherwise hold the charge. If you need billing to stop, cancel instead.
The split is deliberate: Subscriby settles through seven providers and only some can hold a recurring charge at all, so a pause meaning "stop billing" would work on some providers and silently not on others. Access is something Subscriby controls directly, so it behaves identically everywhere.
Before 1 September 2026 this event fired without anything happening: no provider was called and no access was removed. If you built on the old behaviour, note that a paused member now genuinely loses access.
Caveats
- Pausing does not change
ends_at, and does not stop the clock. The member is still being billed, so a long pause costs them money for access they do not have. Tell them, or cancel instead. - Access removal is queued, one call per linked resource, so it completes shortly after this event rather than atomically with it.
- Pausing does not detach resources, so no
member.resource_removedevents follow. Revocation happens only on expiry or cancellation.
Related events
subscription.unpaused: paired transition.
Ability to subscribe
A token needs this to subscribe an endpoint to the event.
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.
Payload
JSONWhat Subscriby posts to your endpointapplication/json
The signed JSON envelope posted to your endpoint.
The envelope every event is delivered in.
Responses
2XXAny success status
Your endpoint acknowledged the delivery. Any 2xx status within 30 seconds marks it delivered; the response body is ignored.
defaultAny other status
Any other status, a connection failure, or no answer within 30 seconds counts as a failed attempt. The delivery is retried 8 times, after 10 seconds, 30 seconds, 2 minutes, 10 minutes, 1 hour, 6 hours, 1 day, 3 days; the last failure dead-letters it, and it can be retried from the dashboard or POST /v1/webhook-deliveries/{delivery}/retry. After 20 consecutive failures the endpoint is paused until it is resumed.
subscription.unpaused
WEBHOOKPaused subscription resumes; resource invite links re-issued.
When this fires
A suspended member has their access restored, with fresh invite links: an invite link revoked on pause cannot be un-revoked.
Billing is not mentioned here because it never stopped: pausing suspends access only, so there is nothing on the provider side to resume.
Caveats
- Expect
member.resource_addedentries as resources are re-attached.subscription.activateddoes not follow an unpause; it fires only once, at first paid acquisition. - Renewal cadence resumes from the original
ends_atboundary, not the unpause moment.
Related events
subscription.paused: paired transition.member.resource_added: re-grant signal.
Ability to subscribe
A token needs this to subscribe an endpoint to the event.
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.
Payload
JSONWhat Subscriby posts to your endpointapplication/json
The signed JSON envelope posted to your endpoint.
The envelope every event is delivered in.
Responses
2XXAny success status
Your endpoint acknowledged the delivery. Any 2xx status within 30 seconds marks it delivered; the response body is ignored.
defaultAny other status
Any other status, a connection failure, or no answer within 30 seconds counts as a failed attempt. The delivery is retried 8 times, after 10 seconds, 30 seconds, 2 minutes, 10 minutes, 1 hour, 6 hours, 1 day, 3 days; the last failure dead-letters it, and it can be retried from the dashboard or POST /v1/webhook-deliveries/{delivery}/retry. After 20 consecutive failures the endpoint is paused until it is resumed.
subscription.past_due
WEBHOOKBilling fails but grace period is active.
When this fires
A scheduled charge fails but the subscription remains within its grace window. The platform will continue to attempt collection.
Coverage is partial: only Stripe and Razorpay report the past-due transition back to Subscriby. Failed renewals on PayPal, Paystack, Skrill, CeyPay, and CoinPayments emit payment.failed without a matching subscription.past_due, so treat payment.failed as the reliable cross-provider signal.
Caveats
- Pairs with a
payment.failedevent for the underlying charge. - If retries succeed,
subscription.renewedfollows. If grace expires,subscription.unpaidfires instead.
Related events
payment.failed: paired payment event.subscription.unpaid: grace-window terminal state.
Ability to subscribe
A token needs this to subscribe an endpoint to the event.
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.
Payload
JSONWhat Subscriby posts to your endpointapplication/json
The signed JSON envelope posted to your endpoint.
The envelope every event is delivered in.
Responses
2XXAny success status
Your endpoint acknowledged the delivery. Any 2xx status within 30 seconds marks it delivered; the response body is ignored.
defaultAny other status
Any other status, a connection failure, or no answer within 30 seconds counts as a failed attempt. The delivery is retried 8 times, after 10 seconds, 30 seconds, 2 minutes, 10 minutes, 1 hour, 6 hours, 1 day, 3 days; the last failure dead-letters it, and it can be retried from the dashboard or POST /v1/webhook-deliveries/{delivery}/retry. After 20 consecutive failures the endpoint is paused until it is resumed.
subscription.unpaid
WEBHOOKBilling permanently failed; grace expired.
When this fires
A subscription's grace period ends without successful collection. The provider has given up retrying. Resource access is typically revoked shortly after.
This event is emitted for Stripe only; it depends on the provider reporting an unpaid subscription status. On every other provider, an abandoned subscription surfaces as subscription.expired once ends_at passes, with no preceding subscription.unpaid.
Caveats
- After this event, the subscription is non-recoverable on its current terms; the subscriber must restart with a new subscription.
- Expect
subscription.expiredandmember.churnedto follow.
Related events
subscription.past_due: predecessor inside the grace window.subscription.expired: terminal state.
Ability to subscribe
A token needs this to subscribe an endpoint to the event.
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.
Payload
JSONWhat Subscriby posts to your endpointapplication/json
The signed JSON envelope posted to your endpoint.
The envelope every event is delivered in.
Responses
2XXAny success status
Your endpoint acknowledged the delivery. Any 2xx status within 30 seconds marks it delivered; the response body is ignored.
defaultAny other status
Any other status, a connection failure, or no answer within 30 seconds counts as a failed attempt. The delivery is retried 8 times, after 10 seconds, 30 seconds, 2 minutes, 10 minutes, 1 hour, 6 hours, 1 day, 3 days; the last failure dead-letters it, and it can be retried from the dashboard or POST /v1/webhook-deliveries/{delivery}/retry. After 20 consecutive failures the endpoint is paused until it is resumed.
subscription.cancelled
WEBHOOKCancellation recorded; access continues until `ends_at`.
When this fires
Cancellation is recorded by the subscriber, by the creator, or by the payment provider (a gateway-side cancellation, or a terminal payment failure on CeyPay, CoinPayments or Skrill). If the paid period still has time left, the subscription stays active and the subscriber keeps access until ends_at, after which subscription.expired fires. If no paid period remains, ends_at is set to the cancellation moment and resource access is revoked straight away.
Caveats
- Cancellation is reversible until
ends_at; seesubscription.reactivated. - A renewal does not occur after cancellation;
subscription.renewedwill not fire.
Related events
subscription.expired: fires when the period ends.subscription.reactivated: reverse path.
Ability to subscribe
A token needs this to subscribe an endpoint to the event.
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.
Payload
JSONWhat Subscriby posts to your endpointapplication/json
The signed JSON envelope posted to your endpoint.
The envelope every event is delivered in.
Responses
2XXAny success status
Your endpoint acknowledged the delivery. Any 2xx status within 30 seconds marks it delivered; the response body is ignored.
defaultAny other status
Any other status, a connection failure, or no answer within 30 seconds counts as a failed attempt. The delivery is retried 8 times, after 10 seconds, 30 seconds, 2 minutes, 10 minutes, 1 hour, 6 hours, 1 day, 3 days; the last failure dead-letters it, and it can be retried from the dashboard or POST /v1/webhook-deliveries/{delivery}/retry. After 20 consecutive failures the endpoint is paused until it is resumed.
subscription.expired
WEBHOOK`ends_at` reached; access revoked.
When this fires
The subscription's ends_at has passed. Resource access is revoked and the subscription transitions to its terminal state.
Caveats
- Pairs with
member.churnedwhen this is the subscriber's last active subscription. - Resource access is revoked as part of expiry; expect
member.resource_removedevents for each granted resource.
Related events
subscription.cancelled,subscription.unpaid,subscription.trial_expired: predecessors.member.churned: paired member-level event.
Ability to subscribe
A token needs this to subscribe an endpoint to the event.
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.
Payload
JSONWhat Subscriby posts to your endpointapplication/json
The signed JSON envelope posted to your endpoint.
The envelope every event is delivered in.
Responses
2XXAny success status
Your endpoint acknowledged the delivery. Any 2xx status within 30 seconds marks it delivered; the response body is ignored.
defaultAny other status
Any other status, a connection failure, or no answer within 30 seconds counts as a failed attempt. The delivery is retried 8 times, after 10 seconds, 30 seconds, 2 minutes, 10 minutes, 1 hour, 6 hours, 1 day, 3 days; the last failure dead-letters it, and it can be retried from the dashboard or POST /v1/webhook-deliveries/{delivery}/retry. After 20 consecutive failures the endpoint is paused until it is resumed.
subscription.refunded
WEBHOOKRefund recorded against a subscription.
When this fires
A full subscription-level refund settles. The subscription is always expired as a result: resource access is revoked and subscription.expired (plus member.churned when this was the subscriber's last active subscription) follows for the same subscription.
Fires only for a settled refund. A refund a provider has queued but not yet paid out raises nothing; access is never revoked for money that has not actually moved.
Caveats
- Emitted by Stripe, PayPal, Paystack, Razorpay and Skrill. CoinPayments and CeyPay expose no refund notification, so a refund taken there is invisible to this event.
- A partial refund raises
payment.refundedonly. This event means the whole charge came back, and access is revoked with it. - Skrill reports a chargeback rather than a merchant refund, and only if the creator's Skrill account is configured to post one.
- Subscriby expires the subscription itself on a full refund; it does not wait for the provider's own cancellation to arrive.
- For per-payment refunds (no subscription mutation), see
payment.refunded.
Related events
payment.refunded: payment-level analogue.subscription.cancelled: often paired in practice.
Ability to subscribe
A token needs this to subscribe an endpoint to the event.
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.
Payload
JSONWhat Subscriby posts to your endpointapplication/json
The signed JSON envelope posted to your endpoint.
The envelope every event is delivered in.
Responses
2XXAny success status
Your endpoint acknowledged the delivery. Any 2xx status within 30 seconds marks it delivered; the response body is ignored.
defaultAny other status
Any other status, a connection failure, or no answer within 30 seconds counts as a failed attempt. The delivery is retried 8 times, after 10 seconds, 30 seconds, 2 minutes, 10 minutes, 1 hour, 6 hours, 1 day, 3 days; the last failure dead-letters it, and it can be retried from the dashboard or POST /v1/webhook-deliveries/{delivery}/retry. After 20 consecutive failures the endpoint is paused until it is resumed.
subscription.upgraded
WEBHOOKSubscriber moved to a higher-priced plan.
When this fires
A subscriber is switched to a higher-priced plan on the same project. The plan assignment, currency, and stored price on the Subscriby subscription record are updated, and this event reports the move.
The switch does not itself perform a provider-side pro-ration or issue a charge. Any billing adjustment is whatever the provider does on the next cycle.
Caveats
- Direction is decided by comparing the two plan prices, normalised to USD, at switch time. Only a strictly higher new price emits
subscription.upgraded; an equal-price switch emitssubscription.downgraded, which is worth guarding for if you offer same-price plan swaps. - Trial windows do not carry across switches; if the destination plan has a trial it does not start.
Related events
subscription.downgraded: opposite direction.payment.succeeded: the next successful charge on the new plan.
Ability to subscribe
A token needs this to subscribe an endpoint to the event.
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.
Payload
JSONWhat Subscriby posts to your endpointapplication/json
The signed JSON envelope posted to your endpoint.
The envelope every event is delivered in.
Responses
2XXAny success status
Your endpoint acknowledged the delivery. Any 2xx status within 30 seconds marks it delivered; the response body is ignored.
defaultAny other status
Any other status, a connection failure, or no answer within 30 seconds counts as a failed attempt. The delivery is retried 8 times, after 10 seconds, 30 seconds, 2 minutes, 10 minutes, 1 hour, 6 hours, 1 day, 3 days; the last failure dead-letters it, and it can be retried from the dashboard or POST /v1/webhook-deliveries/{delivery}/retry. After 20 consecutive failures the endpoint is paused until it is resumed.
subscription.downgraded
WEBHOOKSubscriber moved to a lower-priced plan.
When this fires
A subscriber is switched to a lower-priced plan on the same project. The plan assignment, currency, and stored price on the Subscriby subscription record are updated, and this event reports the move.
The switch does not itself perform a provider-side pro-ration or issue a credit. Any billing adjustment is whatever the provider does on the next cycle.
Caveats
- No credit or refund is issued by this action. If you owe subscribers a mid-cycle credit on downgrade, apply it yourself through the provider.
- Direction is decided by comparing the two plan prices, normalised to USD. Anything that is not strictly more expensive lands here, so a switch between two equally-priced plans emits this event, not
subscription.upgraded. - Resource access tied to the higher tier may be revoked on the next renewal cycle.
Related events
subscription.upgraded: opposite direction.member.resource_removed: emitted when premium-tier resources are detached.
Ability to subscribe
A token needs this to subscribe an endpoint to the event.
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.
Payload
JSONWhat Subscriby posts to your endpointapplication/json
The signed JSON envelope posted to your endpoint.
The envelope every event is delivered in.
Responses
2XXAny success status
Your endpoint acknowledged the delivery. Any 2xx status within 30 seconds marks it delivered; the response body is ignored.
defaultAny other status
Any other status, a connection failure, or no answer within 30 seconds counts as a failed attempt. The delivery is retried 8 times, after 10 seconds, 30 seconds, 2 minutes, 10 minutes, 1 hour, 6 hours, 1 day, 3 days; the last failure dead-letters it, and it can be retried from the dashboard or POST /v1/webhook-deliveries/{delivery}/retry. After 20 consecutive failures the endpoint is paused until it is resumed.
How is this guide?