Subscription
The Subscription object represents a recurring billing relationship with a customer.
A Subscription object represents an ongoing billing relationship where a customer is charged on a recurring basis. Subscriptions are created when a customer purchases a subscription Product and manage the lifecycle of recurring Payments.
Subscriptions track billing intervals, status changes, and link to all associated Payments and Orders. You can use the API to manage subscriptions including updating, pausing, and cancelling them.
Endpoints
| Method | Endpoint | Description |
|---|---|---|
GET | /v0/subscriptions/list | List and filter subscriptions |
POST | /v0/subscriptions/create | Create a new subscription |
GET | /v0/subscriptions/{subscriptionIdOrNumber} | Retrieve a subscription |
PATCH | /v0/subscriptions/{subscriptionIdOrNumber}/update | Update a subscription |
POST | /v0/subscriptions/{subscriptionIdOrNumber}/charge | Charge a subscription immediately |
PATCH | /v0/subscriptions/{subscriptionIdOrNumber}/cancel | Cancel a subscription |
PATCH | /v0/subscriptions/{subscriptionIdOrNumber}/pause-collection | Pause subscription billing |
PATCH | /v0/subscriptions/{subscriptionIdOrNumber}/endTrial | End a trial immediately and start paid billing |
Ending a trial early
A subscription in trialing status can be converted to a paid subscription right away with the
endTrial endpoint. The first invoice is created and charged immediately using the payment method
on file, and the outcome (emails, webhooks, orders) is identical to the trial ending naturally.
The request fails with a 400 if the subscription is not trialing or has no payment method saved.
Multiple line items
The create, update, and charge endpoints accept an items array with up to 20 line items,
so a single subscription can bill several offers together (e.g. a package plus add-ons) while the
invoice and webhook payloads keep the full per-line breakdown.
Because one subscription maps to a single Stripe subscription, all items must be on the same cadence:
- Same currency — every item resolves to the same currency (either explicitly or from its offer).
- Same billing interval — every offer shares the same
intervalandinterval_count. Mixing, for example, a monthly and a yearly offer is rejected with a400rather than failing at Stripe. - No trial — a trial is only applied to single-item subscriptions; multi-item subscriptions start billing immediately.
- No discount codes — discount codes are not supported when a subscription has more than one item.
Requests that violate these rules return a 400 with a descriptive message.
The Subscription object
objectstringObject type identifier. Always "subscription" for Subscription objects.
idstringrequiredSubscription identifier, based on the initial order number.
statusstringrequiredCurrent subscription status. Possible values: active, past_due, canceled, unpaid, incomplete, incomplete_expired, trialing, paused
createdAtinteger | nullUnix timestamp (milliseconds) when the subscription was created.
currentIntervalStartinteger | nullUnix timestamp (milliseconds) when the current billing interval started.
currentIntervalEndinteger | nullUnix timestamp (milliseconds) when the current billing interval ends.
cancelAtIntervalEndbooleanWhether the subscription will cancel at the end of the current interval. Defaults to false.
canceledAtinteger | nullUnix timestamp (milliseconds) when the subscription was cancelled, if applicable.
userIdstring | nullUUID of the subscribed User.
userUser | nullExpanded User object with basic subscriber information.
user properties
objectstringAlways "user".
idstringrequiredUnique identifier (UUID) for this user.
usernamestring | nullUsername of the user.
orderIdstringrequiredUUID of the initial Order that created this subscription.
orderNumberstringrequiredHuman-readable number of the initial order.
orderOrderrequiredExpanded Order object for the initial subscription order.
order properties
objectstringAlways "order".
idstringrequiredUnique identifier (UUID) for this order.
numberstringrequiredHuman-readable order number.
statusstringrequiredCurrent order status.
lastPaymentIdstring | nullUUID of the most recent Payment for this subscription.
lastPaymentNumberstring | nullHuman-readable number of the most recent payment.
lastPaymentPayment | nullExpanded Payment object for the most recent charge.
lastPayment properties
objectstringAlways "payment".
idstringrequiredUnique identifier (UUID) for this payment.
typestringrequiredPayment type: subscription_initial, subscription_interval, subscription_update, subscription_extra
numberstringrequiredHuman-readable payment number.
statusstringrequiredCurrent payment status.
Subscription lifecycle
Example response
{
"status": "success",
"data": {
"subscription": {
"object": "subscription",
"id": "#SUB123DEF456",
"status": "active",
"createdAt": 1705590000000,
"currentIntervalStart": 1708268400000,
"currentIntervalEnd": 1710946800000,
"cancelAtIntervalEnd": false,
"canceledAt": null,
"userId": "123e4567-e89b-12d3-a456-426614174000",
"user": {
"object": "user",
"id": "123e4567-e89b-12d3-a456-426614174000",
"username": "johndoe"
},
"orderId": "550e8400-e29b-41d4-a716-446655440000",
"orderNumber": "#ABC123DEF456",
"order": {
"object": "order",
"id": "550e8400-e29b-41d4-a716-446655440000",
"number": "#ABC123DEF456",
"status": "PAID"
},
"lastPaymentId": "660e8400-e29b-41d4-a716-446655440001",
"lastPaymentNumber": "#PAY789GHI012",
"lastPayment": {
"object": "payment",
"id": "660e8400-e29b-41d4-a716-446655440001",
"type": "subscription_interval",
"number": "#PAY789GHI012",
"status": "PAID"
}
}
}
}Webhook events
| Event | Typical use |
|---|---|
subscription_created | Subscription exists; first payment may still be processing |
payment_success | First or recurring charge succeeded — fulfill here |
subscription_interval | New billing period charged (renewal) |
subscription_updated | Plan change, cancel-at-period-end, trial ended, etc. |
subscription_cancelled | Subscription ended |
See Event types and Webhooks overview for why subscription_created can include PENDING payments and why you should not rely on it alone for access grants.
Related resources
Last updated