What a subscription plan is
A subscription plan is a recurring price and billing cadence: a price in cents, an interval — exactly one ofday, week, month, year — and how many intervals make up one cycle. (The older adverb words daily, weekly, monthly, quarterly, yearly are not accepted; the v1 adverb words must be converted before calling /v2/plans.)
A plan doesn’t have to belong to any product — you can create one on its own — but a subscription checkout needs a product that has an active plan attached. The same plan can be attached to several products at once; nothing about the plan changes per product.
Every subscription line item at checkout carries a plan_id. Gale reads the price and cadence from the plan itself, so a cart never repeats them:
interval or interval_count in the cart metadata on a subscription cart is rejected — cadence comes from the plan only, never from the call.
Subscription plans work whichever way you use Gale — as a custom payment method inside Stripe Elements, or as your payment gateway directly. They live in Gale: a plan is not read from or synced with any other system, so what you set here is exactly what bills.
Creating and managing subscription plans
name and amount are required. amount is the only accepted spelling — there is no amount alias; sending amount instead of amount is rejected. interval must be exactly one of day, week, month, year. currency accepts only uppercase USD — usd is rejected.
currency can only be set on create — it’s rejected on an update. status can only be set on an update, not on create.
source is "gale" for a plan created through this API; it would carry an external provider’s name instead for a plan that originated elsewhere.
Attaching one plan to several products — call attach-plans once per product with the same plan_id:
GET /v2/plans/plan_01K9XYPLAN000000000000000 now returns both products in products[]. detach-plans takes the same body shape and removes the pairing without touching the plan itself.
The list is paginated and its filters are strict. GET /v2/plans takes per_page (default 50, max 200) and page, and reports metadata.pagination with current_page, per_page, total and total_pages — data stays a flat array. A status that isn’t active or archived is a 422, and a product_id that isn’t a product on your account is a 404 PRODUCT_NOT_FOUND — neither comes back as an empty list, so “no results” always means no results.
Editing a plan affects future cycles only. A cycle that has already been charged keeps the amount it was charged at, and there’s no proration. Archiving a plan stops it being used for new subscriptions; subscriptions already running on it keep billing.
Trials aren’t honoured yet
trial_days must be 0 or omitted. Sending a non-zero value is rejected with a 422 at plan creation — the billing engine doesn’t act on trial_days yet, so a plan carrying a trial could never be checked out anyway, and refusing it up front is clearer than accepting it and failing later at checkout.
What changes at checkout
Sendmode: 'subscription' in the cart metadata; every subscription line item carries product_id, quantity, and plan_id — it’s required, not optional. Gale fills in the rest from its own records:
intervalandinterval_countcome from the plan. Sending either in the cart metadata is rejected.pricecomes from the plan, multiplied byquantity. If you do send a price it must match what that works out to, otherwise the call is rejected rather than silently billing a different amount than your checkout page displayed.nameandcurrencycome from the product and its plan.
422 PLAN_NOT_FOUND covers every way a plan reference can fail to resolve: the product has no attached active plan, the plan_id doesn’t exist, it’s archived, it isn’t attached to that product, or it belongs to another merchant. Gale returns the same code for all of these on purpose, rather than leaking which case it was.
Related resources
Elements + PaymentIntent
Your backend hands off to Gale; Stripe is never in the payment path.
Elements + Checkout Session
Stripe orchestrates the charge and owns the subscription object.
Subscription Webhooks
Renewals, failed payments, cancellations and disputes, as they happen.
Custom Payment Methods
Which of the two Stripe integration paths fits.
