# GET /api/v2/customer-subscriptions/{customer_subscription}/items

List a subscription's lines

- MCP id: customer-subscriptions.items.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 one customer subscription's lines in their printed order, `sort_order` ascending.

There is no organisation-wide collection of subscription lines: a line only means anything under the subscription it belongs to, so this nested path is the only way to list them and `filter[customer_subscription_id]` does not exist. A deleted subscription answers `404` for the whole path unless `trashed=with` is passed, which also includes the subscription's deleted lines. Defaults to the summary view; pass `include=customer_subscription` or `include=subscribable` to expand what each line points at.

## Parameters
- customer_subscription (integer, path): The CustomerSubscription's numeric id. Accepts a soft-deleted record.
- 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. This collection's default sort is a display position that changes whenever someone drags the list into a new order in plnnrly, so a page number can skip or repeat a row if the list is reordered between two page requests. These collections rarely exceed one page; for a stable walk, send sort=id and follow links.next without page.
- 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[subscribable_id] (integer, optional): Id of the record this line sells. Send together with `subscribable_type`. Operators: = in null.
- filter[subscribable_type] (string, optional): What kind of record this line sells. Send together with `subscribable_id`.
- 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_subscription_id (integer, required, server-assigned): The subscription this line belongs to. Taken from the path on create and never writable afterwards: a line cannot be moved to another subscription.
- customer_subscription (Ref or CustomerSubscriptionSummary, required): The subscription this line belongs to.
- subscribable_type (string or null, required): The kind of record `subscribable` points at; it says which branch of `subscribable` applies.
- subscribable_id (integer or null, required): The id of the record `subscribable` points at.
- subscribable (Ref or SubscriptionProductSummary or null, required): What this line sells. Rendered as {"id": N} until named in `?include=subscribable`, which additionally requires the read permission and token scope of the `subscription_products` prefix. Lines that bill a hosting domain or a server carry a `subscribable_type` this API publishes no shape for, and keep the {"id": N} form however they are requested; identify those from `subscribable_type` and `subscribable_id` yourself. Null on both halves is a free-text line priced by hand.
- description (string or null, required, multiline): The line text, as printed on the invoice a renewal generates. May contain placeholders such as {{$domain}}; the API publishes the raw stored text and those are resolved only at invoice time.
- quantity (integer, required): Number of units billed per period.
- purchase_price (decimal (2 dp) ≥ 0, required): Cost price per unit, for margin bookkeeping only. It feeds neither generated amount below and appears on no invoice.
- sales_price (decimal (2 dp) ≥ 0, required): Sales price per unit, excluding VAT. This is what actually bills: a renewal copies it into the generated invoice row's unit price.
- vat_rate (integer, required): VAT percentage as a whole number: 21 means 21%.
- vat_amount (decimal (2 dp), required, server-assigned): VAT on this line, computed by the server: quantity x `sales_price` x `vat_rate` / 100. Read-only.
- total_amount (decimal (2 dp), required, server-assigned): Line total including VAT (quantity x `sales_price` plus the VAT above), computed by the server. Note this is the opposite convention from `SalesInvoiceRow.total_amount`, which excludes VAT: adding VAT to this value double-counts it. Read-only.
- sort_order (integer, required, server-assigned): Position of the line within its subscription, and the default sort key. Assigned on create; there is no way to reorder lines through the API. Only the ordering is meaningful: values are not unique across subscriptions.
- exact_item_id (string or null ≤ 255, required): Exact Online article identifier this line bills against. Optional: a renewal falls back to the subscription product's own Exact values and then to the organisation's Exact defaults, so leaving it empty does not break the sync.
- exact_vat_code (string or null ≤ 255, required): Exact Online VAT code, by code rather than by id.
- exact_gl_account (string or null ≤ 255, required): Exact Online general-ledger revenue account for this line.
- exact_cost_center (string or null ≤ 255, required): Exact Online cost-centre code.
- 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. This is also the `ETag` revision: a subscription line has no `version` field.
- deleted_at (timestamp (YYYY-MM-DDThh:mm:ssZ) or null, required): Soft-delete timestamp, `null` while live.
- links (SubscriptionItemLinks, required)
  - self (url, required): The canonical URI of this record.

## 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/1/items' \
  --data-urlencode 'trashed=with' \
  -H 'Authorization: Bearer <token>' \
  -H 'Accept: application/json'
```
