plan.* events
Fires on every change to a plan's state, pricing or storefront position.
Fires on every change to a plan's state, pricing or storefront position. Consumers commonly use these to keep a pricing-page cache or a CRM field in sync.
Background
Example envelope
{
"id": "evt_01HX...",
"type": "plan.updated",
"created_at": "2026-05-18T10:05:00Z",
"api_version": "2026-05-01",
"project_id": "7f3d1c92-8b45-4e6a-9d21-5c8e0a4b6f13",
"data": {
"plan": {
"id": "c4e82f16-93a7-4d5b-b81c-6e0f27a94d3b",
"name": "Premium Monthly",
"price": "29.0000",
"currency_id": "8f27a0d4-63be-4915-8c07-1a5d9e34b628",
"billing_cycle": "month",
"active": true
},
"changes": {
"price": { "from": "25.0000", "to": "29.00" }
}
}
}The data.changes block is present on plan.updated and identifies the fields that changed. For other events it is omitted. Each from is the plan's previous value after model casting, so price is a string and an enum column is its backed string value, while each to is the caller-supplied value exactly as validated.
Required ability
Tokens subscribing to plan.* events must carry project-subscription-plan:view at mint time.
Events
plan.createdA plan is first created on a project.plan.updatedAny mutable plan field changes.plan.activatedInactive plan flipped active.plan.deactivatedActive plan flipped inactive.plan.sold_outA plan hit its sales cap, or a pass series filled its last seat, and Subscriby paused it automatically.plan.order_changedThe creator arranged the order plans appear in on the portal and in the bot, or reset it.plan.deletedPlan soft-deleted (removed from the catalog).plan.sync_completedPlan synced to the payment-provider catalog (Stripe, PayPal, CoinPayments or Razorpay).plan.created
WEBHOOKA plan is first created on a project.
When this fires
A plan is created through the REST API (POST /v1/projects/{project}/plans) or the create_plan MCP tool, or a finished pass season is duplicated into its next season. Plans created from the creator dashboard or the bot do not emit this event. The plan is immediately eligible for purchase if it was created in the active state.
The two shapes are disjoint. The API and MCP path sends
data.planand nothing else; the season-duplication path sends the four flat keys and nodata.planobject. Branch on whetherdata.planordata.plan_idis present before reading any other field.
billing_cycle is only the unit. The multiplier lives in billing_cycle_count on the plan record and is not included in this payload: a "3 month" plan sends billing_cycle: "month" with no indication of the 3. Nor is trial_days. Fetch the plan with GET /v1/projects/{project}/plans/{plan} when you need the full cadence or trial configuration.
Caveats
- A
plan.createdevent does not imply the plan has been synced to a payment-provider catalog. Listen forplan.sync_completedfor that. - Trial is configured at create time. A later trial-only edit is only applied, and only then fires
plan.updated, when the PATCH also carries akindkey; without it the trial fields are dropped and no event is emitted.
Related events
plan.updated: subsequent edits.plan.sync_completed: provider catalog sync.
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.
plan.updated
WEBHOOKAny mutable plan field changes.
When this fires
A plan is edited through the REST API (PATCH /v1/projects/{project}/plans/{plan}): pricing, name, currency, billing cadence, eligibility filters. Edits made in the creator dashboard do not emit this event, and trial fields are only written (and only then reported) when the payload also carries kind. An active flag sent on a PATCH is reported here as an ordinary changes.active entry. The dedicated plan.activated and plan.deactivated events come only from the publish and unpublish endpoints.
Caveats
- Existing subscriptions priced on the old terms are not retroactively re-priced. New checkouts use the new price; renewals follow the billing rules.
- An
activeflag sent on a PATCH is reported here as an ordinarychanges.activeentry. The dedicatedplan.activatedandplan.deactivatedevents come only from the publish and unpublish endpoints.
Related events
plan.activated,plan.deactivated: dedicated active-flag events.plan.sync_completed: fires after price changes propagate to the provider catalog.
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.
plan.activated
WEBHOOKInactive plan flipped active.
When this fires
An inactive plan is flipped to active through the REST API (POST /v1/projects/{project}/plans/{plan}/publish) or the publish_plan MCP tool, and becomes purchasable on the project landing page. Toggling a plan on from the creator dashboard does not emit this event.
Caveats
- Publishing a plan that is already active is a no-op: nothing is written and no event is emitted.
- Activation does not retroactively touch existing subscriptions on the plan; only checkout availability changes.
- Frequent flipping is permitted but produces noisy timelines; use
plan.updatedfor non-state edits.
Related events
plan.deactivated: paired transition.plan.created: predecessor.
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.
plan.deactivated
WEBHOOKActive plan flipped inactive.
When this fires
A plan is taken off sale through the REST API (POST /v1/projects/{project}/plans/{plan}/unpublish) or the publish_plan MCP tool; automatically when a pass series runs its last date; or when the free-plan entitlement sweep disables an unentitled zero-priced plan. The plan remains visible to existing subscribers and stays in the catalog, but new checkouts cannot select it. Deactivating from the creator dashboard does not emit this event.
The two shapes are disjoint. The publish-state path sends
data.planand nothing else; an automatically retired series sends the five flat keys and nodata.planobject. Branch on whetherdata.planordata.plan_idis present before reading any other field.
Caveats
- Existing subscriptions on the plan are unaffected and continue to renew until cancelled or expired.
- For permanent removal use
plan.deleted.
Related events
plan.activated: paired transition.plan.deleted: 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.
plan.sold_out
WEBHOOKA plan hit its sales cap, or a pass series filled its last seat, and Subscriby paused it automatically.
When this fires
A plan carrying a sales cap records its last allowed successful purchase, or a pass_series plan with a seat cap seats its last holder. Subscriby switches the plan off on the spot, records the reason, and fires this event once. The plan disappears from the portal and the bot until the creator switches it back on; existing subscribers are untouched.
A plan.deactivated event fires alongside it, carrying the same reason, so automations that only watch availability still see the change. Subscribe to this event when you care specifically about "sold out": a waitlist, a restock reminder, a celebratory post.
Switching the plan back on from the dashboard, the API (publish) or the
publish_plantool clears the reason and, for a sales cap, restarts the counter at zero, so the same cap sells another batch. Raising or clearing the cap while the plan is on sale also restarts the counter. A seat-capped series keeps its seats taken; raise the seat cap before publishing it again.
Related events
plan.deactivated: fires at the same moment with the samereason.plan.activated: the creator switching the plan back on.pass_series.seats_exhausted: the season-level view of a filled seat cap.
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.
plan.order_changed
WEBHOOKThe creator arranged the order plans appear in on the portal and in the bot, or reset it.
When this fires
A creator drags plans into a new order in the dashboard's Arrange Storefront Order dialog and saves, calls POST /v1/projects/{project}/plans/order, or runs the reorder_plans MCP tool. Resetting to the built-in order fires it too. The event carries the resulting order of every plan currently on sale, so a mirror of the storefront can re-sort itself without a second read.
The built-in order is passes first, then seasons, then subscriptions, each group cheapest first. Plans created after an arrangement join the end in that order until the creator arranges again, so
plan_idson this event may be shorter than the plan list read a week later.
Related events
plan.created: a new plan joins the end of the storefront.plan.activated,plan.deactivated: a plan entering or leaving the storefront.
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.
plan.deleted
WEBHOOKPlan soft-deleted (removed from the catalog).
This is the final event you will receive for the given plan id.
When this fires
The plan is removed from the project. It is soft-deleted: the row is retained with deleted_at set, so subscription rows that reference it are untouched and continue to honor their existing term. Only deletions made through the REST API (DELETE /v1/projects/{project}/plans/{plan}) emit this event; deleting a plan from the creator dashboard does not.
Caveats
- Reads of the plan after this event return
404. Existing subscriptions continue to reference the plan id internally. - Deleting a plan makes no call to the payment providers. Catalog entries previously created by the plan sync (Stripe prices, PayPal plans, and so on) remain active at the provider and must be archived there manually.
Related events
plan.deactivated: typical predecessor.plan.created: first event in the lifecycle.
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.
plan.sync_completed
WEBHOOKPlan synced to the payment-provider catalog (Stripe, PayPal, CoinPayments or Razorpay).
When this fires
The plan finishes syncing to one or more external payment-provider catalogs (Stripe, PayPal, CoinPayments, Razorpay). Fires once per active plan per sync run: a run over a project with twelve active plans emits twelve events. A plan whose providers all failed emits nothing, and inactive plans are never synced.
Caveats
- Partial failures retry on a follow-up run rather than emitting a separate event per provider;
providerslists only the providers that succeeded for that plan. - Errors during sync surface in the dashboard, not as webhook events.
Related events
plan.created: predecessor that typically triggers the first sync.plan.updated: re-sync trigger when pricing or cadence changes.
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?