Plans & Subscriptions
Manage plan subscriptions — lifecycle, claiming, listing, filtering, and admin operations.
For general conventions, see JSON-API Conventions. For authentication, see Authentication.
Prerequisites
- Admin API: Bearer token with admin access +
?o={organization_id} - Customer API: Authenticated customer account for claiming subscriptions
Subscription Lifecycle
Created → Claimed → Active → [Suspended] → Cancelled → Expired
Key Date Fields
| Field | Description |
|---|---|
starts_at |
When the subscription begins |
ends_at |
When the subscription ends (null = indefinite) |
canceled_at |
Timestamp of cancellation request |
cancels_at |
When the cancellation takes effect (typically end of billing period) |
suspended_until |
Paused until this date |
auto_renewal |
Whether the subscription renews automatically |
Status Lifecycle
| Status | Condition |
|---|---|
requested |
No approved_at or rejected_at set |
rejected |
rejected_at is set |
planned |
Approved, but starts_at is in the future |
trial |
Approved and within trial period |
active |
Approved, within date range, not suspended/canceled |
canceled |
cancels_at is set and in the future |
expired |
Past ends_at |
suspended |
Temporarily paused |
Claiming a Subscription (Customer)
After a subscription is created (typically through an order), the customer claims it to activate:
GET /api/v1/plan-subscriptions/{subscription_id}/claim
Claiming transfers ownership from the customer record to the authenticated customer account. Subscriptions are initially attached to a customer (business record) and need to be linked to the customer account (login identity) for self-service management.
Admin Operations
Cancel
Sets cancels_at to the end of the current billing period. The subscription remains active until that date:
PUT /api/v1/plan-subscriptions/{subscription_id}/cancel?o={org_id}
Revoke Cancellation
Un-cancels a subscription that hasn't yet reached cancels_at:
PUT /api/v1/plan-subscriptions/{subscription_id}/revoke?o={org_id}
Suspend
Pauses the subscription until a specified date:
PUT /api/v1/plan-subscriptions/{subscription_id}/suspend?o={org_id}
{
"data": {
"type": "plan-subscriptions",
"attributes": {
"suspended_until": "2026-07-01"
}
}
}
Subscription exports are documented with the other admin export endpoints in Exports.
Listing Subscriptions
Subscriptions are identified by slug (not numeric ID).
GET {BASE_URL}/plan-subscriptions?o={org_id}
Get Subscriptions for a Customer
GET {BASE_URL}/customers/{customer_id}/subscriptions?o={org_id}&include=plan&sort=-starts_at&page[number]=1&page[size]=10
For customer accounts (end-user access):
GET {BASE_URL}/customer-accounts/{uuid}/subscriptions
Automatically scoped to the authenticated customer account — no ?o= param needed.
Search by Customer
GET {BASE_URL}/plan-subscriptions?o={org_id}&filter[search]=jane@example.com
Filters
| Filter | Type | Description |
|---|---|---|
filter[status] |
string | active, inactive, requested, planned, trial, canceled |
filter[ids][] |
string[] | Filter by subscription slugs |
filter[organization_id] |
string | Scope to a specific organization (morph ID) |
filter[start_date] |
date | Subscriptions starting after this date |
filter[end_date] |
date | Subscriptions ending before this date |
filter[start_date_range] |
string | Date range for trial_starts_at (format: YYYY-MM-DD,YYYY-MM-DD) |
filter[end_date_range] |
string | Date range for ends_at |
filter[plans] |
string | Filter by plan ID(s) |
filter[search] |
string | Fuzzy search across customer name/email/phone |
filter[utm_source] |
string | UTM source tracking |
filter[utm_medium] |
string | UTM medium tracking |
filter[utm_campaign] |
string | UTM campaign tracking |
Sorting
| Sort parameter | Description |
|---|---|
name |
Subscription/plan name |
starts_at |
Start date |
ends_at |
End date |
created_at |
Creation date |
updated_at |
Last update |
charged_at |
Last charge date |
GET {BASE_URL}/plan-subscriptions?o={org_id}&filter[status]=active&sort=-starts_at
Includes
| Include path | Description |
|---|---|
plan |
The subscription plan |
plan.features |
Plan features |
plan.quotas.feature |
Plan quota limits with feature |
usage |
Current usage records |
usage.feature |
Usage with feature context |
customer |
Linked customer (admin only) |
invoices.items |
Invoices with line items |
invoices.payment |
Invoices with payment details |
payment_setup |
Payment setup configuration |
payment_setup.payments |
Payment setup with payment history |
payment_setup.method |
Payment method details |
owner |
Organization that owns the plan |
document_acceptances.document |
Accepted legal documents |
document_acceptances.file |
Document files |
files |
Attached files |
sent_emails |
Email history |
custom_entries |
Custom field entries |
custom_entries.field |
Custom entries with field definitions |
utm_tracker |
UTM tracking data |
GET {BASE_URL}/plan-subscriptions?o={org_id}&include=plan,customer,invoices.items
Get a Single Subscription
GET {BASE_URL}/plan-subscriptions/{slug}?o={org_id}&include=plan,customer,usage
Append ?include_summary=true to include a usage_summary in the response meta.
Response Schema
Attributes
| Attribute | Type | Description |
|---|---|---|
name |
string | Plan name |
description |
string | Plan description |
status |
string | Computed: active, requested, planned, trial, canceled, expired, suspended, rejected |
price |
number | Base subscription price |
effective_price |
number | Price after discounts |
display_price |
string | Formatted display price |
currency |
string | e.g. "EUR" |
is_net_price |
boolean | Whether price is net |
starts_at |
datetime | Subscription start |
ends_at |
datetime | Subscription end |
trial_starts_at |
datetime | Trial period start |
trial_ends_at |
datetime | Trial period end |
cancels_at |
datetime | Scheduled cancellation date |
canceled_at |
datetime | Actual cancellation timestamp |
suspended_at |
datetime | Suspension start |
suspended_until |
datetime | Suspension end |
approved_at |
datetime | Approval timestamp |
rejected_at |
datetime | Rejection timestamp |
charged_at |
datetime | Last charge timestamp |
next_billed_at |
datetime | Next billing date |
next_action |
string | Next lifecycle action |
next_action_at |
datetime | When next action occurs |
auto_renewal |
boolean | Whether subscription auto-renews |
is_billed_offline |
boolean | Offline billing flag |
billing_email |
string | Override email for billing |
notice_period |
string | Cancellation notice period |
credited_amount |
number | Amount credited |
relative_discount |
number | Percentage discount |
absolute_discount |
number | Fixed discount amount |
signup_fee |
number | One-time signup fee |
created_at |
datetime | Record creation |
Relationships
| Relationship | Type | Description |
|---|---|---|
plan |
plans |
The subscription plan |
subscriber |
polymorphic | Subscribing entity (customer-account or organization) |
customer |
customers |
Linked customer (admin only) |
owner |
polymorphic | Plan owner (organization) |
payment_setup |
payment-setups |
Payment configuration |
invoices |
invoices |
Generated invoices |
usage |
plan-subscription-usages |
Feature usage records |
document_acceptances |
document-acceptances |
Legal document acceptances |
files |
files |
Attached files |
sent_emails |
sent-emails |
Email history |
utm_tracker |
utm-trackers |
UTM tracking data |
Example Response
{
"data": {
"type": "plan-subscriptions",
"id": "abc123-slug",
"attributes": {
"name": "Premium Monthly",
"status": "active",
"price": 29.99,
"effective_price": 29.99,
"currency": "EUR",
"starts_at": "2026-01-01T00:00:00+00:00",
"ends_at": "2027-01-01T00:00:00+00:00",
"auto_renewal": true,
"next_billed_at": "2026-04-01T00:00:00+00:00"
},
"relationships": {
"plan": {
"data": { "type": "plans", "id": "7" }
},
"customer": {
"data": { "type": "customers", "id": "123" }
}
}
}
}
Common Errors
| Error | Cause | Solution |
|---|---|---|
403 — unauthorized |
Missing permissions | Ensure admin token has the required abilities |
422 — subscription not claimable |
Claim attempted on wrong status | Verify subscription status before claiming |