# GET /api/v2/customer-subscriptions

List customer subscriptions

- MCP id: customer-subscriptions.index
- Scope: api:read:customer_subscriptions
- Permission: customer_subscriptions::read
- Needs the billing feature on your organisation
- Rate cost: 1 unit, read bucket. `view=detail` makes it 3. Adds: each include +1, `q` +2.
- Cache-Control: private, no-store

Returns the organisation's customer subscriptions, newest start date first.

Defaults to the summary view; `view=detail` carries the same fields on this resource (no field of it is detail-only) and costs three read units instead of one. `filter[status]=active` with `filter[auto_renew]=true` and `filter[next_invoice_date][lte]=<today>` is the due-for-invoicing query the renewal run uses. Search with `q=` over the subscription description, and pass `trashed=with|only` to see deleted subscriptions. There is no relationship sort: use `sort=customer_id` or `filter[customer_id]` rather than `customer.name`.

## Parameters
- view (string, optional): Which field set to render.
- per_page (integer 1 to 100, optional): Rows per page. At most 25 when `include` names a to-many relation; a larger value is 400 invalid-query-parameter.
- cursor (string, optional): Opaque keyset cursor from a previous page's links.next. Never construct one by hand.
- page (integer 1 to 1000, optional): Opt in to page-number paging: 1-based, at most 1000. Omit it, the default, to page by opaque cursor, which is what links.next hands you. Cannot be combined with cursor. Published only on collections that count their rows on every request.
- filter[auto_renew] (boolean, optional): Whether the renewal run may invoice the subscription again.
- filter[billing_interval] (string, optional): Interval the subscription is invoiced at. Operators: = ne in.
- filter[cancelled_at] (date (YYYY-MM-DD), optional): Day the subscription was cancelled. `null` selects the ones that were not. Operators: = gte lte null.
- filter[created_at] (timestamp (YYYY-MM-DDThh:mm:ssZ), optional): Creation timestamp. Pair with `sort=id` for a stable full export. Operators: = gte lt.
- filter[customer_id] (integer, optional): Customer the subscription belongs to. This is how you list one customer's subscriptions: there is no nested path for them. Operators: = in.
- filter[expires_at] (date (YYYY-MM-DD), optional): Day the subscription runs out. `null` selects the open-ended ones. Operators: = gte lte null.
- filter[last_invoiced_at] (date (YYYY-MM-DD), optional): Day the subscription was last invoiced. `null` selects the ones that never were. Operators: = gte lte null.
- filter[next_invoice_date] (date (YYYY-MM-DD), optional): First day of the period to be invoiced next. `null` selects the subscriptions the renewal run skips. Combined with `filter[status]=active` and `filter[auto_renew]=true` this is the due-for-invoicing query the renewal run itself uses, and it is the single most useful query on this resource. Operators: = gte lte null.
- filter[starts_at] (date (YYYY-MM-DD), optional): First day the subscription runs from. Combine gte and lte to select a period, e.g. the subscriptions that started in one month. Operators: = gte lte.
- filter[status] (string, optional): Lifecycle status. Only `active` subscriptions are invoiced by the renewal run. Operators: = ne in.
- filter[subscription_product_id] (integer, optional): Subscriptions with at least one line selling this subscription product, which is the Products filter in plnnrly. Lines that bill a hosting domain or a server are not products and never match. Operators: = in.
- filter[subscription_type_id] (integer, optional): Subscription type the subscription is an instance of. Operators: = in.
- filter[updated_at] (timestamp (YYYY-MM-DDThh:mm:ssZ), optional): Last-write timestamp. Use for incremental sync. Operators: = gte lt.
- q (string, optional): Free-text search over `description`. At most one substring match per request: `q` together with a `contains` filter is 400 invalid-query-parameter.
- sort (string, optional): Up to three keys, comma-separated, each optionally prefixed with `-` for descending.
- include (string, optional): Comma-separated names to inline, at most five.
- trashed (string, optional): Whether soft-deleted rows are included.
- X-Request-Id (header, optional): A correlation id of your own. It is recorded in our logs next to the server's request id but never returned: the response header always carries the server's id. A value that does not match the pattern is discarded silently, never rejected.
- If-None-Match (header, optional): The ETag a read is conditional on. A match is answered 304 with no body.

