Subscriptions
Recurring billing, billed in advance.
Concepts, behaviour and examples: Subscriptions guide.
GET /v1/subscriptions
List subscriptions
Cursor-paginated (limit, starting_after).
- Authentication
- Merchant API key
- Effect
- Read-only.
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
limit | integer | no | Page size (1–100). · ≥ 1, ≤ 100, default 20 |
starting_after | string | no | Object ID; return objects after it (ascending ID order). · 26 chars |
customer | string | no | Filter by customer ID. · 26 chars |
status | "incomplete" | "incomplete_expired" | "trialing" | "active" | "past_due" | "unpaid" | "paused" | "canceled" | no | Filter by status. |
Responses
| Status | Meaning | Body / error codes |
|---|---|---|
| 200 | Success. | object |
| 400 | Invalid request. | invalid_query_param |
| 401 | Missing or invalid API key. | authentication_error |
| 429 | Rate limited; honor retry-after. | rate_limit_exceeded too_many_auth_failures |
| 500 | Server error. | api_error |
Example response
{
"object": "list",
"url": "string",
"has_more": false,
"data": [
{
"object": "subscription",
"id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"merchant_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"customer_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"status": "incomplete",
"default_instrument_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"collection_method": "charge_automatically",
"billing_cycle_anchor": "2026-10-25T18:00:00.000Z",
"current_period_start": "2026-10-25T18:00:00.000Z",
"current_period_end": "2026-10-25T18:00:00.000Z",
"trial_start": "2026-10-25T18:00:00.000Z",
"trial_end": "2026-10-25T18:00:00.000Z",
"cancel_at": "2026-10-25T18:00:00.000Z",
"next_payment_attempt": "2026-10-25T18:00:00.000Z",
"cancel_at_period_end": false,
"canceled_at": "2026-10-25T18:00:00.000Z",
"ended_at": "2026-10-25T18:00:00.000Z",
"pause_collection": {
"behavior": "void",
"resumes_at": "2026-10-25T18:00:00.000Z"
},
"metadata": {},
"description": "string",
"items": [
{
"id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"price_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"quantity": 1,
"metadata": {}
}
],
"created_at": "2026-10-25T18:00:00.000Z",
"updated_at": "2026-10-25T18:00:00.000Z"
}
]
}POST /v1/subscriptions
Create a subscription
Bills in advance. Without a trial a pending first charge is committed with the subscription. With an Idempotency-Key the response is incomplete and the charge is submitted after commit; without a key the synchronous response is active on success or incomplete on decline/pending. A 201 does not mean the customer has paid — read status and consume payment.succeeded/payment.failed.
- Authentication
- Merchant API key
- Effect
- Creates the subscription and its first-period charge (none during a trial); emits
subscription.created.
Headers
| Name | Type | Required | Description |
|---|---|---|---|
Idempotency-Key | string | no | Makes retries safe: same key + body replays the stored response (idempotency-replayed: true); a different body returns 409 idempotency_key_in_use. · ≤ 96 chars |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
customer_id | string | yes | ULID · 26 chars |
items | object[] | yes | All prices must share currency and interval, be active, and belong to non-archived products. · ≥ 1 items, ≤ 100 items |
items[].price_id | string | yes | ULID · 26 chars |
items[].quantity | integer | no | ≥ 1, default 1 |
items[].metadata | object | no | Free-form key/value data. Each value ≤16 KiB of JSON, ≤8 nesting levels, ≤100 properties/elements. |
default_instrument_id | string | null | no | Defaults to the customer's default instrument. Required unless a trial starts. · 26 chars |
metadata | object | no | Free-form key/value data. Each value ≤16 KiB of JSON, ≤8 nesting levels, ≤100 properties/elements. |
description | string | no | ≤ 500 chars |
trial_period_days | integer | no | Mutually exclusive with trial_end. · > 0 |
trial_end | string (date-time) | no |
Example request
{
"customer_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"items": [
{
"price_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"quantity": 1,
"metadata": {}
}
],
"default_instrument_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"metadata": {},
"description": "string",
"trial_period_days": 1,
"trial_end": "2026-10-25T18:00:00.000Z"
}Responses
| Status | Meaning | Body / error codes |
|---|---|---|
| 201 | Created (not necessarily paid). | Subscription |
| 400 | Rule violation. | instrument_required price_inactive product_inactive mixed_billing_dimensions instrument_enrollment_required |
| 401 | Missing or invalid API key. | authentication_error |
| 404 | Not found, or not yours. | resource_missing |
| 409 | Another change holds the subscription lock; retry. | subscription_locked |
| 429 | Rate limited; honor retry-after. | rate_limit_exceeded too_many_auth_failures |
| 500 | Server error. | api_error |
Example response
{
"object": "subscription",
"id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"merchant_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"customer_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"status": "incomplete",
"default_instrument_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"collection_method": "charge_automatically",
"billing_cycle_anchor": "2026-10-25T18:00:00.000Z",
"current_period_start": "2026-10-25T18:00:00.000Z",
"current_period_end": "2026-10-25T18:00:00.000Z",
"trial_start": "2026-10-25T18:00:00.000Z",
"trial_end": "2026-10-25T18:00:00.000Z",
"cancel_at": "2026-10-25T18:00:00.000Z",
"next_payment_attempt": "2026-10-25T18:00:00.000Z",
"cancel_at_period_end": false,
"canceled_at": "2026-10-25T18:00:00.000Z",
"ended_at": "2026-10-25T18:00:00.000Z",
"pause_collection": {
"behavior": "void",
"resumes_at": "2026-10-25T18:00:00.000Z"
},
"metadata": {},
"description": "string",
"items": [
{
"id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"price_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"quantity": 1,
"metadata": {}
}
],
"created_at": "2026-10-25T18:00:00.000Z",
"updated_at": "2026-10-25T18:00:00.000Z"
}GET /v1/subscriptions/:id
Retrieve a subscription
- Authentication
- Merchant API key
- Effect
- Read-only.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | string | yes | Object ID (ULID). · 26 chars |
Responses
| Status | Meaning | Body / error codes |
|---|---|---|
| 200 | Success. | Subscription |
| 401 | Missing or invalid API key. | authentication_error |
| 404 | Not found, or not yours. | resource_missing |
| 429 | Rate limited; honor retry-after. | rate_limit_exceeded too_many_auth_failures |
| 500 | Server error. | api_error |
Example response
{
"object": "subscription",
"id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"merchant_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"customer_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"status": "incomplete",
"default_instrument_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"collection_method": "charge_automatically",
"billing_cycle_anchor": "2026-10-25T18:00:00.000Z",
"current_period_start": "2026-10-25T18:00:00.000Z",
"current_period_end": "2026-10-25T18:00:00.000Z",
"trial_start": "2026-10-25T18:00:00.000Z",
"trial_end": "2026-10-25T18:00:00.000Z",
"cancel_at": "2026-10-25T18:00:00.000Z",
"next_payment_attempt": "2026-10-25T18:00:00.000Z",
"cancel_at_period_end": false,
"canceled_at": "2026-10-25T18:00:00.000Z",
"ended_at": "2026-10-25T18:00:00.000Z",
"pause_collection": {
"behavior": "void",
"resumes_at": "2026-10-25T18:00:00.000Z"
},
"metadata": {},
"description": "string",
"items": [
{
"id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"price_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"quantity": 1,
"metadata": {}
}
],
"created_at": "2026-10-25T18:00:00.000Z",
"updated_at": "2026-10-25T18:00:00.000Z"
}POST /v1/subscriptions/:id
Update a subscription
Partial update. Changing items replaces all items; they must keep the subscription's currency and interval. On an active subscription the price difference for the rest of the period is charged first (proration_behavior: create_prorations, default); a declined unkeyed charge returns 402 and leaves items unchanged, a pending result holds the change until it settles. Mid-period downgrades return 409 proration_credit_unsupported — send proration_behavior: none to change items with no charge/credit (billed from the next period). trialing, paused and past_due change items without proration. Pausing: pause_collection: {behavior: "void", resumes_at}; null resumes.
- Authentication
- Merchant API key
- Effect
- Updates the subscription; may create a proration charge, pause or resume it; emits
subscription.updated/paused/resumed.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | string | yes | Object ID (ULID). · 26 chars |
Headers
| Name | Type | Required | Description |
|---|---|---|---|
Idempotency-Key | string | no | Makes retries safe: same key + body replays the stored response (idempotency-replayed: true); a different body returns 409 idempotency_key_in_use. · ≤ 96 chars |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
default_instrument_id | string | null | no | ULID · 26 chars |
items | object[] | no | ≥ 1 items |
items[].price_id | string | yes | ULID · 26 chars |
items[].quantity | integer | no | ≥ 1, default 1 |
items[].metadata | object | no | Free-form key/value data. Each value ≤16 KiB of JSON, ≤8 nesting levels, ≤100 properties/elements. |
metadata | object | no | Free-form key/value data. Each value ≤16 KiB of JSON, ≤8 nesting levels, ≤100 properties/elements. |
description | string | no | ≤ 500 chars |
cancel_at_period_end | boolean | no | |
pause_collection | object | null | no | |
pause_collection.behavior | "void" | yes | |
pause_collection.resumes_at | string (date-time) | no | Optional; must be in the future. |
proration_behavior | "create_prorations" | "none" | no | default "create_prorations" |
Example request
{
"default_instrument_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"items": [
{
"price_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"quantity": 1,
"metadata": {}
}
],
"metadata": {},
"description": "string",
"cancel_at_period_end": false,
"pause_collection": {
"behavior": "void",
"resumes_at": "2026-10-25T18:00:00.000Z"
},
"proration_behavior": "create_prorations"
}Responses
| Status | Meaning | Body / error codes |
|---|---|---|
| 200 | Success. | SubscriptionWithProration |
| 400 | Rule violation. | mixed_billing_dimensions instrument_required price_inactive product_inactive |
| 401 | Missing or invalid API key. | authentication_error |
| 402 | Unkeyed proration charge declined; items unchanged. | proration_payment_failed |
| 404 | Not found, or not yours. | resource_missing |
| 409 | State conflict. | subscription_not_updatable proration_in_progress proration_credit_unsupported invalid_status_transition subscription_locked |
| 429 | Rate limited; honor retry-after. | rate_limit_exceeded too_many_auth_failures |
| 500 | Server error. | api_error |
Example response
{
"object": "subscription",
"id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"merchant_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"customer_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"status": "incomplete",
"default_instrument_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"collection_method": "charge_automatically",
"billing_cycle_anchor": "2026-10-25T18:00:00.000Z",
"current_period_start": "2026-10-25T18:00:00.000Z",
"current_period_end": "2026-10-25T18:00:00.000Z",
"trial_start": "2026-10-25T18:00:00.000Z",
"trial_end": "2026-10-25T18:00:00.000Z",
"cancel_at": "2026-10-25T18:00:00.000Z",
"next_payment_attempt": "2026-10-25T18:00:00.000Z",
"cancel_at_period_end": false,
"canceled_at": "2026-10-25T18:00:00.000Z",
"ended_at": "2026-10-25T18:00:00.000Z",
"pause_collection": {
"behavior": "void",
"resumes_at": "2026-10-25T18:00:00.000Z"
},
"metadata": {},
"description": "string",
"items": [
{
"id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"price_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"quantity": 1,
"metadata": {}
}
],
"created_at": "2026-10-25T18:00:00.000Z",
"updated_at": "2026-10-25T18:00:00.000Z",
"proration_transaction": {
"object": "payment",
"id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"merchant_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"subscription_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"customer_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"instrument_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"amount": 1,
"currency": "RON",
"status": "pending",
"netopia_ntp_id": "string",
"netopia_status_code": 1,
"error_message": "string",
"period_start": "2026-10-25T18:00:00.000Z",
"period_end": "2026-10-25T18:00:00.000Z",
"description": "string",
"metadata": {},
"proration": false,
"review": {
"status": "open",
"reason": "subscription_expired",
"opened_at": "2026-10-25T18:00:00.000Z",
"resolution": "refunded_externally",
"note": "string",
"resolved_at": "2026-10-25T18:00:00.000Z",
"resolved_by_api_key_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C"
},
"created_at": "2026-10-25T18:00:00.000Z",
"payment_link_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"payer_email": "string"
}
}DELETE /v1/subscriptions/:id
Cancel a subscription
Cancels immediately (no refund). With at_period_end=true the paid period is kept and a fixed cancel_at deadline is set; it cancels without a further charge once due.
- Authentication
- Merchant API key
- Effect
- Cancels now (
subscription.canceled) or schedules cancellation (subscription.updated).
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | string | yes | Object ID (ULID). · 26 chars |
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
at_period_end | boolean | no | Cancel at period end instead of now. · default false |
Headers
| Name | Type | Required | Description |
|---|---|---|---|
Idempotency-Key | string | no | Makes retries safe: same key + body replays the stored response (idempotency-replayed: true); a different body returns 409 idempotency_key_in_use. · ≤ 96 chars |
Responses
| Status | Meaning | Body / error codes |
|---|---|---|
| 200 | The canceled or scheduled subscription. | Subscription |
| 401 | Missing or invalid API key. | authentication_error |
| 404 | Not found, or not yours. | resource_missing |
| 409 | State conflict. | invalid_status_transition subscription_locked |
| 429 | Rate limited; honor retry-after. | rate_limit_exceeded too_many_auth_failures |
| 500 | Server error. | api_error |
Example response
{
"object": "subscription",
"id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"merchant_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"customer_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"status": "incomplete",
"default_instrument_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"collection_method": "charge_automatically",
"billing_cycle_anchor": "2026-10-25T18:00:00.000Z",
"current_period_start": "2026-10-25T18:00:00.000Z",
"current_period_end": "2026-10-25T18:00:00.000Z",
"trial_start": "2026-10-25T18:00:00.000Z",
"trial_end": "2026-10-25T18:00:00.000Z",
"cancel_at": "2026-10-25T18:00:00.000Z",
"next_payment_attempt": "2026-10-25T18:00:00.000Z",
"cancel_at_period_end": false,
"canceled_at": "2026-10-25T18:00:00.000Z",
"ended_at": "2026-10-25T18:00:00.000Z",
"pause_collection": {
"behavior": "void",
"resumes_at": "2026-10-25T18:00:00.000Z"
},
"metadata": {},
"description": "string",
"items": [
{
"id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"price_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"quantity": 1,
"metadata": {}
}
],
"created_at": "2026-10-25T18:00:00.000Z",
"updated_at": "2026-10-25T18:00:00.000Z"
}POST /v1/subscriptions/:id/resume
Resume a paused subscription
If the paid period has already ended a new period starts immediately and is charged; otherwise the existing period is kept. A due scheduled cancellation cancels instead.
- Authentication
- Merchant API key
- Effect
- Clears the pause; may start and charge a new period; emits
subscription.resumed.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | string | yes | Object ID (ULID). · 26 chars |
Headers
| Name | Type | Required | Description |
|---|---|---|---|
Idempotency-Key | string | no | Makes retries safe: same key + body replays the stored response (idempotency-replayed: true); a different body returns 409 idempotency_key_in_use. · ≤ 96 chars |
Responses
| Status | Meaning | Body / error codes |
|---|---|---|
| 200 | Success. | Subscription |
| 401 | Missing or invalid API key. | authentication_error |
| 404 | Not found, or not yours. | resource_missing |
| 409 | State conflict. | invalid_status_transition subscription_locked |
| 429 | Rate limited; honor retry-after. | rate_limit_exceeded too_many_auth_failures |
| 500 | Server error. | api_error |
Example response
{
"object": "subscription",
"id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"merchant_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"customer_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"status": "incomplete",
"default_instrument_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"collection_method": "charge_automatically",
"billing_cycle_anchor": "2026-10-25T18:00:00.000Z",
"current_period_start": "2026-10-25T18:00:00.000Z",
"current_period_end": "2026-10-25T18:00:00.000Z",
"trial_start": "2026-10-25T18:00:00.000Z",
"trial_end": "2026-10-25T18:00:00.000Z",
"cancel_at": "2026-10-25T18:00:00.000Z",
"next_payment_attempt": "2026-10-25T18:00:00.000Z",
"cancel_at_period_end": false,
"canceled_at": "2026-10-25T18:00:00.000Z",
"ended_at": "2026-10-25T18:00:00.000Z",
"pause_collection": {
"behavior": "void",
"resumes_at": "2026-10-25T18:00:00.000Z"
},
"metadata": {},
"description": "string",
"items": [
{
"id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"price_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
"quantity": 1,
"metadata": {}
}
],
"created_at": "2026-10-25T18:00:00.000Z",
"updated_at": "2026-10-25T18:00:00.000Z"
}