Subscriptions API
Manage recurring billing with subscriptions and plans from your server.
sk_test_ key only sees test subscriptions. Responses use the standard envelope ({ success, errorCode, errorMessage, data }); the examples below show data. Subscriptions are started through a checkout session with paymentType: "subscription" and a subscriptionPlanId.Retrieve a Subscription
/v1/subscriptions/{id}Scope: subscription.read
{
"id": 812,
"object": "subscription",
"status": "active",
"clientId": 4410,
"clientEmail": "[email protected]",
"planId": 37,
"planName": "Pro Monthly",
"amount": 29.99,
"currency": "USD",
"interval": "month",
"intervalCount": 1,
"startDate": "2025-01-01T00:00:00+00:00",
"currentPeriodStart": "2025-01-01T00:00:00+00:00",
"currentPeriodEnd": "2025-02-01T00:00:00+00:00",
"trialEnd": null,
"cancelAtPeriodEnd": false,
"canceledAt": null,
"pausedAt": null,
"hasPaymentMethod": true,
"livemode": true,
"items": [
{ "id": 901, "planId": 37, "planName": "Pro Monthly", "quantity": 1, "amount": 29.99, "currency": "USD" }
]
}Statuses: active, trialing, past_due, unpaid, paused, canceled, pending.
List Subscriptions
/v1/subscriptionsScope: subscription.read. Newest first.
| Parameter | Type | Description |
|---|---|---|
| clientId | number | Filter by customer |
| status | string | One of the statuses above |
| planId | number | Subscriptions with an item on this plan |
| limit | number | 1–100, default 25 |
| startingAfter | number | Cursor: subscriptions older than this id |
{
"object": "list",
"data": [ { "id": 812, "object": "subscription", "status": "active", "...": "..." } ],
"hasMore": false
}Cancel a Subscription
/v1/subscriptions/{id}/cancelScope: subscription.update
{
"cancelAtPeriodEnd": true,
"reason": "Customer requested cancellation"
}With cancelAtPeriodEnd: true (the default) the subscription stays active until the current period ends; false cancels it now. Returns the updated subscription. Cancelling a canceled subscription is a no-op.
Pause a Subscription
/v1/subscriptions/{id}/pauseScope: subscription.update
{
"reason": "Customer travelling"
}Returns the subscription with status: "paused". Pausing a paused or canceled subscription is a 400. There is no scheduled resume date; call resume when billing should restart.
Resume a Subscription
/v1/subscriptions/{id}/resumeScope: subscription.update
Reactivates a paused subscription; anything else is a 400. Returns the subscription.
Update Payment Method — not available
/v1/subscriptions/{id}/update-payment-methodList a Subscription's Invoices
/v1/subscriptions/{id}/invoicesScope: subscription.read. Newest first, up to 100.
{
"object": "list",
"data": [
{
"id": 5531,
"object": "invoice",
"invoiceNumber": "INV-000123",
"status": "paid",
"amount": 29.99,
"amountPaid": 29.99,
"currency": "USD",
"periodStart": "2025-01-01T00:00:00+00:00",
"periodEnd": "2025-02-01T00:00:00+00:00",
"dueDate": "2025-01-01T00:00:00+00:00"
}
],
"hasMore": false
}Plans
Plans define the price and billing interval. Every plan belongs to a subscription product you created in the merchant portal. Plans are shared by test and live keys.
Create a Plan
/v1/plansScope: subscriptionplan.create
{
"productId": 12,
"name": "Pro Monthly",
"description": "Everything in Basic, plus priority support",
"amount": 29.99,
"currency": "USD",
"interval": "month",
"intervalCount": 1,
"active": true
}interval is day, week, month or year. active: false creates a draft. Trials are set per checkout session (trialDays), not on the plan. Returns the plan:
{
"id": 37,
"object": "plan",
"productId": 12,
"name": "Pro Monthly",
"description": "Everything in Basic, plus priority support",
"amount": 29.99,
"currency": "USD",
"interval": "month",
"intervalCount": 1,
"status": "available",
"active": true,
"createdAt": "2025-01-15T10:00:00+00:00"
}List Plans
/v1/plansScope: subscriptionplan.read. Discontinued plans are left out unless includeArchived=true.
{
"object": "list",
"data": [ { "id": 37, "object": "plan", "name": "Pro Monthly", "...": "..." } ],
"hasMore": false
}Retrieve a Plan
/v1/plans/{id}Scope: subscriptionplan.read. Returns the plan object.
Update a Plan
/v1/plans/{id}Scope: subscriptionplan.update
{
"name": "Pro Monthly (2025)",
"description": "Now with API access",
"active": true
}amount, currency, interval and intervalCount cannot be changed; sending them is a 400. Create a new plan and move subscribers instead.Archive a Plan
/v1/plans/{id}Scope: subscriptionplan.delete. Discontinues the plan: existing subscriptions keep billing, new ones cannot start. Returns the plan with status: "discontinued".
Renewals and the Card on File
When a customer starts a subscription through checkout and pays its first invoice by card, we keep that card for the subscription's renewals. The checkout tells the customer this before they pay. The card is attached to the subscription, and to the customer if they have no card yet (hasPaymentMethod: true), and renewals are charged automatically as merchant-initiated payments. A subscription that starts on a free trial has no first payment, so no card is kept at checkout: point the customer to the portal to add one before the trial ends.
Customers
A subscription checkout (paymentType: "subscription") and a portal session need the clientId of one of your customers. Customers have no test/live mode: both keys see the same customers, while their subscriptions and invoices belong to one mode.
Create a Customer
/v1/customersScope: merchantclient.create
{ "email": "[email protected]", "name": "Andre Clarke", "phone": "+18765550100", "externalId": "tenant-9", "metadata": { "tenantId": "t-9" } }Creating is safe to repeat: it returns the customer you already have. Without externalId, that is the one with the same email. With externalId (your own id for the customer, at most 100 characters, e.g. a tenant id), it is the one with that id, never matched by email, so two of your accounts that share a billing email stay separate customers with their own subscriptions and portal.
{ "id": 512, "object": "customer", "email": "[email protected]", "name": "Andre Clarke", "phone": "+18765550100", "externalId": "tenant-9", "metadata": { "tenantId": "t-9" }, "hasPaymentMethod": false, "createdAt": "2026-10-10T14:00:00+00:00" }Find or List Customers
/v1/[email protected]&limit=1Scope: merchantclient.read. ?externalId= finds a customer by your id. Newest first (limit 1–100, default 10), as { "object": "list", "data": [ …customers ], "hasMore": false }. GET /v1/customers/{id} returns one.
Products
Every plan belongs to a subscription product (a plan's productId).
/v1/productsScopes: subscriptionproduct.create; subscriptionproduct.read for GET /v1/products (a list) and GET /v1/products/{id}.
{ "name": "Platform plans", "description": "What businesses pay for the platform" }