Subscriptions
| Method & path | Description |
|---|---|
POST /v1/subscriptions | Create and charge the first period |
GET /v1/subscriptions/:id | Retrieve |
POST /v1/subscriptions/:id | Update |
DELETE /v1/subscriptions/:id | Cancel (?at_period_end=true to cancel at period end) |
POST /v1/subscriptions/:id/resume | Resume a paused subscription |
GET /v1/subscriptions | List; filters customer (ID), status |
Create
| Field | Type | Required | Notes |
|---|---|---|---|
customer_id | ULID | yes | |
items | array ≥1 | yes | each { price_id, quantity (default 1), metadata }; all prices must share currency and interval, be active, and belong to non-archived products (price_inactive, product_inactive) |
default_instrument_id | ULID | conditional | defaults to the customer's default method. Required unless a trial starts (400 instrument_required) |
trial_period_days | integer > 0 | no | mutually exclusive with trial_end |
trial_end | timestamp | no | |
metadata, description | no | description ≤500 |
Without a trial, keyed requests return 201 with the committed status: "incomplete" while the
first charge is submitted after commit. Unkeyed creation also commits the subscription, event and
charge intent together, then awaits dispatch. Without a key, the synchronous response is active on
success or incomplete on decline/pending confirmation — a 201 does not mean
the customer has paid; check status and listen for payment.succeeded/payment.failed. Use
an Idempotency-Key so a retried request cannot subscribe the customer twice.
Update
default_instrument_id (or null), items, metadata, description, cancel_at_period_end,
pause_collection and proration_behavior.
Changing items. Replaces all items. New items must keep the subscription's currency and
interval (400 mixed_billing_dimensions), and the subscription must not be canceled,
incomplete or incomplete_expired (409 subscription_not_updatable).
- On an
activesubscription the price difference for the rest of the period is charged first (proration_behavior: "create_prorations", the default). A declined charge returns402 proration_payment_failedand leaves the items unchanged; a pending result holds the change: the items stay as they were until the charge settles, then the new items are applied (a later decline never applies them). While a proration is pending, further item changes return409 proration_in_progress. The charge appears as a payment transaction withproration: true, and the response carries it asproration_transaction. With anIdempotency-Key, the response records a pending transaction and unchanged items; a later decline is a payment event/status change, rather than a402replay. Item revisions prevent an older paid change from overwriting a newer plan; obsolete paid changes are logged for a refund decision. - Mid-period downgrades are rejected with
409 proration_credit_unsupported, because there is no credit balance. Send"proration_behavior": "none"to apply any item change with no charge or credit; items change immediately and the new recurring amount is billed from the next period. trialing,pausedandpast_duesubscriptions change items without any proration charge.
For example, to change items immediately without charging or issuing credit for the remainder of the current period:
{ "items": [{ "price_id": "<new-price-id>", "quantity": 1 }], "proration_behavior": "none" }
The response is 200 with the new items and proration_transaction: null.
Pausing.
{ "pause_collection": { "behavior": "void", "resumes_at": "2027-01-01T00:00:00Z" } }
behavior must be void (paused time is not billed); resumes_at is optional but must be in the
future. Send "pause_collection": null (or call POST /:id/resume) to resume. On resume, if the
paid period has already ended, a new period starts immediately and is charged; if it has not,
the existing period is kept. Both paths, and the scheduler's automatic resume at resumes_at,
emit subscription.resumed. If a scheduled cancellation is already due, resume cancels instead
of starting another period or charging.
Invalid status changes return 409 invalid_status_transition.
Subscription object
{
"object": "subscription", "id": "01…", "customer_id": "01…",
"status": "active",
"default_instrument_id": "01…", "collection_method": "charge_automatically",
"billing_cycle_anchor": "…", "current_period_start": "…", "current_period_end": "…",
"trial_start": null, "trial_end": null,
"next_payment_attempt": null,
"cancel_at": null, "cancel_at_period_end": false, "canceled_at": null, "ended_at": null,
"pause_collection": null, "metadata": {}, "description": null,
"items": [{ "id": "01…", "price_id": "01…", "quantity": 1, "metadata": {} }],
"created_at": "…", "updated_at": "…"
}
next_payment_attempt is set only while past_due. Events: subscription.created,
subscription.updated, subscription.canceled, subscription.paused, subscription.resumed,
subscription.trial_will_end.