Skip to main content
A plan is what a membership is sold on. It carries its own price, joining fee, billing frequency and session allowance, so creating a membership only has to name the plan and the customer - the plan supplies the rest. Read operations require plans:read. Create, update, retire, and delete operations require plans:write.

Search plans

Requires the plans:read scope.
Query parameters:
  • search (optional) - matches on plan name or description
  • clubId (optional) - only plans limited to that gym
  • sport (optional) - only plans listing that sport, for example padel
  • includeInactive (optional) - true to include retired plans, which are hidden by default
  • limit (optional) - 1 to 100, defaults to 25
  • offset (optional) - defaults to 0
Response:
By default only plans the gym still sells are returned, so everything here can be sold. Add includeInactive=true when you need retired plans as well - to find one you retired and want back, for example. Name matching works like contact search: case-insensitive and cross-script.

Open a plan

Requires the plans:read scope.
Returns the same object as one row of the search response.
Get-by-id returns retired plans too. Resolving an id you already hold is not the same as offering a plan for sale, so a plan you retired stays readable here - and reachable for a PATCH that un-retires it. Only plan search hides retired plans, and only until you pass includeInactive=true.

Create a plan

Requires plans:write. Send an Idempotency-Key so a retry cannot create a duplicate.
validFor.scopes controls which booking resources the plan can cover. Omit a type list to cover every type in that scope. For example, scopes: ["classes"] covers every class type. Add classTypes: [3, 7] to limit it to those class type IDs. An empty validFor creates a generic plan for direct gym entry. It does not make class, area, or instructor bookings free. For a custom billing frequency, send both customPeriod and customPeriodUnit.

Update or retire a plan

Requires plans:write. Send only fields that should change.
Set isActive to false to retire a plan. Existing memberships keep their snapshotted plan details, but the plan is no longer something the gym sells. A retired plan drops out of plan search, so an integration that lists plans stops offering it. It does not disappear:
  • GET /v1/platform/plans/{id} still returns it, with isActive: false.
  • GET /v1/platform/plans?includeInactive=true lists it again alongside the active ones.
  • PATCH with { "isActive": true } puts it back on sale.

Delete a plan

Requires plans:write.
Deletion returns 204 No Content. If memberships or other records still reference the plan, the API returns 409 Conflict. Retire an in-use plan instead of deleting it.

What the fields mean for a sale

Read the plan before selling it and you can show the customer the real total - price plus signupFee - rather than discovering the joining fee after the charge lands.

Next step

Pass the planId to Create a membership.