pass.holder_missed
A window closed and one holder never turned up for it.
When this fires
An access window closed and a specific holder was recorded as Missed — they paid, the window ran, and they never joined.
pass.window_closed already reports an aggregate subscribers_affected,
which is the wrong half for outreach. Who did not turn up is the useful question, the answer
is already computed and stored per holder, and this is that answer.
Missed is a claim about the customer, so it is made carefully
A holder is only marked Missed when they were never admitted. If they bought so late that the window was effectively over before their payment cleared, the pass is settled as ended rather than missed and this event does not fire — Subscriby will not tell you a paying customer no-showed when the timing was ours. One exception runs the other way: when a window never opened at all because of a worker outage, its ungranted holders are recorded as Missed and this event fires for each of them, so treat a burst of these for a single window as an outage signal rather than as no-shows.
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_missed",
"created_at": "2026-09-21T03:00:07Z",
"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",
"window_id": "3d5a8c72-b016-4e94-8fa7-61c209d4e738",
"starts_at": "2026-09-20T13:00:00+00:00",
"ends_at": "2026-09-21T03:00:00+00:00",
"join_requested": false
}
}Field reference
| Field | Type | Notes |
|---|---|---|
id | string ULID | Unique event id, prefixed evt_. Use for idempotent processing. |
type | string | Always pass.holder_missed 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 purchase that went unused. |
data.subscriber_id | string UUID | The project user who did not turn up. |
data.plan_id | string UUID | The plan the window belongs to. |
data.window_id | string UUID | The window they missed. |
data.starts_at | ISO 8601 timestamp | Window start, always UTC. |
data.ends_at | ISO 8601 timestamp | Window end, always UTC. |
data.join_requested | boolean | Whether they ever tapped their invite link. false means they never engaged at all; true means they queued and still did not appear. |
Caveats
join_requestedis the field worth branching on. A holder who never queued probably never saw the message — that is a reachability problem. A holder who queued and still did not appear made a choice, and chasing them the same way reads as nagging.- On a series this fires per date. Missing one date of a season affects nothing else: the
rest of the slate runs as booked, so treat a single occurrence as a data point rather than a
churn signal.
pass_series.completedcarries the final tally, which is the figure that actually means something. - It fires alongside
pass.window_closedfor the same window. Both are correct — one is per holder, one is the aggregate — so an endpoint subscribed to both receives one of each.
Related events
pass.holder_queued— the engagement this is the absence of.pass.window_closed— the aggregate for the same window.pass_series.leg_completed— the same close, seen as progress through a season.- Pass events overview — back to family overview.
How is this guide?