start_next_season
Duplicate a finished pass series into its next season — a new inactive pass_series plan with the same settings, an empty slate, and the old season linked to it. Not idempotent.
Purpose
The plan list's "start next season" button, for agents. It creates a new plan of kind
pass_series copied from the one you name — same price, currency, description, eligibility,
linked resources, overlap rule, sales cutoff and seat cap — with two deliberate differences: it is
created inactive, and its slate is empty. A season that went straight on sale with last
year's dates in it would be selling something that has already happened.
The step a hand-built successor forgets is the link: the old season's successor_plan_id is pointed
at the new plan (and a presale window is set if the old season had none), which is what lets current
holders be offered the next season first. Rules are copied forward with their date bounds shifted by
the length of the finished season, so "every pass in September" becomes next September; the slate
itself and any blackouts are not copied, because both name specific windows that have run.
Not idempotent — call it once per season
Every call creates another plan, named after the source with a season number
appended — Match Day Season (Season 2), then (Season 3), and so on — and
re-points the old season's successor at the newest one. Check
pass_series.successor_plan_id on the source with
get_plan before calling; if it is already set, the
next season exists.
Emits plan.created for the new plan. The new season is then
composed and published like any other: add dates with update_plan —
pass_series.window_ids from list_pass_windows, or
pass_series.rules — and put it on sale with publish_plan.
Required ability
project-subscription-plan:create
Input schema
{
"type": "object",
"required": ["plan_id"],
"properties": {
"plan_id": {
"type": "string",
"description": "UUID of the finished pass_series plan to duplicate into its next season."
}
}
}Output shape
{
"data": {
"id": "9e12f0b4-7c3a-4d58-b2e6-0a5f81c4d739",
"project_id": "7f3d1c92-8b45-4e6a-9d21-5c8e0a4b6f13",
"name": "Match Day Season (Season 2)",
"description": "Every home match this season",
"price": "180.00",
"currency": "USD",
"kind": "pass_series",
"cadence": "For all 0 passes",
"active": false,
"created_at": "2026-12-01T09:00:00+00:00",
"pass_series": {
"timezone": null,
"window_count": 0,
"starts_at": null,
"ends_at": null,
"seat_cap": 50,
"seats_remaining": 50,
"successor_plan_id": null
}
}
}The row is the new plan's, in the get_plan shape. active is false
and window_count is 0 until you compose it; starts_at, ends_at and timezone are null
because a slate with no dates has no span. Its own successor_plan_id is null — it is the source
plan whose successor_plan_id now points here.
Example prompts
"Start the next season from plan
c4e82f16-93a7-4d5b-b81c-6e0f27a94d3b."
"The 2026 season ticket has finished — set up the 2027 one with the same price and seat cap, but don't put it on sale yet."
"Duplicate the Match Day Season into Season 2, then add every home window in the new fixture list to it."
Failure modes
VALIDATION_FAILED—plan_idnames a plan whose kind is notpass_series(error.context.plan_idsays which kind it is), or the clone itself is refused (error.context.plan).RESOURCE_NOT_FOUND— unknownplan_id, a plan on another team's project, one outside the token'sscope:project:allow-list, or a plan that has been deleted.AUTHENTICATION_REQUIRED— no authenticated user on the request.TOKEN_MISSING_ABILITY— token lacksproject-subscription-plan:create.
Related
get_plan— checksuccessor_plan_idbefore calling.update_plan— fill the new slate.list_pass_windows— the window ids to fill it with.publish_plan— put the new season on sale.create_plan— build a season from scratch instead.- Plans API — the REST equivalent,
POST /projects/{project}/plans/{plan}/successor. - Pass Series — what the dashboard does and why.
How is this guide?
reorder_plans
Pin the order a project's plans appear in on the portal and in the project's bot, or reset it to the built-in order. Emits plan.order_changed.
update_plan
Change one or more fields of a plan. Partial by design — anything omitted keeps its stored value; the kind is fixed. Emits plan.updated.