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_planpass_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_FAILEDplan_id names a plan whose kind is not pass_series (error.context.plan_id says which kind it is), or the clone itself is refused (error.context.plan).
  • RESOURCE_NOT_FOUND — unknown plan_id, a plan on another team's project, one outside the token's scope:project: allow-list, or a plan that has been deleted.
  • AUTHENTICATION_REQUIRED — no authenticated user on the request.
  • TOKEN_MISSING_ABILITY — token lacks project-subscription-plan:create.

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