Developer docs v0.1.0

Subscriptions

Method & pathDescription
POST /v1/subscriptionsCreate and charge the first period
GET /v1/subscriptions/:idRetrieve
POST /v1/subscriptions/:idUpdate
DELETE /v1/subscriptions/:idCancel (?at_period_end=true to cancel at period end)
POST /v1/subscriptions/:id/resumeResume a paused subscription
GET /v1/subscriptionsList; filters customer (ID), status

Create

FieldTypeRequiredNotes
customer_idULIDyes
itemsarray ≥1yeseach { 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_idULIDconditionaldefaults to the customer's default method. Required unless a trial starts (400 instrument_required)
trial_period_daysinteger > 0nomutually exclusive with trial_end
trial_endtimestampno
metadata, descriptionnodescription ≤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 active subscription the price difference for the rest of the period is charged first (proration_behavior: "create_prorations", the default). A declined charge returns 402 proration_payment_failed and 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 return 409 proration_in_progress. The charge appears as a payment transaction with proration: true, and the response carries it as proration_transaction. With an Idempotency-Key, the response records a pending transaction and unchanged items; a later decline is a payment event/status change, rather than a 402 replay. 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, paused and past_due subscriptions 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.