Subscriptions API

Manage recurring billing with subscriptions and plans from your server.

Every endpoint needs a server keyand is scoped to the key's merchant. Subscriptions are also scoped to the key's mode: a 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

GET/api/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

GET/api/v1/subscriptions

Scope: subscription.read. Newest first.

ParameterTypeDescription
clientIdnumberFilter by customer
statusstringOne of the statuses above
planIdnumberSubscriptions with an item on this plan
limitnumber1–100, default 25
startingAfternumberCursor: subscriptions older than this id
{
  "object": "list",
  "data": [ { "id": 812, "object": "subscription", "status": "active", "...": "..." } ],
  "hasMore": false
}

Cancel a Subscription

POST/api/v1/subscriptions/{id}/cancel

Scope: 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

POST/api/v1/subscriptions/{id}/pause

Scope: 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

POST/api/v1/subscriptions/{id}/resume

Scope: subscription.update

Reactivates a paused subscription; anything else is a 400. Returns the subscription.

Update Payment Method — not available

POST/api/v1/subscriptions/{id}/update-payment-method
Returns 501 not_implemented. A card on file needs the customer's consent, which your server cannot give for them, and the customer-facing card update is not available yet.

List a Subscription's Invoices

GET/api/v1/subscriptions/{id}/invoices

Scope: 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

POST/api/v1/plans

Scope: 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

GET/api/v1/plans

Scope: 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

GET/api/v1/plans/{id}

Scope: subscriptionplan.read. Returns the plan object.

Update a Plan

PATCH/api/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

DELETE/api/v1/plans/{id}

Scope: subscriptionplan.delete. Discontinues the plan: existing subscriptions keep billing, new ones cannot start. Returns the plan with status: "discontinued".