pass_series.leg_added
An automatic rule absorbed a newly-scheduled window into a live series.
When this fires
A Pass Series with Automatic Passes Selection matched a newly-scheduled window on one of its source plans, added it to the slate, and granted it to everyone currently holding the series — at no extra charge.
This is the event that makes an external calendar or CRM worth wiring up. A season composed with rules is not fixed at the point it sold: it grows, and holders are given what it grows by. Without this you would have to re-read the plan to notice.
Holders are messaged too
Every current holder receives a Telegram message naming the new date, and it appears on their timetable and in their calendar feed. Nothing is asked of them — their invite link arrives before it opens, as usual.
Required ability
project-subscription-plan:view — token must carry this at mint time to subscribe an endpoint to this event.
Payload
{
"id": "evt_01HX...",
"type": "pass_series.leg_added",
"created_at": "2026-10-04T07:15:00Z",
"api_version": "2026-05-01",
"project_id": "7f3d1c92-8b45-4e6a-9d21-5c8e0a4b6f13",
"data": {
"plan_id": "c4e82f16-93a7-4d5b-b81c-6e0f27a94d3b",
"plan_name": "Autumn Season Ticket",
"window_id": "3d5a8c72-b016-4e94-8fa7-61c209d4e738",
"source_plan_id": "9a4c1b58-2e37-4d80-b6f1-0c7e35a92b41",
"starts_at": "2026-11-08T18:00:00Z",
"ends_at": "2026-11-08T21:00:00Z",
"timezone": "America/New_York",
"window_count": 12
}
}Field reference
| Field | Type | Notes |
|---|---|---|
id | string ULID | Unique event id, prefixed evt_. Use for idempotent processing. |
type | string | Always pass_series.leg_added 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.plan_id | string UUID | The series plan that grew. |
data.plan_name | string | Its name. |
data.window_id | string UUID | The window that was absorbed. |
data.source_plan_id | string UUID | The pass plan the window belongs to. This is the plan whose resources that date grants. |
data.starts_at | ISO 8601 timestamp | Window start, always UTC. |
data.ends_at | ISO 8601 timestamp | Window end, always UTC. |
data.timezone | string | The source plan's authoring zone — a series has none of its own. Render the timestamps in this. |
data.window_count | integer | The slate's total length after this absorption. |
Caveats
- This fires once per window. One absorption run can take in several at a time, which arrives as several events rather than one carrying a list.
- Absorption respects Prevent Overlapping Passes. With the toggle on, a window that clashes with something already on the slate is refused rather than absorbed — the series will not hand holders two things at the same time — so a matching window can exist and never produce this event.
- A rule of type
next_nstops once it has taken its count and never tops itself back up. A window becoming free later does not make it reach for another. - A series is capped at 120 dates. A rule that would take the slate past the cap stops there.
- Holders who cancelled are not granted the new date.
- Manually handpicked dates never produce this event. Handpicking is a fixed list by design; only rules keep working after the save.
- A date the creator has excluded stays excluded. Unticking a rule-added pass records a permanent exclusion, and the rule will not put it back.
Related events
pass.window_scheduled— the window coming into existence, which is what a rule reacts to.pass_series.leg_substituted— a date being swapped rather than added.pass_series.leg_dropped— a date leaving a season.- Pass series events overview — back to family overview.
How is this guide?