pass.holder_stranded
A pass holder's window was cancelled with no replacement available, so their pass ended and a refund is owed.
When this fires
One holder of a cancelled access window could not be moved anywhere, so their pass was ended.
Fires once per stranded holder of an ordinary pass, alongside the single
pass.window_cancelled for the window itself. A season-ticket holder
never reaches this state — cancelling one leg of a season emits
pass_series.leg_dropped instead and leaves the
rest of the slate intact.
They have paid for a date that is not happening and received nothing. Subscriby tells them so and asks them to contact the creator — it does not issue a refund.
This is the durable record of who is owed money
The creator's dashboard shows the refund count once, in a toast that survives a single page load, and the ended subscriptions are afterwards indistinguishable from ordinary expiries. This event carries the identity, the amount and the gateway reference, so consuming it is the only reliable way to reconcile refunds automatically.
Why a replacement can be missing
- The plan has no later window scheduled at all.
- The only later windows are already inside the plan's sales cutoff, so they are closed to sales and cannot take new holders — a later date can be visible on the calendar and still not qualify.
- The customer already holds a pass for every remaining window.
- The plan's repeating schedule has passed its recurrence end date, so no later window qualifies even if the calendar still shows dates.
Required ability
project-subscription:view — token must carry this at mint time to subscribe an endpoint to this event.
Payload
{
"id": "evt_01HX...",
"type": "pass.holder_stranded",
"created_at": "2026-09-18T09:14:22Z",
"api_version": "2026-05-01",
"project_id": "7f3d1c92-8b45-4e6a-9d21-5c8e0a4b6f13",
"data": {
"subscription_id": "5b7e2d40-1a86-4c39-97f2-e83d0b16c5a4",
"subscriber_id": "2a91c4e7-6f38-4b52-8e0d-9c1a7b3f5d80",
"plan_id": "c4e82f16-93a7-4d5b-b81c-6e0f27a94d3b",
"from_window_id": "3d5a8c72-b016-4e94-8fa7-61c209d4e738",
"from_starts_at": "2026-09-20T13:00:00+00:00",
"from_ends_at": "2026-09-20T19:00:00+00:00",
"refund_due": true,
"amount_paid": "15.000",
"currency": "GBP",
"payment_id": "pi_3U9Jan4m40lWsKma0f3ntmnl"
}
}Field reference
| Field | Type | Notes |
|---|---|---|
id | string ULID | Unique event id, prefixed evt_. Use for idempotent processing. |
type | string | Always pass.holder_stranded for this event. |
created_at | ISO 8601 timestamp | Server-side emission time. |
api_version | string | Webhook API contract version. |
project_id | string UUID | Project this event belongs to. |
data.subscription_id | string UUID | The pass purchase that ended. |
data.subscriber_id | string UUID | The subscriber owed a refund. |
data.plan_id | string UUID | The pass plan. |
data.from_window_id | string UUID | The cancelled window they held. |
data.from_starts_at | ISO 8601 timestamp | Cancelled window start, always UTC. |
data.from_ends_at | ISO 8601 timestamp | Cancelled window end, always UTC. |
data.refund_due | boolean | Always true. Present so a single handler can branch on it. |
data.amount_paid | string decimal | What they paid for the window. A string to preserve precision. |
data.currency | string | ISO 4217 code, e.g. GBP. Null if the subscription has no currency recorded. |
data.payment_id | string | The gateway's own reference, for issuing the refund. Null when none was recorded. |
Caveats
- The subscription also emits
subscription.expired, andmember.churnedwhen it was their last active subscription. De-duplicate if you consume several. - No
subscription.refundedfollows unless the creator actually issues the refund in their payment provider, at which point the gateway's webhook records it. - Holders who were paused, past due, or had already cancelled their own pass are not included, even though they may also have paid. Reconcile those separately.
amount_paidis what the subscription recorded at purchase; it does not account for any partial refund already issued.
Related events
pass.window_cancelled— the window-level event, fired once.pass.holder_moved— the other outcome, when a replacement existed.subscription.expired— also fires for this subscription.- Pass events overview — back to family overview.
How is this guide?