## Response 200
- id (integer, required): Unique identifier.
- customer_id (integer, required): Customer this subscription belongs to.
- customer (Ref or CustomerSummary, required): The customer this subscription belongs to. Expanding it with `?include=customer` additionally requires the `customers::read` permission and a token scope covering the customers prefix.
- subscription_type_id (integer, required): Subscription type this subscription is an instance of.
- subscription_type (Ref or SubscriptionTypeSummary, required): The subscription type this subscription is an instance of, which is also where its displayed name comes from. Expanding it with `?include=subscription_type` additionally requires the `subscription_types::read` permission and a token scope covering the `subscription_types` prefix.
- description (string or null, required, multiline): What this subscription covers, as free text. This is the field `?q=` searches, and it is also what a generated invoice line falls back to.
- status (string, required): Lifecycle status. Only an active subscription is picked up by the renewal run; the other three are inert.
- billing_interval (string, required): How often the subscription is invoiced. one-time forces `auto_renew` to `false`, because a one-off has no next period to move on to.
- starts_at (date (YYYY-MM-DD), required): First day the subscription runs from, as a zone-free calendar date. Newest first is the default sort.
- next_invoice_date (date (YYYY-MM-DD) or null, required): First day of the period to be invoiced next. Omit it on create and the server fills it with `starts_at`, so the first period is billable; the renewal run advances it by one interval each time it invoices. Null makes the subscription invisible to that run (it is skipped, silently), so a subscription that should never auto-invoice is expressed this way.
- cancelled_at (date (YYYY-MM-DD) or null, required): Day the subscription was cancelled, `null` while it has not been. It is a record of the cancellation date only: nothing derives status from it.
- expires_at (date (YYYY-MM-DD) or null, required): Day the subscription runs out, `null` when it is open-ended.
- auto_renew (boolean, required): Whether the renewal run may invoice this subscription again. A one-time subscription is always `false`: it is forced on every save, so sending `true` together with `billing_interval=one-time` succeeds and comes back as `false` rather than failing.
- exact_subscription_id (string or null ≤ 255, required, server-assigned): Exact Online subscription this one maps to, by Exact's own external identifier, not by a local id. Written by the sync; `null` when the subscription has never been synced.
- last_invoiced_at (date (YYYY-MM-DD) or null, required, server-assigned): Day the subscription was last invoiced, `null` until it has been. Maintained by the renewal run.
- created_at (timestamp (YYYY-MM-DDThh:mm:ssZ), required): Creation timestamp.
- updated_at (timestamp (YYYY-MM-DDThh:mm:ssZ), required): Last-write timestamp; use for incremental sync. It also feeds the `ETag` revision, because a customer subscription has no `version` field.
- deleted_at (timestamp (YYYY-MM-DDThh:mm:ssZ) or null, required): Soft-delete timestamp, `null` while live.
- items_count (integer ≥ 0, required): Number of lines on this subscription.
- links (CustomerSubscriptionLinks, required)
  - self (url, required): The canonical URI of this record.
  - items (url, required): Lines on this subscription.

## Errors
- 403 forbidden-by-policy | insufficient-permission | insufficient-token-scope: Forbidden.
- 304 : Not modified.
- 400 idempotency-key-required | invalid-cursor | invalid-query-parameter | malformed-request | unsupported-parameter: Bad request.
- 401 token-expired | unauthenticated: Unauthenticated.
- 404 endpoint-not-found | resource-not-found: Not found.
- 406 not-acceptable: Not acceptable.
- 429 rate-limit-exceeded: Too many requests.
- 500 internal-error: Server error.
- 503 tenant-unavailable: Service unavailable.

## Example
```bash
curl -G \
  'https://<your-url>/api/v2/customer-subscriptions' \
  --data-urlencode 'filter[status]=active' \
  --data-urlencode 'filter[auto_renew]=true' \
  --data-urlencode 'filter[next_invoice_date][lte]=2026-12-31' \
  --data-urlencode 'sort=-starts_at' \
  -H 'Authorization: Bearer <token>' \
  -H 'Accept: application/json'
```
