> ## Documentation Index
> Fetch the complete documentation index at: https://docs.anny.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Plans & Subscriptions

Manage plan subscriptions — lifecycle, claiming, listing, filtering, and admin operations.

For general conventions, see [JSON-API Conventions](https://docs.anny.co/developers/guides/json-api-conventions.md). For authentication, see [Authentication](https://docs.anny.co/developers/guides/authentication.md).

***

## Prerequisites

* Admin API: Bearer token with admin access + `?o={organization_id}`
* Customer API: Authenticated customer account for claiming subscriptions

***

## Public plan catalog (shop)

The shop subscription page loads **plan groups** from the public organization, then loads plans per group. Groups are morph-owned by the organization or its master. Empty groups and groups with only private plans are omitted.

```http theme={null}
GET /api/v1/organizations/{slug}?include=offered_plan_groups,offered_plan_groups.owner
GET /api/v1/organizations/{slug}/available-plans?filter[groups]={group_id_or_uuid}&include=group
GET /api/v1/organizations/{slug}/available-plans?filter[without_group]=true
```

| Include / filter | Description |
| - | - |
| `include=offered_plan_groups` | Public plan groups that currently have at least one public plan, ordered by `name`. JSON:API ids are group UUIDs. |
| `include=offered_plan_groups.owner` | Sideload the owning organization (this org or its master). |
| `filter[groups]` | Plans in any of the given group **numeric ids or UUIDs**. Shop clients send the UUID from `offered_plan_groups`. |
| `filter[without_group]` | Pass `true` (string) to return ungrouped public plans only. |

Match the web shop: one section per offered group, then an **Other** section for `filter[without_group]=true`. Hide Other when that collection is empty.

> [!WARNING]
>
> Send `filter[without_group]=true` as a **string**. A JSON boolean query value is rejected by the JSON:API decoder.

***

## Subscription Lifecycle

```text theme={null}
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:

```http theme={null}
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:

```http theme={null}
PUT /api/v1/plan-subscriptions/{subscription_id}/cancel?o={org_id}
```

### Revoke Cancellation

Un-cancels a subscription that hasn't yet reached `cancels_at`:

```http theme={null}
PUT /api/v1/plan-subscriptions/{subscription_id}/revoke?o={org_id}
```

### Suspend

Pauses the subscription until a specified date:

```http theme={null}
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](https://docs.anny.co/developers/guides/admin/exports.md).

***

## Listing Subscriptions

Subscriptions are identified by `slug` (not numeric ID).

```http theme={null}
GET {BASE_URL}/plan-subscriptions?o={org_id}
```

### Get Subscriptions for a Customer

```http theme={null}
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):

```http theme={null}
GET {BASE_URL}/customer-accounts/{uuid}/subscriptions
```

Automatically scoped to the authenticated customer account — no `?o=` param needed.

### Search by Customer

```http theme={null}
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 |

```http theme={null}
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 |

```http theme={null}
GET {BASE_URL}/plan-subscriptions?o={org_id}&include=plan,customer,invoices.items
```

***

## Get a Single Subscription

```http theme={null}
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

```json theme={null}
{
  "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 |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.