pass_series.leg_completed

One date of a holder's season finished, with their running attendance.

When this fires

One window on a season ticket closed for one holder. It fires per holder per date, so a ten-date season sold to forty people emits four hundred of these across its run.

It is the progress event. Where pass.holder_missed answers "did they turn up", this answers "where are they in the season" — which is what an integration syncing a timetable or scoring engagement actually needs.

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_series.leg_completed",
  "created_at": "2026-10-25T21:00:06Z",
  "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",
    "source_plan_id": "9a4c1b58-2e37-4d80-b6f1-0c7e35a92b41",
    "granted": true,
    "joined": true,
    "passes_total": 10,
    "passes_attended": 4,
    "passes_missed": 1,
    "passes_remaining": 5
  }
}

Field reference

FieldTypeNotes
idstring ULIDUnique event id, prefixed evt_. Use for idempotent processing.
typestringAlways pass_series.leg_completed for this event.
created_atISO 8601 timestampServer-side emission time.
api_versionstringWebhook API contract version.
project_idstring UUIDProject this event belongs to.
data.subscription_idstring UUIDThe season ticket.
data.subscriber_idstring UUIDThe holder.
data.plan_idstring UUIDThe series plan they bought.
data.window_idstring UUIDThe date that just finished.
data.source_plan_idstring UUIDThe pass plan that date belongs to — a series can mix several.
data.grantedbooleanWhether access was actually issued to them for this date.
data.joinedbooleanWhether they actually joined. Granted and joined are different questions — see below.
data.passes_totalintegerDates on this holder's slate.
data.passes_attendedintegerHow many they have joined so far, including this one.
data.passes_missedintegerHow many they have missed so far.
data.passes_remainingintegerHow many are still ahead of them. 0 means this was their last — see the caveat.

Caveats

  • granted and joined are tracked separately on purpose. Granted means Subscriby admitted them; joined means they actually appeared. A date can be granted and not joined — a held request approved into a channel the person never opened — and that distinction is the difference between a delivery problem and a disengaged customer.
  • passes_attended + passes_missed will not equal passes_total mid-season. The remainder is dates still ahead, plus any marked as already covered because the holder owned them individually before buying the series.
  • When passes_remaining reaches 0, pass_series.completed fires for the same holder in the same pass. Both are emitted; de-duplicate if you only want one.
  • Two holders of the same series reach the same date at different points in their own season if one bought mid-way — the counts are per purchase, never per plan.

How is this guide?

On this page

Subscriby is a product designed by you — for you.

No boardroom full of executives deciding what we ships next. Our roadmap always shaped by you with your feedback.

Share feedback or a request