Plans API
A plan is what a project sells: the price, the currency, the billing cycle or the dated windows, the eligibility rules and the resources a purchase unlocks.
A plan is what a project sells: the price, the currency, the billing cycle or the dated windows, the eligibility rules and the resources a purchase unlocks. Every plan has a kind that decides its whole shape. A subscription renews on a cycle and carries a billing block; a pass sells one dated access window per purchase and carries a pass block; a pass_series sells a slate of other pass plans' windows in one go and carries a pass_series block. The kind names exactly one block, and the other two are absent.
A plan exists and, separately, is on sale. Publish and unpublish flip active and are how intake is paused while the plan stays on the books and editable; delete removes the row, and is refused while a customer still holds an unfinished window. A sales_cap pauses the plan by itself when it fills, eligibility narrows who may buy, resources are the places the plan grants, and the storefront order and a series' next season are actions of their own. Plans live under a project at /v1/projects/{project}/plans, and POST takes the same discriminated shape the reads return.
Every change announces itself as a plan.* event; a kind: pass plan also emits pass.* events as its windows are scheduled, open and close, and a series emits pass_series.* alongside them.
Background
The shape is a discriminated union
kind is always present, and it names exactly one nested object that accompanies it:
kind | Carries | Sells |
|---|---|---|
subscription | billing | Access that begins at payment and renews on a cycle. |
pass | pass | One dated access window per purchase. |
pass_series | pass_series | A slate of other pass plans' windows, sold once. |
The other two blocks are absent, not null. Presence is a consequence of the tag, never a signal in its own right: read kind and you know what you are holding.
This replaced a nullable
passobject. The previous shape emittedpass: nullon ordinary plans and told consumers to branch on its presence. That is a type tag smuggled in as a presence check: it cannot express a third kind, and it left every integrator inferring the rule. It also emittedbilling_cycle,trial_daysandrecurringon every plan including passes, where they mean nothing. A field that is present and lying is worse than one that is absent, so the cycle fields now appear only on the kind that has a cycle.
Writes mirror reads exactly, so a payload you read back is a payload you can send. The read endpoint shows one worked plan per kind, field by field.
Two axes: existence and availability
DELETE removes the row; publish and unpublish flip active. Prefer unpublish for "pause intake while keeping the plan on the books": members who already joined keep their access either way, and an unpublished plan stays fully editable.
Endpoints
/v1/projects/{project}/plansList a project's plansPOST/v1/projects/{project}/plansCreate a planGET/v1/projects/{project}/plans/{plan}Get a planPATCH/v1/projects/{project}/plans/{plan}Update a planDELETE/v1/projects/{project}/plans/{plan}Delete a planPOST/v1/projects/{project}/plans/{plan}/publishPublish a planPOST/v1/projects/{project}/plans/{plan}/unpublishUnpublish a planPOST/v1/projects/{project}/plans/orderArrange the storefront orderPOST/v1/projects/{project}/plans/{plan}/successorStart the next seasonRelated
How is this guide?
Last updated on