Version
READ

get_plan

Fetch one plan by UUID — the same kind-tagged row list_plans emits, with its one nested block and its cadence string.

Read one plan in full. The row is the same one list_plans emits, so an agent that found a plan in the list reads exactly the same fields back, and the row update_plan returns after a change is comparable field for field.

Reads go through the plan service, so the tenant scope and the token's scope:project: allow-list both apply. An id the token cannot see answers RESOURCE_NOT_FOUND, indistinguishable from an id that never existed.

`kind` names the ONE block you will find

Every plan carries a kind — subscription, pass or pass_series — and the kind decides which single nested object accompanies it: billing, pass or pass_series. The other two are absent, not null. Read the tag and you know what you are holding; there is no nullable object to probe.

Every row also carries cadence, the human-readable duration the portal and the bot show — "Per Month", "Per 3 Hours", "For all 10 passes". Use it rather than deriving a duration yourself.

The token behind the MCP session must hold it, or the call is refused with TOKEN_MISSING_ABILITY.

The REST endpoint and this tool share one action, so validation, permissions and events are identical.

Annotations

Read-only

It reads and never changes anything.

Arguments

plan_id*string

UUID of the plan to fetch.

What it returns

{  "data": {    "id": "c4e82f16-93a7-4d5b-b81c-6e0f27a94d3b",    "project_id": "7f3d1c92-8b45-4e6a-9d21-5c8e0a4b6f13",    "name": "Premium Monthly",    "description": "All-access pass",    "price": "29.00",    "currency": "USD",    "kind": "subscription",    "cadence": "Per Month",    "active": true,    "sales_cap": 10,    "sales_cap_sold": 3,    "position": 0,    "paused_reason": null,    "created_at": "2026-05-18T10:05:00+00:00",    "billing": {      "billing_cycle": "months",      "billing_cycle_count": 1,      "recurring": true,      "trial_days": 7,      "trial_cardless": false    }  }}

price is a decimal string; currency is an ISO code. The block changes with the kind:

kind: pass

{
  "kind": "pass",
  "cadence": "Per 3 Hours",
  "pass": {
    "timezone": "America/New_York",
    "recurrence": "weekly",
    "sales_cutoff_minutes": 60,
    "sales_cutoff_anchor": "before_start",
    "next_window": {
      "id": "3d5a8c72-b016-4e94-8fa7-61c209d4e738",
      "starts_at": "2026-09-20T13:00:00+00:00",
      "ends_at": "2026-09-20T16:00:00+00:00"
    }
  }
}

pass.next_window is the next window still on sale, in UTC, or null when the schedule has nothing left to sell — which also means the plan is not purchasable right now. For the full schedule call list_pass_windows.

kind: pass_series

{
  "kind": "pass_series",
  "cadence": "For all 10 passes",
  "pass_series": {
    "timezone": "America/New_York",
    "window_count": 10,
    "starts_at": "2026-09-20T13:00:00+00:00",
    "ends_at": "2026-11-29T22:00:00+00:00",
    "seat_cap": 50,
    "seats_remaining": 13,
    "successor_plan_id": null
  }
}

seat_cap and seats_remaining are null on an uncapped season. successor_plan_id is set once start_next_season has run; it is the plan current holders are offered in the presale.

How it fails

RESOURCE_NOT_FOUND

unknown plan_id, a plan on another team's project, one outside the token's

AUTHENTICATION_REQUIRED

no authenticated user on the request.

TOKEN_MISSING_ABILITY

token lacks project-subscription-plan:view.

How is this guide?

Last updated on