# Subscriptions tools

> MCP tools for Subscriptions: subscriptions_cancel, subscriptions_create, subscriptions_discounts_create, subscriptions_events_list, subscriptions_get, subscriptions_list, subscriptions_metrics, subscriptions_migrations_create, subscriptions_migrations_get, subscriptions_migrations_list, subscriptions_pause, subscriptions_preview_change, subscriptions_reactivate, subscriptions_resume, subscriptions_update.

- `subscriptions_cancel`: Cancel a subscription
- `subscriptions_create`: Create a subscription
- `subscriptions_discounts_create`: Apply a coupon to a subscription
- `subscriptions_events_list`: List a subscription's history
- `subscriptions_get`: Get a subscription
- `subscriptions_list`: List subscriptions
- `subscriptions_metrics`: Subscription metrics
- `subscriptions_migrations_create`: Migrate subscribers to a new price
- `subscriptions_migrations_get`: Get a price migration
- `subscriptions_migrations_list`: List price migrations
- `subscriptions_pause`: Pause a subscription
- `subscriptions_preview_change`: Preview a subscription change
- `subscriptions_reactivate`: Withdraw a scheduled cancellation
- `subscriptions_resume`: Resume a paused subscription
- `subscriptions_update`: Change plan or quantity of a subscription

## `subscriptions_cancel`

**Cancel a subscription.** Operation [`subscriptions.cancel`](https://ownrecord.io/docs/reference/subscriptions-cancel.md) · Brand level · permission `subscriptions:write` · risk tier `financial` · since M5

Ends a subscription.

- `mode: at_period_end` (default): it stays active until the current period ends (`cancelAt`), then ends;
  `subscriptions.reactivate` withdraws the cancellation until then. Emits `subscription.cancel_scheduled`.
- `mode: now`: it ends at once. With `prorate: true` the unused time of the current period goes to the
  customer's credit balance (at the prices' amounts, discounts taken into account). With `invoiceNow` (default)
  the metered usage up to now and any pending items are invoiced in a final invoice, which the credit balance
  reduces. An incomplete subscription's unpaid first invoice is voided. Emits `subscription.canceled`.

`mode: now` with `refund: true` refunds the unused time of the current period to the customer's card instead:
every paid invoice of the subscription with time left gets a credit note at its original tax rates and a
refund (`refunds.create` with `subscription_prorated`; you need the refund permission, and support's refund
limit applies). An invoice paid by bank transfer or from the credit balance can't be refunded that way
(`subscription_refund_not_supported`: cancel with `prorate: true` instead).

`feedback` and `comment` record why the customer left. The customer's entitlements are recomputed.

The customer is emailed that the subscription is set to end or has ended. `reason: replaced` says another
subscription of the same customer takes its place (for example an upgrade bought through a new checkout): it is
recorded as `cancellation.reason: replaced`, the webhook events go out as usual, and the customer gets no
cancellation email, since the new subscription's own emails tell them what runs.

Annotations: `readOnlyHint: false` · `destructiveHint: true` · `idempotentHint: false` · `openWorldHint: true`

### Arguments

| Argument          | Type                                                                                                                                | Required | Description                                                                                                                                                                                                                                                                             |
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`              | ID (`sub_…`)                                                                                                                        | yes      | –                                                                                                                                                                                                                                                                                       |
| `expectedVersion` | integer                                                                                                                             | no       | (1–9007199254740991)                                                                                                                                                                                                                                                                    |
| `mode`            | one of `at_period_end`, `now`                                                                                                       | no       | `at_period_end` (default; it can be reactivated until then) or `now`. (default `"at_period_end"`)                                                                                                                                                                                       |
| `prorate`         | boolean                                                                                                                             | no       | `now`: credit the unused time of the current period to the customer's credit balance. (default `false`)                                                                                                                                                                                 |
| `refund`          | boolean                                                                                                                             | no       | `now`: refund the unused time of the current period to the customer's card, with a credit note (needs the refund permission). (default `false`)                                                                                                                                         |
| `invoiceNow`      | boolean                                                                                                                             | no       | `now`: invoice the metered usage and pending items up to now in a final invoice. (default `true`)                                                                                                                                                                                       |
| `feedback`        | one of `too_expensive`, `missing_features`, `switched_service`, `unused`, `customer_service`, `too_complex`, `low_quality`, `other` | no       | Why the customer is leaving.                                                                                                                                                                                                                                                            |
| `comment`         | string                                                                                                                              | no       | (1–500 characters)                                                                                                                                                                                                                                                                      |
| `by`              | one of `customer`, `operator`, `system`                                                                                             | no       | Who asked: `customer` or `operator` (default `operator`).                                                                                                                                                                                                                               |
| `reason`          | one of `cancellation_requested`, `replaced`                                                                                         | no       | `cancellation_requested` (default; the customer is emailed that it ends) or `replaced`: another subscription of the same customer takes its place (an upgrade bought through a new checkout), so the customer isn't emailed about this one ending. (default `"cancellation_requested"`) |
| `entity_id`       | ID (`ent_…`)                                                                                                                        | no       | Optional: the brand's legal entity (ent\_…); `brand_id` alone is enough.                                                                                                                                                                                                                |
| `brand_id`        | ID (`brd_…`)                                                                                                                        | no       | The brand to act on (brd\_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand.                                                                                                                                                |
| `idempotency_key` | string                                                                                                                              | no       | A unique string for this change. Retrying with the same key and arguments never acts twice. When left out, the server generates one and returns it in the result's `idempotency_key`. (1–255 characters)                                                                                |
| `dry_run`         | boolean                                                                                                                             | no       | true: check permissions and rules and compute the result, then roll everything back. Nothing is saved. (default `false`)                                                                                                                                                                |

- **Brand:** pass `brand_id` with an organization or entity key; a brand key acts on its own brand.
- **Idempotency:** the result returns the `idempotency_key` used, yours or one the server generated. Retry with it: a call with the same key and arguments never acts twice (keys are kept for 24 hours).
- **Dry run:** supported. `dry_run: true` checks permissions and rules and computes the result, then rolls everything back.

### Errors

- [`validation_failed`](https://ownrecord.io/docs/reference/errors.md#validation_failed): A field is malformed or out of range.
- [`resource_not_found`](https://ownrecord.io/docs/reference/errors.md#resource_not_found): No subscription (or customer, price, coupon) with this ID is visible to the request.
- [`version_conflict`](https://ownrecord.io/docs/reference/errors.md#version_conflict): The subscription changed since you read it (`expectedVersion`), or at the same time; read it and retry.
- [`subscription_status_invalid`](https://ownrecord.io/docs/reference/errors.md#subscription_status_invalid): The subscription's status doesn't allow this (spec §16.1): see `details.reason`.
- [`subscription_refund_not_supported`](https://ownrecord.io/docs/reference/errors.md#subscription_refund_not_supported): `refund: true`, and an invoice with time left wasn't paid by card (bank transfer or credit balance): use `prorate: true`.
- [`refund_limit_exceeded`](https://ownrecord.io/docs/reference/errors.md#refund_limit_exceeded): `refund: true` by the support role, above the brand's refund limit: finance cancels it.
- [`registration_required`](https://ownrecord.io/docs/reference/errors.md#registration_required): An invoice issued now can't be taxed: the seller isn't registered where the customer is (a new sale).
- [`jurisdiction_blocked`](https://ownrecord.io/docs/reference/errors.md#jurisdiction_blocked): The customer's location is blocked for new sales.
- [`evidence_conflict`](https://ownrecord.io/docs/reference/errors.md#evidence_conflict): The customer's stored location evidence isn't enough to tax an invoice issued now (§13.3).
- [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied): The credentials can't change this brand's subscriptions (`subscriptions:write`).

### Examples

**Cancel at the end of the period**

Arguments:

```json
{
  "id": "sub_01m4tx5nj8emwbyf7y9vcf47z5",
  "feedback": "too_expensive",
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
  "idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
```

Result `output`:

```json
{
  "id": "sub_01m4tx5nj8emwbyf7y9vcf47z5",
  "object": "subscription",
  "livemode": false,
  "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47zm",
  "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
  "customerId": "cus_01m4tx5nj8emwbyf7y9vcf47z4",
  "status": "active",
  "items": [
    {
      "id": "si_01m4tx5nj8emwbyf7y9vcf47za",
      "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y2",
      "productId": "prod_01m4tx5nj8emwbyf7y9vcf47y0",
      "quantity": 3,
      "createdAt": "2026-10-13T12:00:00.000Z"
    },
    {
      "id": "si_01m4tx5nj8emwbyf7y9vcf47zb",
      "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y9",
      "productId": "prod_01m4tx5nj8emwbyf7y9vcf47y1",
      "quantity": 1,
      "createdAt": "2026-10-13T12:00:00.000Z"
    }
  ],
  "currency": "EUR",
  "mrr": {
    "amount": "87000000",
    "currency": "EUR"
  },
  "collectionMethod": "charge_automatically",
  "daysUntilDue": null,
  "defaultPaymentMethodId": "pm_01m4tx5nj8emwbyf7y9vcf47zd",
  "billingCycleAnchor": "2026-10-13T12:00:00.000Z",
  "currentPeriodStart": "2026-10-13T12:00:00.000Z",
  "currentPeriodEnd": "2026-11-13T12:00:00.000Z",
  "trialStart": null,
  "trialEnd": null,
  "trialEndBehavior": "convert",
  "cancelAtPeriodEnd": true,
  "cancelAt": "2026-11-13T12:00:00.000Z",
  "canceledAt": null,
  "endedAt": null,
  "cancellation": {
    "reason": "cancellation_requested",
    "feedback": "too_expensive",
    "comment": null,
    "by": "operator"
  },
  "pause": null,
  "discountIds": [],
  "pendingUpdate": null,
  "latestInvoiceId": "inv_01m4tx5nj8emwbyf7y9vcf47zn",
  "incompleteExpiresAt": null,
  "testClockId": null,
  "dunning": null,
  "usageThreshold": null,
  "entitlementGraceUntil": null,
  "metadata": {
    "crm_account": "A-1042"
  },
  "version": 3,
  "createdAt": "2026-10-13T12:00:00.000Z",
  "updatedAt": "2026-10-20T09:00:00.000Z"
}
```

**Cancel now and credit the unused time**

Arguments:

```json
{
  "id": "sub_01m4tx5nj8emwbyf7y9vcf47z5",
  "mode": "now",
  "prorate": true,
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
  "idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
```

Result `output`:

```json
{
  "id": "sub_01m4tx5nj8emwbyf7y9vcf47z5",
  "object": "subscription",
  "livemode": false,
  "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47zm",
  "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
  "customerId": "cus_01m4tx5nj8emwbyf7y9vcf47z4",
  "status": "canceled",
  "items": [
    {
      "id": "si_01m4tx5nj8emwbyf7y9vcf47za",
      "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y2",
      "productId": "prod_01m4tx5nj8emwbyf7y9vcf47y0",
      "quantity": 3,
      "createdAt": "2026-10-13T12:00:00.000Z"
    },
    {
      "id": "si_01m4tx5nj8emwbyf7y9vcf47zb",
      "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y9",
      "productId": "prod_01m4tx5nj8emwbyf7y9vcf47y1",
      "quantity": 1,
      "createdAt": "2026-10-13T12:00:00.000Z"
    }
  ],
  "currency": "EUR",
  "mrr": {
    "amount": "87000000",
    "currency": "EUR"
  },
  "collectionMethod": "charge_automatically",
  "daysUntilDue": null,
  "defaultPaymentMethodId": "pm_01m4tx5nj8emwbyf7y9vcf47zd",
  "billingCycleAnchor": "2026-10-13T12:00:00.000Z",
  "currentPeriodStart": "2026-10-13T12:00:00.000Z",
  "currentPeriodEnd": "2026-11-13T12:00:00.000Z",
  "trialStart": null,
  "trialEnd": null,
  "trialEndBehavior": "convert",
  "cancelAtPeriodEnd": false,
  "cancelAt": null,
  "canceledAt": "2026-10-20T09:00:00.000Z",
  "endedAt": "2026-10-20T09:00:00.000Z",
  "cancellation": {
    "reason": "cancellation_requested",
    "feedback": null,
    "comment": null,
    "by": "operator"
  },
  "pause": null,
  "discountIds": [],
  "pendingUpdate": null,
  "latestInvoiceId": "inv_01m4tx5nj8emwbyf7y9vcf47zn",
  "incompleteExpiresAt": null,
  "testClockId": null,
  "dunning": null,
  "usageThreshold": null,
  "entitlementGraceUntil": null,
  "metadata": {
    "crm_account": "A-1042"
  },
  "version": 3,
  "createdAt": "2026-10-13T12:00:00.000Z",
  "updatedAt": "2026-10-20T09:00:00.000Z"
}
```

**End a subscription another one replaced**

The customer upgraded through a new checkout: the old plan ends now, without an email.

Arguments:

```json
{
  "id": "sub_01m4tx5nj8emwbyf7y9vcf47z5",
  "mode": "now",
  "reason": "replaced",
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
  "idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
```

Result `output`:

```json
{
  "id": "sub_01m4tx5nj8emwbyf7y9vcf47z5",
  "object": "subscription",
  "livemode": false,
  "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47zm",
  "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
  "customerId": "cus_01m4tx5nj8emwbyf7y9vcf47z4",
  "status": "canceled",
  "items": [
    {
      "id": "si_01m4tx5nj8emwbyf7y9vcf47za",
      "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y2",
      "productId": "prod_01m4tx5nj8emwbyf7y9vcf47y0",
      "quantity": 3,
      "createdAt": "2026-10-13T12:00:00.000Z"
    },
    {
      "id": "si_01m4tx5nj8emwbyf7y9vcf47zb",
      "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y9",
      "productId": "prod_01m4tx5nj8emwbyf7y9vcf47y1",
      "quantity": 1,
      "createdAt": "2026-10-13T12:00:00.000Z"
    }
  ],
  "currency": "EUR",
  "mrr": {
    "amount": "87000000",
    "currency": "EUR"
  },
  "collectionMethod": "charge_automatically",
  "daysUntilDue": null,
  "defaultPaymentMethodId": "pm_01m4tx5nj8emwbyf7y9vcf47zd",
  "billingCycleAnchor": "2026-10-13T12:00:00.000Z",
  "currentPeriodStart": "2026-10-13T12:00:00.000Z",
  "currentPeriodEnd": "2026-11-13T12:00:00.000Z",
  "trialStart": null,
  "trialEnd": null,
  "trialEndBehavior": "convert",
  "cancelAtPeriodEnd": false,
  "cancelAt": null,
  "canceledAt": "2026-10-20T09:00:00.000Z",
  "endedAt": "2026-10-20T09:00:00.000Z",
  "cancellation": {
    "reason": "replaced",
    "feedback": null,
    "comment": null,
    "by": "operator"
  },
  "pause": null,
  "discountIds": [],
  "pendingUpdate": null,
  "latestInvoiceId": "inv_01m4tx5nj8emwbyf7y9vcf47zn",
  "incompleteExpiresAt": null,
  "testClockId": null,
  "dunning": null,
  "usageThreshold": null,
  "entitlementGraceUntil": null,
  "metadata": {
    "crm_account": "A-1042"
  },
  "version": 3,
  "createdAt": "2026-10-13T12:00:00.000Z",
  "updatedAt": "2026-10-20T09:00:00.000Z"
}
```

## `subscriptions_create`

**Create a subscription.** Operation [`subscriptions.create`](https://ownrecord.io/docs/reference/subscriptions-create.md) · Brand level · permission `subscriptions:write` · risk tier `financial` · since M5

Starts a subscription of a customer to one or more recurring prices (spec §16.2). The prices must share a
currency, and their intervals must be whole multiples of each other (monthly with yearly). A customer has at
most one live item per metered price's meter.

- **Trial:** `trialEnd`, else `trialDays` (0 = none), else the prices' shortest trial. The subscription is
  `trialing` and nothing is invoiced until the trial ends; free plans have no trial.
- **Free plans** (only zero-amount licensed prices) are `active` at once, with no invoice and no payment method.
- **First invoice:** licensed items for the first period, with the coupon or promotion code applied, taxed now
  with the customer's stored location evidence (a new sale: a blocked location is refused). A later
  `billingCycleAnchor` bills a prorated first period (`prorationBehavior: none` bills nothing until then). A
  zero total isn't issued.
- **Collection:** `charge_automatically` charges the invoice to the customer's saved payment method
  (`paymentMethodId`, else their default): the subscription is `incomplete` until the payment succeeds (23
  hours at most). Without a saved payment method the answer carries `paymentSetup.url`, a hosted checkout in
  setup mode where the customer saves one; the first invoice is charged right after. `send_invoice` emails the
  invoice with the bank transfer details and is `active` at once.

Emits `subscription.created` (and `invoice.issued`/`invoice.finalized` for the first invoice); the customer's
entitlements are recomputed. Dry-run it to see the first invoice before charging anyone.

Annotations: `readOnlyHint: false` · `destructiveHint: false` · `idempotentHint: false` · `openWorldHint: true`

### Arguments

| Argument             | Type                                                                          | Required | Description                                                                                                                                                                                              |
| -------------------- | ----------------------------------------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `customerId`         | ID (`cus_…`)                                                                  | yes      | The customer (`cus_…`).                                                                                                                                                                                  |
| `items`              | array of object                                                               | yes      | The recurring prices: one currency; intervals that are whole multiples of each other. (1–20 items)                                                                                                       |
| `collectionMethod`   | one of `charge_automatically`, `send_invoice`                                 | no       | `charge_automatically` (the default payment method is charged) or `send_invoice` (the invoice is emailed with bank transfer details and paid by the due date). (default `"charge_automatically"`)        |
| `daysUntilDue`       | integer                                                                       | no       | `send_invoice`: days from an invoice's issue date to its due date (default 14). (0–365)                                                                                                                  |
| `trialDays`          | integer                                                                       | no       | Trial days (0 = no trial). Default: the shortest trial of the prices. (0–730)                                                                                                                            |
| `trialEnd`           | date-time (ISO 8601)                                                          | no       | When the trial ends (instead of `trialDays`).                                                                                                                                                            |
| `trialEndBehavior`   | one of `convert`, `cancel_if_no_payment_method`, `pause_if_no_payment_method` | no       | What happens at the trial's end without a payment method: `convert` (bill anyway), `cancel_if_no_payment_method` or `pause_if_no_payment_method`. (default `"convert"`)                                  |
| `couponId`           | ID (`cpn_…`)                                                                  | no       | A coupon to apply (`cpn_…`).                                                                                                                                                                             |
| `promotionCode`      | string                                                                        | no       | A promotion code as the customer typed it (case doesn't matter). (1–50 characters)                                                                                                                       |
| `billingCycleAnchor` | date-time (ISO 8601)                                                          | no       | When the first full period starts (default: now, or the trial's end). A later anchor bills a prorated first period.                                                                                      |
| `prorationBehavior`  | one of `create_prorations`, `always_invoice`, `none`                          | no       | With a later `billingCycleAnchor`: `create_prorations` and `always_invoice` charge the partial first period now; `none` bills nothing until the anchor. (default `"create_prorations"`)                  |
| `paymentMethodId`    | ID (`pm_…`)                                                                   | no       | A saved payment method of the customer (`pm_…`); default: the customer's default method.                                                                                                                 |
| `setupSuccessUrl`    | string                                                                        | no       | Without a payment method (`charge_automatically`): where the setup checkout sends the customer after saving one. (at most 2000 characters)                                                               |
| `usageThreshold`     | object                                                                        | no       | Invoice metered usage as soon as what it would charge reaches this amount (spec §16.7): limits the credit risk of usage-heavy customers. In the subscription's currency, whole minor units.              |
| `metadata`           | object                                                                        | no       | Your own key-value pairs (at most 50 keys). On updates the whole set is replaced.                                                                                                                        |
| `entity_id`          | ID (`ent_…`)                                                                  | no       | Optional: the brand's legal entity (ent\_…); `brand_id` alone is enough.                                                                                                                                 |
| `brand_id`           | ID (`brd_…`)                                                                  | no       | The brand to act on (brd\_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand.                                                                 |
| `idempotency_key`    | string                                                                        | no       | A unique string for this change. Retrying with the same key and arguments never acts twice. When left out, the server generates one and returns it in the result's `idempotency_key`. (1–255 characters) |
| `dry_run`            | boolean                                                                       | no       | true: check permissions and rules and compute the result, then roll everything back. Nothing is saved. (default `false`)                                                                                 |

- **Brand:** pass `brand_id` with an organization or entity key; a brand key acts on its own brand.
- **Idempotency:** the result returns the `idempotency_key` used, yours or one the server generated. Retry with it: a call with the same key and arguments never acts twice (keys are kept for 24 hours).
- **Dry run:** supported. `dry_run: true` checks permissions and rules and computes the result, then rolls everything back.
- **Plan feature:** needs `subscriptions.enabled`.

### Errors

- [`validation_failed`](https://ownrecord.io/docs/reference/errors.md#validation_failed): A field is malformed or out of range.
- [`resource_not_found`](https://ownrecord.io/docs/reference/errors.md#resource_not_found): No subscription (or customer, price, coupon) with this ID is visible to the request.
- [`customer_deleted`](https://ownrecord.io/docs/reference/errors.md#customer_deleted): The customer was deleted.
- [`subscription_price_invalid`](https://ownrecord.io/docs/reference/errors.md#subscription_price_invalid): A price isn't recurring, is archived, is in another currency, or its interval doesn't combine with the others.
- [`subscription_meter_conflict`](https://ownrecord.io/docs/reference/errors.md#subscription_meter_conflict): The customer already has a live subscription item for a metered price's meter.
- [`subscription_payment_method_invalid`](https://ownrecord.io/docs/reference/errors.md#subscription_payment_method_invalid): `paymentMethodId` isn't a saved, attached payment method of the customer.
- [`subscription_anchor_invalid`](https://ownrecord.io/docs/reference/errors.md#subscription_anchor_invalid): `billingCycleAnchor` is before the start or too far ahead.
- [`coupon_not_redeemable`](https://ownrecord.io/docs/reference/errors.md#coupon_not_redeemable): The coupon is archived, expired or used up.
- [`promotion_code_not_redeemable`](https://ownrecord.io/docs/reference/errors.md#promotion_code_not_redeemable): The promotion code can't be used for this customer or amount (`details.reason`).
- [`registration_required`](https://ownrecord.io/docs/reference/errors.md#registration_required): An invoice issued now can't be taxed: the seller isn't registered where the customer is (a new sale).
- [`jurisdiction_blocked`](https://ownrecord.io/docs/reference/errors.md#jurisdiction_blocked): The customer's location is blocked for new sales.
- [`evidence_conflict`](https://ownrecord.io/docs/reference/errors.md#evidence_conflict): The customer's stored location evidence isn't enough to tax an invoice issued now (§13.3).
- [`invoice_bank_transfer_missing`](https://ownrecord.io/docs/reference/errors.md#invoice_bank_transfer_missing): `send_invoice`: the entity has no bank transfer details to put on the first invoice.
- [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied): The credentials can't change this brand's subscriptions (`subscriptions:write`).
- [`entitlement_required`](https://ownrecord.io/docs/reference/errors.md#entitlement_required): The organization's plan doesn't include subscriptions (`subscriptions.enabled`).
- [`org_suspended`](https://ownrecord.io/docs/reference/errors.md#org_suspended): Live mode, while the organization is suspended (§37.5).

### Examples

**Three seats and metered API calls, charged to the saved card**

Arguments:

```json
{
  "customerId": "cus_01m4tx5nj8emwbyf7y9vcf47z4",
  "items": [
    {
      "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y2",
      "quantity": 3
    },
    {
      "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y9"
    }
  ],
  "metadata": {
    "crm_account": "A-1042"
  },
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
  "idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
```

Result `output`:

```json
{
  "id": "sub_01m4tx5nj8emwbyf7y9vcf47z5",
  "object": "subscription",
  "livemode": false,
  "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47zm",
  "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
  "customerId": "cus_01m4tx5nj8emwbyf7y9vcf47z4",
  "status": "incomplete",
  "items": [
    {
      "id": "si_01m4tx5nj8emwbyf7y9vcf47za",
      "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y2",
      "productId": "prod_01m4tx5nj8emwbyf7y9vcf47y0",
      "quantity": 3,
      "createdAt": "2026-10-13T12:00:00.000Z"
    },
    {
      "id": "si_01m4tx5nj8emwbyf7y9vcf47zb",
      "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y9",
      "productId": "prod_01m4tx5nj8emwbyf7y9vcf47y1",
      "quantity": 1,
      "createdAt": "2026-10-13T12:00:00.000Z"
    }
  ],
  "currency": "EUR",
  "mrr": {
    "amount": "87000000",
    "currency": "EUR"
  },
  "collectionMethod": "charge_automatically",
  "daysUntilDue": null,
  "defaultPaymentMethodId": "pm_01m4tx5nj8emwbyf7y9vcf47zd",
  "billingCycleAnchor": "2026-10-13T12:00:00.000Z",
  "currentPeriodStart": "2026-10-13T12:00:00.000Z",
  "currentPeriodEnd": "2026-11-13T12:00:00.000Z",
  "trialStart": null,
  "trialEnd": null,
  "trialEndBehavior": "convert",
  "cancelAtPeriodEnd": false,
  "cancelAt": null,
  "canceledAt": null,
  "endedAt": null,
  "cancellation": null,
  "pause": null,
  "discountIds": [],
  "pendingUpdate": null,
  "latestInvoiceId": "inv_01m4tx5nj8emwbyf7y9vcf47zn",
  "incompleteExpiresAt": "2026-10-14T11:00:00.000Z",
  "testClockId": null,
  "dunning": null,
  "usageThreshold": null,
  "entitlementGraceUntil": null,
  "metadata": {
    "crm_account": "A-1042"
  },
  "version": 2,
  "createdAt": "2026-10-13T12:00:00.000Z",
  "updatedAt": "2026-10-13T12:00:00.000Z",
  "paymentSetup": null
}
```

**A 14-day trial without a saved card**

The trial starts at once; `paymentSetup.url` lets the customer add a card before it ends.

Arguments:

```json
{
  "customerId": "cus_01m4tx5nj8emwbyf7y9vcf47z4",
  "items": [
    {
      "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y2",
      "quantity": 3
    }
  ],
  "trialDays": 14,
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
  "idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
```

Result `output`:

```json
{
  "id": "sub_01m4tx5nj8emwbyf7y9vcf47z5",
  "object": "subscription",
  "livemode": false,
  "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47zm",
  "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
  "customerId": "cus_01m4tx5nj8emwbyf7y9vcf47z4",
  "status": "trialing",
  "items": [
    {
      "id": "si_01m4tx5nj8emwbyf7y9vcf47za",
      "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y2",
      "productId": "prod_01m4tx5nj8emwbyf7y9vcf47y0",
      "quantity": 3,
      "createdAt": "2026-10-13T12:00:00.000Z"
    },
    {
      "id": "si_01m4tx5nj8emwbyf7y9vcf47zb",
      "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y9",
      "productId": "prod_01m4tx5nj8emwbyf7y9vcf47y1",
      "quantity": 1,
      "createdAt": "2026-10-13T12:00:00.000Z"
    }
  ],
  "currency": "EUR",
  "mrr": {
    "amount": "87000000",
    "currency": "EUR"
  },
  "collectionMethod": "charge_automatically",
  "daysUntilDue": null,
  "defaultPaymentMethodId": null,
  "billingCycleAnchor": "2026-10-27T12:00:00.000Z",
  "currentPeriodStart": "2026-10-13T12:00:00.000Z",
  "currentPeriodEnd": "2026-10-27T12:00:00.000Z",
  "trialStart": "2026-10-13T12:00:00.000Z",
  "trialEnd": "2026-10-27T12:00:00.000Z",
  "trialEndBehavior": "convert",
  "cancelAtPeriodEnd": false,
  "cancelAt": null,
  "canceledAt": null,
  "endedAt": null,
  "cancellation": null,
  "pause": null,
  "discountIds": [],
  "pendingUpdate": null,
  "latestInvoiceId": null,
  "incompleteExpiresAt": null,
  "testClockId": null,
  "dunning": null,
  "usageThreshold": null,
  "entitlementGraceUntil": null,
  "metadata": {
    "crm_account": "A-1042"
  },
  "version": 1,
  "createdAt": "2026-10-13T12:00:00.000Z",
  "updatedAt": "2026-10-13T12:00:00.000Z",
  "paymentSetup": {
    "checkoutSessionId": "cs_01m4tx5nj8emwbyf7y9vcf47zj",
    "url": "https://ownrecord.io/c/genno/cs_01m4tx5nj8emwbyf7y9vcf47zj?key=example",
    "expiresAt": "2026-10-14T12:00:00.000Z",
    "required": false
  }
}
```

## `subscriptions_discounts_create`

**Apply a coupon to a subscription.** Operation [`subscriptions.discounts.create`](https://ownrecord.io/docs/reference/subscriptions-discounts-create.md) · Brand level · permission `subscriptions:write` · risk tier `financial` · since M5

Applies a coupon (`couponId`) or a promotion code the customer gave (`promotionCode`) to the subscription from
now on: it discounts the subscription's next invoices for the coupon's duration, counted in the subscription's
billing periods. Promotion codes are checked against their restrictions; the redemption counts when the next
invoice is paid (at once for a trial). End a discount with `discounts.delete`. Emits `discount.created` and
`subscription.updated`.

Annotations: `readOnlyHint: false` · `destructiveHint: false` · `idempotentHint: false` · `openWorldHint: false`

### Arguments

| Argument          | Type         | Required | Description                                                                                                                                                                                              |
| ----------------- | ------------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`              | ID (`sub_…`) | yes      | –                                                                                                                                                                                                        |
| `couponId`        | ID (`cpn_…`) | no       | –                                                                                                                                                                                                        |
| `promotionCode`   | string       | no       | A promotion code as the customer typed it (case doesn't matter). (1–50 characters)                                                                                                                       |
| `entity_id`       | ID (`ent_…`) | no       | Optional: the brand's legal entity (ent\_…); `brand_id` alone is enough.                                                                                                                                 |
| `brand_id`        | ID (`brd_…`) | no       | The brand to act on (brd\_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand.                                                                 |
| `idempotency_key` | string       | no       | A unique string for this change. Retrying with the same key and arguments never acts twice. When left out, the server generates one and returns it in the result's `idempotency_key`. (1–255 characters) |
| `dry_run`         | boolean      | no       | true: check permissions and rules and compute the result, then roll everything back. Nothing is saved. (default `false`)                                                                                 |

- **Brand:** pass `brand_id` with an organization or entity key; a brand key acts on its own brand.
- **Idempotency:** the result returns the `idempotency_key` used, yours or one the server generated. Retry with it: a call with the same key and arguments never acts twice (keys are kept for 24 hours).
- **Dry run:** supported. `dry_run: true` checks permissions and rules and computes the result, then rolls everything back.

### Errors

- [`validation_failed`](https://ownrecord.io/docs/reference/errors.md#validation_failed): A field is malformed or out of range.
- [`resource_not_found`](https://ownrecord.io/docs/reference/errors.md#resource_not_found): No subscription (or customer, price, coupon) with this ID is visible to the request.
- [`subscription_status_invalid`](https://ownrecord.io/docs/reference/errors.md#subscription_status_invalid): The subscription's status doesn't allow this (spec §16.1): see `details.reason`.
- [`coupon_not_redeemable`](https://ownrecord.io/docs/reference/errors.md#coupon_not_redeemable): The coupon is archived, expired or used up.
- [`promotion_code_not_redeemable`](https://ownrecord.io/docs/reference/errors.md#promotion_code_not_redeemable): The promotion code can't be used (`details.reason`).
- [`discount_already_applied`](https://ownrecord.io/docs/reference/errors.md#discount_already_applied): The coupon is already applied to this subscription.
- [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied): The credentials can't change this brand's subscriptions (`subscriptions:write`).

### Example

**Apply the customer's promotion code**

Arguments:

```json
{
  "id": "sub_01m4tx5nj8emwbyf7y9vcf47z5",
  "promotionCode": "LAUNCH50",
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
  "idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
```

Result `output`:

```json
{
  "id": "sub_01m4tx5nj8emwbyf7y9vcf47z5",
  "object": "subscription",
  "livemode": false,
  "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47zm",
  "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
  "customerId": "cus_01m4tx5nj8emwbyf7y9vcf47z4",
  "status": "active",
  "items": [
    {
      "id": "si_01m4tx5nj8emwbyf7y9vcf47za",
      "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y2",
      "productId": "prod_01m4tx5nj8emwbyf7y9vcf47y0",
      "quantity": 3,
      "createdAt": "2026-10-13T12:00:00.000Z"
    },
    {
      "id": "si_01m4tx5nj8emwbyf7y9vcf47zb",
      "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y9",
      "productId": "prod_01m4tx5nj8emwbyf7y9vcf47y1",
      "quantity": 1,
      "createdAt": "2026-10-13T12:00:00.000Z"
    }
  ],
  "currency": "EUR",
  "mrr": {
    "amount": "87000000",
    "currency": "EUR"
  },
  "collectionMethod": "charge_automatically",
  "daysUntilDue": null,
  "defaultPaymentMethodId": "pm_01m4tx5nj8emwbyf7y9vcf47zd",
  "billingCycleAnchor": "2026-10-13T12:00:00.000Z",
  "currentPeriodStart": "2026-10-13T12:00:00.000Z",
  "currentPeriodEnd": "2026-11-13T12:00:00.000Z",
  "trialStart": null,
  "trialEnd": null,
  "trialEndBehavior": "convert",
  "cancelAtPeriodEnd": false,
  "cancelAt": null,
  "canceledAt": null,
  "endedAt": null,
  "cancellation": null,
  "pause": null,
  "discountIds": ["disc_01m4tx5nj8emwbyf7y9vcf47z3"],
  "pendingUpdate": null,
  "latestInvoiceId": "inv_01m4tx5nj8emwbyf7y9vcf47zn",
  "incompleteExpiresAt": null,
  "testClockId": null,
  "dunning": null,
  "usageThreshold": null,
  "entitlementGraceUntil": null,
  "metadata": {
    "crm_account": "A-1042"
  },
  "version": 3,
  "createdAt": "2026-10-13T12:00:00.000Z",
  "updatedAt": "2026-10-20T09:00:00.000Z"
}
```

## `subscriptions_events_list`

**List a subscription's history.** Operation [`subscriptions.events.list`](https://ownrecord.io/docs/reference/subscriptions-events-list.md) · Brand level · permission `subscriptions:read` · risk tier `read` · since M5

Lists a subscription's history, newest first: creation, trial, activation, plan and quantity changes,
discounts, scheduled changes, pauses, cancellations, renewals and payment problems. Each entry has what changed
(`before`, `after`), how it moved monthly recurring revenue (`mrrDelta`), who did it and when.

Paginate with `limit` (1–100, default 10) and `starting_after` (the `next_cursor` of the previous page).

Annotations: `readOnlyHint: true` · `destructiveHint: false` · `idempotentHint: true` · `openWorldHint: false`

### Arguments

| Argument         | Type          | Required | Description                                                                                                                              |
| ---------------- | ------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `id`             | ID (`sub_…`)  | yes      | –                                                                                                                                        |
| `limit`          | integer       | no       | (1–100)                                                                                                                                  |
| `starting_after` | ID (`sevt_…`) | no       | –                                                                                                                                        |
| `entity_id`      | ID (`ent_…`)  | no       | Optional: the brand's legal entity (ent\_…); `brand_id` alone is enough.                                                                 |
| `brand_id`       | ID (`brd_…`)  | no       | The brand to act on (brd\_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand. |

- **Brand:** pass `brand_id` with an organization or entity key; a brand key acts on its own brand.
- **Read-only:** changes nothing; `idempotency_key` is ignored.

### Errors

- [`resource_not_found`](https://ownrecord.io/docs/reference/errors.md#resource_not_found): No subscription with this ID is visible to the request.
- [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied): You can't see this brand's subscriptions (`subscriptions:read`).

### Example

**The latest changes**

Arguments:

```json
{
  "id": "sub_01m4tx5nj8emwbyf7y9vcf47z5",
  "limit": 2,
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz"
}
```

Result `output`:

```json
{
  "object": "list",
  "data": [
    {
      "id": "sevt_01m4tx5nj8emwbyf7y9vcf47zg",
      "object": "subscription_event",
      "livemode": false,
      "subscriptionId": "sub_01m4tx5nj8emwbyf7y9vcf47z5",
      "customerId": "cus_01m4tx5nj8emwbyf7y9vcf47z4",
      "type": "upgraded",
      "before": {
        "items": [
          {
            "id": "si_01m4tx5nj8emwbyf7y9vcf47za",
            "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y2",
            "quantity": 3
          }
        ]
      },
      "after": {
        "items": [
          {
            "id": "si_01m4tx5nj8emwbyf7y9vcf47za",
            "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y3",
            "quantity": 3
          }
        ],
        "effective": "now",
        "prorationBehavior": "always_invoice",
        "invoiceId": "inv_01m4tx5nj8emwbyf7y9vcf47zn"
      },
      "mrrDelta": {
        "amount": "60000000",
        "currency": "EUR"
      },
      "actor": {
        "type": "user",
        "id": "usr_01m4tx5nj8emwbyf7y9vcf47zk",
        "via": "console"
      },
      "at": "2026-10-20T09:00:00.000Z"
    },
    {
      "id": "sevt_01m4tx5nj8emwbyf7y9vcf47zh",
      "object": "subscription_event",
      "livemode": false,
      "subscriptionId": "sub_01m4tx5nj8emwbyf7y9vcf47z5",
      "customerId": "cus_01m4tx5nj8emwbyf7y9vcf47z4",
      "type": "created",
      "before": null,
      "after": {
        "status": "active"
      },
      "mrrDelta": {
        "amount": "87000000",
        "currency": "EUR"
      },
      "actor": {
        "type": "user",
        "id": "usr_01m4tx5nj8emwbyf7y9vcf47zk",
        "via": "console"
      },
      "at": "2026-10-13T12:00:00.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}
```

## `subscriptions_get`

**Get a subscription.** Operation [`subscriptions.get`](https://ownrecord.io/docs/reference/subscriptions-get.md) · Brand level · permission `subscriptions:read` · risk tier `read` · since M5

Reads a subscription: its status, items, billing period, trial, cancellation, pause, scheduled change
(`pendingUpdate`), discounts, latest invoice and its items' monthly recurring amount (`mrr`).

Annotations: `readOnlyHint: true` · `destructiveHint: false` · `idempotentHint: true` · `openWorldHint: false`

### Arguments

| Argument    | Type         | Required | Description                                                                                                                              |
| ----------- | ------------ | -------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `id`        | ID (`sub_…`) | yes      | –                                                                                                                                        |
| `entity_id` | ID (`ent_…`) | no       | Optional: the brand's legal entity (ent\_…); `brand_id` alone is enough.                                                                 |
| `brand_id`  | ID (`brd_…`) | no       | The brand to act on (brd\_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand. |

- **Brand:** pass `brand_id` with an organization or entity key; a brand key acts on its own brand.
- **Read-only:** changes nothing; `idempotency_key` is ignored.

### Errors

- [`resource_not_found`](https://ownrecord.io/docs/reference/errors.md#resource_not_found): No subscription with this ID is visible to the request.
- [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied): You can't see this brand's subscriptions (`subscriptions:read`).

### Example

**An active subscription**

Arguments:

```json
{
  "id": "sub_01m4tx5nj8emwbyf7y9vcf47z5",
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz"
}
```

Result `output`:

```json
{
  "id": "sub_01m4tx5nj8emwbyf7y9vcf47z5",
  "object": "subscription",
  "livemode": false,
  "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47zm",
  "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
  "customerId": "cus_01m4tx5nj8emwbyf7y9vcf47z4",
  "status": "active",
  "items": [
    {
      "id": "si_01m4tx5nj8emwbyf7y9vcf47za",
      "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y2",
      "productId": "prod_01m4tx5nj8emwbyf7y9vcf47y0",
      "quantity": 3,
      "createdAt": "2026-10-13T12:00:00.000Z"
    },
    {
      "id": "si_01m4tx5nj8emwbyf7y9vcf47zb",
      "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y9",
      "productId": "prod_01m4tx5nj8emwbyf7y9vcf47y1",
      "quantity": 1,
      "createdAt": "2026-10-13T12:00:00.000Z"
    }
  ],
  "currency": "EUR",
  "mrr": {
    "amount": "87000000",
    "currency": "EUR"
  },
  "collectionMethod": "charge_automatically",
  "daysUntilDue": null,
  "defaultPaymentMethodId": "pm_01m4tx5nj8emwbyf7y9vcf47zd",
  "billingCycleAnchor": "2026-10-13T12:00:00.000Z",
  "currentPeriodStart": "2026-10-13T12:00:00.000Z",
  "currentPeriodEnd": "2026-11-13T12:00:00.000Z",
  "trialStart": null,
  "trialEnd": null,
  "trialEndBehavior": "convert",
  "cancelAtPeriodEnd": false,
  "cancelAt": null,
  "canceledAt": null,
  "endedAt": null,
  "cancellation": null,
  "pause": null,
  "discountIds": [],
  "pendingUpdate": null,
  "latestInvoiceId": "inv_01m4tx5nj8emwbyf7y9vcf47zn",
  "incompleteExpiresAt": null,
  "testClockId": null,
  "dunning": null,
  "usageThreshold": null,
  "entitlementGraceUntil": null,
  "metadata": {
    "crm_account": "A-1042"
  },
  "version": 2,
  "createdAt": "2026-10-13T12:00:00.000Z",
  "updatedAt": "2026-10-13T12:00:00.000Z"
}
```

## `subscriptions_list`

**List subscriptions.** Operation [`subscriptions.list`](https://ownrecord.io/docs/reference/subscriptions-list.md) · Brand level · permission `subscriptions:read` · risk tier `read` · since M5

Lists the brand's subscriptions in the request's mode, newest first. Filter by `customerId`, `status`
(`trialing`, `active`, `past_due`, `unpaid`, `paused`, `canceled`, `incomplete` or `incomplete_expired`) or
`priceId` (subscriptions with an item on that price).

Paginate with `limit` (1–100, default 10) and `starting_after` (the `next_cursor` of the previous page).

Annotations: `readOnlyHint: true` · `destructiveHint: false` · `idempotentHint: true` · `openWorldHint: false`

### Arguments

| Argument         | Type                                                                                                        | Required | Description                                                                                                                              |
| ---------------- | ----------------------------------------------------------------------------------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `customerId`     | ID (`cus_…`)                                                                                                | no       | Only this customer's subscriptions.                                                                                                      |
| `status`         | one of `incomplete`, `incomplete_expired`, `trialing`, `active`, `past_due`, `unpaid`, `paused`, `canceled` | no       | Only subscriptions in this status.                                                                                                       |
| `priceId`        | ID (`price_…`)                                                                                              | no       | Only subscriptions with an item on this price.                                                                                           |
| `limit`          | integer                                                                                                     | no       | (1–100)                                                                                                                                  |
| `starting_after` | ID (`sub_…`)                                                                                                | no       | –                                                                                                                                        |
| `entity_id`      | ID (`ent_…`)                                                                                                | no       | Optional: the brand's legal entity (ent\_…); `brand_id` alone is enough.                                                                 |
| `brand_id`       | ID (`brd_…`)                                                                                                | no       | The brand to act on (brd\_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand. |

- **Brand:** pass `brand_id` with an organization or entity key; a brand key acts on its own brand.
- **Read-only:** changes nothing; `idempotency_key` is ignored.

### Errors

- [`validation_failed`](https://ownrecord.io/docs/reference/errors.md#validation_failed): A filter or pagination value is malformed.
- [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied): You can't see this brand's subscriptions (`subscriptions:read`).

### Example

**A customer's subscriptions**

Arguments:

```json
{
  "customerId": "cus_01m4tx5nj8emwbyf7y9vcf47z4",
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz"
}
```

Result `output`:

```json
{
  "object": "list",
  "data": [
    {
      "id": "sub_01m4tx5nj8emwbyf7y9vcf47z5",
      "object": "subscription",
      "livemode": false,
      "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47zm",
      "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
      "customerId": "cus_01m4tx5nj8emwbyf7y9vcf47z4",
      "status": "active",
      "items": [
        {
          "id": "si_01m4tx5nj8emwbyf7y9vcf47za",
          "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y2",
          "productId": "prod_01m4tx5nj8emwbyf7y9vcf47y0",
          "quantity": 3,
          "createdAt": "2026-10-13T12:00:00.000Z"
        },
        {
          "id": "si_01m4tx5nj8emwbyf7y9vcf47zb",
          "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y9",
          "productId": "prod_01m4tx5nj8emwbyf7y9vcf47y1",
          "quantity": 1,
          "createdAt": "2026-10-13T12:00:00.000Z"
        }
      ],
      "currency": "EUR",
      "mrr": {
        "amount": "87000000",
        "currency": "EUR"
      },
      "collectionMethod": "charge_automatically",
      "daysUntilDue": null,
      "defaultPaymentMethodId": "pm_01m4tx5nj8emwbyf7y9vcf47zd",
      "billingCycleAnchor": "2026-10-13T12:00:00.000Z",
      "currentPeriodStart": "2026-10-13T12:00:00.000Z",
      "currentPeriodEnd": "2026-11-13T12:00:00.000Z",
      "trialStart": null,
      "trialEnd": null,
      "trialEndBehavior": "convert",
      "cancelAtPeriodEnd": false,
      "cancelAt": null,
      "canceledAt": null,
      "endedAt": null,
      "cancellation": null,
      "pause": null,
      "discountIds": [],
      "pendingUpdate": null,
      "latestInvoiceId": "inv_01m4tx5nj8emwbyf7y9vcf47zn",
      "incompleteExpiresAt": null,
      "testClockId": null,
      "dunning": null,
      "usageThreshold": null,
      "entitlementGraceUntil": null,
      "metadata": {
        "crm_account": "A-1042"
      },
      "version": 2,
      "createdAt": "2026-10-13T12:00:00.000Z",
      "updatedAt": "2026-10-13T12:00:00.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}
```

## `subscriptions_metrics`

**Subscription metrics.** Operation [`subscriptions.metrics`](https://ownrecord.io/docs/reference/subscriptions-metrics.md) · Brand level · permission `subscriptions:read` · risk tier `read` · since M5

The brand's monthly recurring revenue (MRR) per currency in the request's mode, from the subscriptions'
history: MRR at the window's start and end, and what moved it in between: new (subscriptions that started
paying), reactivation (resumed or recovered), expansion (upgrades, more seats), contraction (downgrades, fewer
seats) and churn (canceled, paused, expired unpaid), with the churn rate (churned MRR / MRR at the start).

MRR counts active and past-due subscriptions' licensed items at their monthly amount (a year is 12 months),
before discounts and tax; trials, paused and ended subscriptions don't count. The window is `[from, to)`,
by default the last 30 days.

Annotations: `readOnlyHint: true` · `destructiveHint: false` · `idempotentHint: true` · `openWorldHint: false`

### Arguments

| Argument    | Type                 | Required | Description                                                                                                                              |
| ----------- | -------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `from`      | date-time (ISO 8601) | no       | The window's start (default: 30 days before `to`).                                                                                       |
| `to`        | date-time (ISO 8601) | no       | The window's end (default: now).                                                                                                         |
| `entity_id` | ID (`ent_…`)         | no       | Optional: the brand's legal entity (ent\_…); `brand_id` alone is enough.                                                                 |
| `brand_id`  | ID (`brd_…`)         | no       | The brand to act on (brd\_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand. |

- **Brand:** pass `brand_id` with an organization or entity key; a brand key acts on its own brand.
- **Read-only:** changes nothing; `idempotency_key` is ignored.

### Errors

- [`validation_failed`](https://ownrecord.io/docs/reference/errors.md#validation_failed): `from` isn't before `to`.
- [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied): You can't see this brand's subscriptions (`subscriptions:read`).

### Example

**The last 30 days**

Arguments:

```json
{
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz"
}
```

Result `output`:

```json
{
  "object": "subscription_metrics",
  "livemode": false,
  "from": "2026-09-20T09:00:00.000Z",
  "to": "2026-10-20T09:00:00.000Z",
  "currencies": [
    {
      "currency": "EUR",
      "mrr": {
        "amount": "12450000000",
        "currency": "EUR"
      },
      "startMrr": {
        "amount": "11800000000",
        "currency": "EUR"
      },
      "newMrr": {
        "amount": "870000000",
        "currency": "EUR"
      },
      "reactivationMrr": {
        "amount": "0",
        "currency": "EUR"
      },
      "expansionMrr": {
        "amount": "240000000",
        "currency": "EUR"
      },
      "contractionMrr": {
        "amount": "60000000",
        "currency": "EUR"
      },
      "churnedMrr": {
        "amount": "400000000",
        "currency": "EUR"
      },
      "netNewMrr": {
        "amount": "650000000",
        "currency": "EUR"
      },
      "churnRatePpm": "33898"
    }
  ],
  "truncated": false
}
```

## `subscriptions_migrations_create`

**Migrate subscribers to a new price.** Operation [`subscriptions.migrations.create`](https://ownrecord.io/docs/reference/subscriptions-migrations-create.md) · Brand level · permission `subscriptions:write` · risk tier `financial` · since M5

Moves the subscriptions on one price to another at their renewals, after a notice (spec §16.14). Prices can't
change once used, so changing what existing subscribers pay is a migration to a new price that bills alike (the
same currency, interval and usage type, and meter for metered prices).

1. Every matching subscription (an item on `fromPriceId`; `filter` narrows by status, default trialing, active
   and past due, and by customer) gets a scheduled change (`pendingUpdate`) that swaps the item's price at its
   first renewal on or after the earliest change: `noticeDays` from now (`effective: next_renewal`, default) or
   `effectiveDate` (`effective: date`, itself at least `noticeDays` away). Quantities stay.
2. Each customer is emailed a notice `noticeDays` (default 30) before their change.
3. The renewal applies the change and bills the new price.
4. `subscriptions.migrations.get` reports progress: scheduled, notified, applied, pending and skipped.

Subscriptions with another change already scheduled, or set to cancel, are skipped (`skippedAtCreation`). At
most 1,000 subscriptions per migration. Run it as a dry run first: it returns the counts and the monthly
recurring revenue before and after without changing anything. Each scheduled subscription emits
`subscription.updated`.

Annotations: `readOnlyHint: false` · `destructiveHint: false` · `idempotentHint: false` · `openWorldHint: true`

### Arguments

| Argument          | Type                          | Required | Description                                                                                                                                                                                              |
| ----------------- | ----------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `fromPriceId`     | ID (`price_…`)                | yes      | The price subscribers pay today (`price_…`).                                                                                                                                                             |
| `toPriceId`       | ID (`price_…`)                | yes      | The price they move to: an active recurring price with the same currency, interval and usage type.                                                                                                       |
| `effective`       | one of `next_renewal`, `date` | no       | `next_renewal`: each subscription changes at its first renewal at least `noticeDays` away; `date`: at its first renewal on or after `effectiveDate`. (default `"next_renewal"`)                          |
| `effectiveDate`   | date-time (ISO 8601)          | no       | With `effective: date`: the earliest change (at least `noticeDays` from now).                                                                                                                            |
| `noticeDays`      | integer                       | no       | Days of notice: the customers are emailed this many days before their change (default 30; at least what your terms promise). (0–365) (default `30`)                                                      |
| `filter`          | object                        | no       | –                                                                                                                                                                                                        |
| `entity_id`       | ID (`ent_…`)                  | no       | Optional: the brand's legal entity (ent\_…); `brand_id` alone is enough.                                                                                                                                 |
| `brand_id`        | ID (`brd_…`)                  | no       | The brand to act on (brd\_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand.                                                                 |
| `idempotency_key` | string                        | no       | A unique string for this change. Retrying with the same key and arguments never acts twice. When left out, the server generates one and returns it in the result's `idempotency_key`. (1–255 characters) |
| `dry_run`         | boolean                       | no       | true: check permissions and rules and compute the result, then roll everything back. Nothing is saved. (default `false`)                                                                                 |

- **Brand:** pass `brand_id` with an organization or entity key; a brand key acts on its own brand.
- **Idempotency:** the result returns the `idempotency_key` used, yours or one the server generated. Retry with it: a call with the same key and arguments never acts twice (keys are kept for 24 hours).
- **Dry run:** supported. `dry_run: true` checks permissions and rules and computes the result, then rolls everything back.

### Errors

- [`validation_failed`](https://ownrecord.io/docs/reference/errors.md#validation_failed): A field is malformed, or `effectiveDate` is missing, misplaced or less than `noticeDays` away.
- [`resource_not_found`](https://ownrecord.io/docs/reference/errors.md#resource_not_found): No price with this ID exists for the brand in this mode.
- [`subscription_migration_invalid`](https://ownrecord.io/docs/reference/errors.md#subscription_migration_invalid): The prices don't bill alike (currency, interval, usage type, meter), are the same, aren't recurring, or the new one is archived (`details.reason`).
- [`subscription_migration_too_large`](https://ownrecord.io/docs/reference/errors.md#subscription_migration_too_large): More than 1,000 subscriptions match: narrow the filter and run several migrations.
- [`version_conflict`](https://ownrecord.io/docs/reference/errors.md#version_conflict): A matching subscription changed at the same time; retry.
- [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied): The credentials can't change this brand's subscriptions (`subscriptions:write`).

### Example

**Move monthly subscribers to the new price at their next renewal after 30 days**

Arguments:

```json
{
  "fromPriceId": "price_01jacq4m3xf0v8w9zq2y7k5n6p",
  "toPriceId": "price_01jacq4m3xf0v8w9zq2y7k5n6q",
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
  "idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
```

Result `output`:

```json
{
  "id": "smig_01jacq4m3xf0v8w9zq2y7k5n6h",
  "object": "subscription_migration",
  "livemode": false,
  "brandId": "brd_01jacq4m3xf0v8w9zq2y7k5n6b",
  "fromPriceId": "price_01jacq4m3xf0v8w9zq2y7k5n6p",
  "toPriceId": "price_01jacq4m3xf0v8w9zq2y7k5n6q",
  "currency": "EUR",
  "effective": "next_renewal",
  "effectiveDate": null,
  "noticeDays": 30,
  "filter": {
    "statuses": ["trialing", "active", "past_due"],
    "customerIds": null
  },
  "status": "scheduled",
  "counts": {
    "matched": 42,
    "scheduled": 40,
    "notified": 0,
    "applied": 0,
    "pending": 40,
    "skipped": 2
  },
  "skippedAtCreation": {
    "pending_update": 2,
    "cancel_scheduled": 0
  },
  "revenue": {
    "mrrBefore": {
      "amount": "400000000",
      "currency": "EUR"
    },
    "mrrAfter": {
      "amount": "480000000",
      "currency": "EUR"
    },
    "mrrDelta": {
      "amount": "80000000",
      "currency": "EUR"
    }
  },
  "firstChangeAt": "2026-11-20T10:00:00.000Z",
  "lastChangeAt": "2026-12-19T10:00:00.000Z",
  "version": 2,
  "createdAt": "2026-10-20T09:00:00.000Z",
  "updatedAt": "2026-10-20T09:00:00.000Z"
}
```

## `subscriptions_migrations_get`

**Get a price migration.** Operation [`subscriptions.migrations.get`](https://ownrecord.io/docs/reference/subscriptions-migrations-get.md) · Brand level · permission `subscriptions:read` · risk tier `read` · since M5

Returns a price migration with its progress: how many subscriptions matched and were scheduled, how many
customers were notified, how many changes were applied at a renewal and how many are still pending, and how
many were skipped (at once, or dropped later because the subscription was canceled or changed again).
`status` is `completed` once no change is pending.

Annotations: `readOnlyHint: true` · `destructiveHint: false` · `idempotentHint: true` · `openWorldHint: false`

### Arguments

| Argument    | Type          | Required | Description                                                                                                                              |
| ----------- | ------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `id`        | ID (`smig_…`) | yes      | –                                                                                                                                        |
| `entity_id` | ID (`ent_…`)  | no       | Optional: the brand's legal entity (ent\_…); `brand_id` alone is enough.                                                                 |
| `brand_id`  | ID (`brd_…`)  | no       | The brand to act on (brd\_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand. |

- **Brand:** pass `brand_id` with an organization or entity key; a brand key acts on its own brand.
- **Read-only:** changes nothing; `idempotency_key` is ignored.

### Errors

- [`resource_not_found`](https://ownrecord.io/docs/reference/errors.md#resource_not_found): No price migration with this ID exists for the brand in this mode.
- [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied): The credentials can't read this brand's subscriptions.

### Example

**A migration half applied**

Arguments:

```json
{
  "id": "smig_01jacq4m3xf0v8w9zq2y7k5n6h",
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz"
}
```

Result `output`:

```json
{
  "id": "smig_01jacq4m3xf0v8w9zq2y7k5n6h",
  "object": "subscription_migration",
  "livemode": false,
  "brandId": "brd_01jacq4m3xf0v8w9zq2y7k5n6b",
  "fromPriceId": "price_01jacq4m3xf0v8w9zq2y7k5n6p",
  "toPriceId": "price_01jacq4m3xf0v8w9zq2y7k5n6q",
  "currency": "EUR",
  "effective": "next_renewal",
  "effectiveDate": null,
  "noticeDays": 30,
  "filter": {
    "statuses": ["trialing", "active", "past_due"],
    "customerIds": null
  },
  "status": "scheduled",
  "counts": {
    "matched": 42,
    "scheduled": 40,
    "notified": 40,
    "applied": 25,
    "pending": 14,
    "skipped": 3
  },
  "skippedAtCreation": {
    "pending_update": 2,
    "cancel_scheduled": 0
  },
  "revenue": {
    "mrrBefore": {
      "amount": "400000000",
      "currency": "EUR"
    },
    "mrrAfter": {
      "amount": "480000000",
      "currency": "EUR"
    },
    "mrrDelta": {
      "amount": "80000000",
      "currency": "EUR"
    }
  },
  "firstChangeAt": "2026-11-20T10:00:00.000Z",
  "lastChangeAt": "2026-12-19T10:00:00.000Z",
  "version": 67,
  "createdAt": "2026-10-20T09:00:00.000Z",
  "updatedAt": "2026-12-05T10:00:00.000Z"
}
```

## `subscriptions_migrations_list`

**List price migrations.** Operation [`subscriptions.migrations.list`](https://ownrecord.io/docs/reference/subscriptions-migrations-list.md) · Brand level · permission `subscriptions:read` · risk tier `read` · since M5

Lists the brand's price migrations in the request's mode, newest first, with their progress. Filter by
`fromPriceId`.

Paginate with `limit` (1–100, default 10) and `starting_after` (the `next_cursor` of the previous page).

Annotations: `readOnlyHint: true` · `destructiveHint: false` · `idempotentHint: true` · `openWorldHint: false`

### Arguments

| Argument         | Type           | Required | Description                                                                                                                              |
| ---------------- | -------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `fromPriceId`    | ID (`price_…`) | no       | Only migrations away from this price.                                                                                                    |
| `limit`          | integer        | no       | (1–100)                                                                                                                                  |
| `starting_after` | ID (`smig_…`)  | no       | –                                                                                                                                        |
| `entity_id`      | ID (`ent_…`)   | no       | Optional: the brand's legal entity (ent\_…); `brand_id` alone is enough.                                                                 |
| `brand_id`       | ID (`brd_…`)   | no       | The brand to act on (brd\_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand. |

- **Brand:** pass `brand_id` with an organization or entity key; a brand key acts on its own brand.
- **Read-only:** changes nothing; `idempotency_key` is ignored.

### Errors

- [`validation_failed`](https://ownrecord.io/docs/reference/errors.md#validation_failed): A filter or pagination value is malformed.
- [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied): The credentials can't read this brand's subscriptions.

### Example

**A price's migrations**

Arguments:

```json
{
  "fromPriceId": "price_01jacq4m3xf0v8w9zq2y7k5n6p",
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz"
}
```

Result `output`:

```json
{
  "object": "list",
  "data": [
    {
      "id": "smig_01jacq4m3xf0v8w9zq2y7k5n6h",
      "object": "subscription_migration",
      "livemode": false,
      "brandId": "brd_01jacq4m3xf0v8w9zq2y7k5n6b",
      "fromPriceId": "price_01jacq4m3xf0v8w9zq2y7k5n6p",
      "toPriceId": "price_01jacq4m3xf0v8w9zq2y7k5n6q",
      "currency": "EUR",
      "effective": "next_renewal",
      "effectiveDate": null,
      "noticeDays": 30,
      "filter": {
        "statuses": ["trialing", "active", "past_due"],
        "customerIds": null
      },
      "status": "scheduled",
      "counts": {
        "matched": 42,
        "scheduled": 40,
        "notified": 0,
        "applied": 0,
        "pending": 40,
        "skipped": 2
      },
      "skippedAtCreation": {
        "pending_update": 2,
        "cancel_scheduled": 0
      },
      "revenue": {
        "mrrBefore": {
          "amount": "400000000",
          "currency": "EUR"
        },
        "mrrAfter": {
          "amount": "480000000",
          "currency": "EUR"
        },
        "mrrDelta": {
          "amount": "80000000",
          "currency": "EUR"
        }
      },
      "firstChangeAt": "2026-11-20T10:00:00.000Z",
      "lastChangeAt": "2026-12-19T10:00:00.000Z",
      "version": 2,
      "createdAt": "2026-10-20T09:00:00.000Z",
      "updatedAt": "2026-10-20T09:00:00.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}
```

## `subscriptions_pause`

**Pause a subscription.** Operation [`subscriptions.pause`](https://ownrecord.io/docs/reference/subscriptions-pause.md) · Brand level · permission `subscriptions:write` · risk tier `write` · since M5

Pauses an active subscription: collection stops until it resumes, at `resumesAt` or with
`subscriptions.resume`. `behavior` says what happens to the invoices of the periods that pass meanwhile:
`void` (none are created; the default), `keep_as_draft` (created, not finalized) or `mark_uncollectible`
(created and written off). The customer's entitlements stop during the pause (the brand default), and the
subscription stops counting for MRR. Emits `subscription.paused`.

Annotations: `readOnlyHint: false` · `destructiveHint: false` · `idempotentHint: false` · `openWorldHint: false`

### Arguments

| Argument          | Type                                                 | Required | Description                                                                                                                                                                                              |
| ----------------- | ---------------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`              | ID (`sub_…`)                                         | yes      | –                                                                                                                                                                                                        |
| `expectedVersion` | integer                                              | no       | (1–9007199254740991)                                                                                                                                                                                     |
| `behavior`        | one of `keep_as_draft`, `void`, `mark_uncollectible` | no       | What happens to the invoices while paused: `keep_as_draft` (created, not finalized), `void` (none) or `mark_uncollectible` (created and written off). (default `"void"`)                                 |
| `resumesAt`       | date-time (ISO 8601)                                 | no       | Resume automatically at this time.                                                                                                                                                                       |
| `entity_id`       | ID (`ent_…`)                                         | no       | Optional: the brand's legal entity (ent\_…); `brand_id` alone is enough.                                                                                                                                 |
| `brand_id`        | ID (`brd_…`)                                         | no       | The brand to act on (brd\_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand.                                                                 |
| `idempotency_key` | string                                               | no       | A unique string for this change. Retrying with the same key and arguments never acts twice. When left out, the server generates one and returns it in the result's `idempotency_key`. (1–255 characters) |
| `dry_run`         | boolean                                              | no       | true: check permissions and rules and compute the result, then roll everything back. Nothing is saved. (default `false`)                                                                                 |

- **Brand:** pass `brand_id` with an organization or entity key; a brand key acts on its own brand.
- **Idempotency:** the result returns the `idempotency_key` used, yours or one the server generated. Retry with it: a call with the same key and arguments never acts twice (keys are kept for 24 hours).
- **Dry run:** supported. `dry_run: true` checks permissions and rules and computes the result, then rolls everything back.

### Errors

- [`validation_failed`](https://ownrecord.io/docs/reference/errors.md#validation_failed): A field is malformed or out of range.
- [`resource_not_found`](https://ownrecord.io/docs/reference/errors.md#resource_not_found): No subscription (or customer, price, coupon) with this ID is visible to the request.
- [`version_conflict`](https://ownrecord.io/docs/reference/errors.md#version_conflict): The subscription changed since you read it (`expectedVersion`), or at the same time; read it and retry.
- [`subscription_status_invalid`](https://ownrecord.io/docs/reference/errors.md#subscription_status_invalid): The subscription's status doesn't allow this (spec §16.1): see `details.reason`.
- [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied): The credentials can't change this brand's subscriptions (`subscriptions:write`).

### Example

**Pause for a month**

Arguments:

```json
{
  "id": "sub_01m4tx5nj8emwbyf7y9vcf47z5",
  "behavior": "void",
  "resumesAt": "2026-11-20T09:00:00.000Z",
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
  "idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
```

Result `output`:

```json
{
  "id": "sub_01m4tx5nj8emwbyf7y9vcf47z5",
  "object": "subscription",
  "livemode": false,
  "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47zm",
  "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
  "customerId": "cus_01m4tx5nj8emwbyf7y9vcf47z4",
  "status": "paused",
  "items": [
    {
      "id": "si_01m4tx5nj8emwbyf7y9vcf47za",
      "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y2",
      "productId": "prod_01m4tx5nj8emwbyf7y9vcf47y0",
      "quantity": 3,
      "createdAt": "2026-10-13T12:00:00.000Z"
    },
    {
      "id": "si_01m4tx5nj8emwbyf7y9vcf47zb",
      "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y9",
      "productId": "prod_01m4tx5nj8emwbyf7y9vcf47y1",
      "quantity": 1,
      "createdAt": "2026-10-13T12:00:00.000Z"
    }
  ],
  "currency": "EUR",
  "mrr": {
    "amount": "87000000",
    "currency": "EUR"
  },
  "collectionMethod": "charge_automatically",
  "daysUntilDue": null,
  "defaultPaymentMethodId": "pm_01m4tx5nj8emwbyf7y9vcf47zd",
  "billingCycleAnchor": "2026-10-13T12:00:00.000Z",
  "currentPeriodStart": "2026-10-13T12:00:00.000Z",
  "currentPeriodEnd": "2026-11-13T12:00:00.000Z",
  "trialStart": null,
  "trialEnd": null,
  "trialEndBehavior": "convert",
  "cancelAtPeriodEnd": false,
  "cancelAt": null,
  "canceledAt": null,
  "endedAt": null,
  "cancellation": null,
  "pause": {
    "behavior": "void",
    "resumesAt": "2026-11-20T09:00:00.000Z",
    "pausedAt": "2026-10-20T09:00:00.000Z"
  },
  "discountIds": [],
  "pendingUpdate": null,
  "latestInvoiceId": "inv_01m4tx5nj8emwbyf7y9vcf47zn",
  "incompleteExpiresAt": null,
  "testClockId": null,
  "dunning": null,
  "usageThreshold": null,
  "entitlementGraceUntil": null,
  "metadata": {
    "crm_account": "A-1042"
  },
  "version": 3,
  "createdAt": "2026-10-13T12:00:00.000Z",
  "updatedAt": "2026-10-20T09:00:00.000Z"
}
```

## `subscriptions_preview_change`

**Preview a subscription change.** Operation [`subscriptions.preview_change`](https://ownrecord.io/docs/reference/subscriptions-preview-change.md) · Brand level · permission `subscriptions:read` · risk tier `read` · since M5

Shows exactly what `subscriptions.update` would do with the same item changes, proration behaviour, timing and
promotion code, without changing anything: whether it is an upgrade, a downgrade or lateral, when it applies,
and how it is settled (`settlement`): the invoice issued now (`invoice`: lines, prorations, discounts, tax at
today's rates, the credit balance applied, the amount due; without a number until it is issued), the pending
items for the next invoice, the credit to the customer's credit balance, or the scheduled change. Also the
subscription as it would be and its monthly recurring amount before and after.

The preview runs the change's own code in a transaction that is rolled back, so it matches the real change as
long as nothing changes in between (the time moves on: proration is exact to the second).

Annotations: `readOnlyHint: true` · `destructiveHint: false` · `idempotentHint: true` · `openWorldHint: true`

### Arguments

| Argument            | Type                                                 | Required | Description                                                                                                                                                                                           |
| ------------------- | ---------------------------------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`                | ID (`sub_…`)                                         | yes      | –                                                                                                                                                                                                     |
| `items`             | array of object                                      | no       | Item changes: `{ id, priceId }` swaps a price, `{ id, quantity }` changes seats, `{ priceId, quantity }` adds an item, `{ id, deleted: true }` removes one. Items not named stay. (1–40 items)        |
| `prorationBehavior` | one of `create_prorations`, `always_invoice`, `none` | no       | `create_prorations` (credit unused time and charge the remaining time on the next invoice; a net credit goes to the customer credit balance), `always_invoice` (invoice the proration now) or `none`. |
| `effective`         | one of `now`, `period_end`                           | no       | `now`, or at the end of the current period (`period_end`, stored as `pendingUpdate`). Default: upgrades and interval changes now with `always_invoice`, downgrades at the period end.                 |
| `paymentBehavior`   | one of `allow_incomplete`, `pending_if_incomplete`   | no       | For a change invoiced now: `allow_incomplete` (default; the change applies and a failed payment goes to dunning) or `pending_if_incomplete` (the old items stay until the invoice is paid).           |
| `couponId`          | ID (`cpn_…`)                                         | no       | Apply a coupon to the subscription.                                                                                                                                                                   |
| `promotionCode`     | string                                               | no       | A promotion code as the customer typed it (case doesn't matter). (1–50 characters)                                                                                                                    |
| `entity_id`         | ID (`ent_…`)                                         | no       | Optional: the brand's legal entity (ent\_…); `brand_id` alone is enough.                                                                                                                              |
| `brand_id`          | ID (`brd_…`)                                         | no       | The brand to act on (brd\_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand.                                                              |

- **Brand:** pass `brand_id` with an organization or entity key; a brand key acts on its own brand.
- **Read-only:** changes nothing; `idempotency_key` is ignored.

### Errors

- [`validation_failed`](https://ownrecord.io/docs/reference/errors.md#validation_failed): A field is malformed or out of range.
- [`resource_not_found`](https://ownrecord.io/docs/reference/errors.md#resource_not_found): No subscription (or customer, price, coupon) with this ID is visible to the request.
- [`subscription_status_invalid`](https://ownrecord.io/docs/reference/errors.md#subscription_status_invalid): The subscription's status doesn't allow this (spec §16.1): see `details.reason`.
- [`subscription_item_not_found`](https://ownrecord.io/docs/reference/errors.md#subscription_item_not_found): An item `id` isn't one of the subscription's items.
- [`subscription_price_invalid`](https://ownrecord.io/docs/reference/errors.md#subscription_price_invalid): A new price isn't recurring, is archived, is in another currency, or its interval doesn't combine.
- [`subscription_meter_conflict`](https://ownrecord.io/docs/reference/errors.md#subscription_meter_conflict): Another live item of the customer already bills this meter.
- [`subscription_change_invalid`](https://ownrecord.io/docs/reference/errors.md#subscription_change_invalid): A change waits for its invoice to be paid, or `pending_if_incomplete` was asked for a `send_invoice` subscription.
- [`coupon_not_redeemable`](https://ownrecord.io/docs/reference/errors.md#coupon_not_redeemable): The coupon is archived, expired or used up.
- [`promotion_code_not_redeemable`](https://ownrecord.io/docs/reference/errors.md#promotion_code_not_redeemable): The promotion code can't be used (`details.reason`).
- [`discount_already_applied`](https://ownrecord.io/docs/reference/errors.md#discount_already_applied): The coupon is already applied to this subscription.
- [`registration_required`](https://ownrecord.io/docs/reference/errors.md#registration_required): An invoice issued now can't be taxed: the seller isn't registered where the customer is (a new sale).
- [`jurisdiction_blocked`](https://ownrecord.io/docs/reference/errors.md#jurisdiction_blocked): The customer's location is blocked for new sales.
- [`evidence_conflict`](https://ownrecord.io/docs/reference/errors.md#evidence_conflict): The customer's stored location evidence isn't enough to tax an invoice issued now (§13.3).
- [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied): You can't see this brand's subscriptions (`subscriptions:read`).

### Example

**What upgrading to Pro now costs**

Arguments:

```json
{
  "id": "sub_01m4tx5nj8emwbyf7y9vcf47z5",
  "items": [
    {
      "id": "si_01m4tx5nj8emwbyf7y9vcf47za",
      "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y3"
    }
  ],
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz"
}
```

Result `output`:

```json
{
  "object": "subscription_change_preview",
  "subscriptionId": "sub_01m4tx5nj8emwbyf7y9vcf47z5",
  "direction": "upgrade",
  "intervalChange": false,
  "effective": "now",
  "prorationBehavior": "always_invoice",
  "settlement": "invoice_now",
  "invoice": {
    "id": "inv_01m4tx5nj8emwbyf7y9vcf47yk",
    "object": "invoice",
    "livemode": false,
    "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47x2",
    "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
    "number": null,
    "numbering": null,
    "customerId": "cus_01m4tx5nj8emwbyf7y9vcf47ym",
    "subscriptionId": null,
    "collectionMethod": "send_invoice",
    "kind": "invoice",
    "status": "open",
    "language": "en",
    "issuedAt": "2026-10-20T09:00:00.000Z",
    "issueDate": "2026-10-20",
    "taxPoint": "2026-10-20T09:00:00.000Z",
    "taxPointDate": "2026-10-20",
    "daysUntilDue": 14,
    "dueDate": "2026-11-03",
    "seller": {
      "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47x2",
      "legalName": "Acme Digital d.o.o.",
      "tradingName": null,
      "address": {
        "line1": "Ilica 1",
        "line2": null,
        "city": "Zagreb",
        "postalCode": "10000",
        "region": null,
        "country": "HR"
      },
      "companyRegistryId": "080000001",
      "taxIds": [
        {
          "type": "eu_vat",
          "value": "HR12345678901",
          "regimeId": null
        }
      ],
      "brand": {
        "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
        "name": "Genno",
        "primaryColor": "#0E6B5C",
        "accentColor": null,
        "supportEmail": "help@genno.example",
        "supportUrl": null
      },
      "footerText": null
    },
    "buyer": {
      "type": "b2b",
      "customerId": "cus_01m4tx5nj8emwbyf7y9vcf47ym",
      "name": "Alpen Apps GmbH",
      "email": "billing@alpen.example",
      "address": null,
      "country": "AT",
      "taxId": {
        "type": "eu_vat",
        "value": "ATU00000000",
        "country": "AT"
      }
    },
    "currency": "EUR",
    "lines": [
      {
        "id": "1",
        "description": "Implementation workshop (days)",
        "productId": "prod_01m4tx5nj8emwbyf7y9vcf47yr",
        "priceId": null,
        "quantity": 2,
        "taxCategoryId": "consulting_remote",
        "taxBehavior": "exclusive",
        "unitAmount": {
          "amount": "600000000",
          "currency": "EUR"
        },
        "net": {
          "amount": "1200000000",
          "currency": "EUR"
        },
        "tax": {
          "ratePpm": "0",
          "amount": {
            "amount": "0",
            "currency": "EUR"
          },
          "jurisdictionId": "AT",
          "regimeId": "EU_OSS_UNION",
          "decision": "reverse_charge",
          "rateKind": null,
          "rateId": null,
          "pendingRegistration": false
        },
        "gross": {
          "amount": "1200000000",
          "currency": "EUR"
        },
        "kind": "invoice_item",
        "period": null,
        "subscriptionItemId": null,
        "invoiceItemId": "ii_01m4tx5nj8emwbyf7y9vcf47ys",
        "discount": null,
        "meteredQuantity": null
      }
    ],
    "totals": {
      "net": {
        "amount": "1200000000",
        "currency": "EUR"
      },
      "tax": {
        "amount": "0",
        "currency": "EUR"
      },
      "gross": {
        "amount": "1200000000",
        "currency": "EUR"
      },
      "taxByRate": [
        {
          "ratePpm": "0",
          "jurisdictionId": "AT",
          "regimeId": "EU_OSS_UNION",
          "decision": "reverse_charge",
          "net": {
            "amount": "1200000000",
            "currency": "EUR"
          },
          "tax": {
            "amount": "0",
            "currency": "EUR"
          }
        }
      ]
    },
    "taxCurrencyTotals": null,
    "creditApplied": {
      "amount": "200000000",
      "currency": "EUR"
    },
    "amountDue": {
      "amount": "1000000000",
      "currency": "EUR"
    },
    "notes": [
      {
        "code": "reverse_charge",
        "text": "Prijenos porezne obveze (reverse charge) – čl. 17. st. 1. Zakona o PDV-u"
      }
    ],
    "fieldCheck": {
      "invoicingRuleIds": [],
      "missing": ["buyer_address"],
      "unchecked": []
    },
    "pendingRegistration": false,
    "paymentIds": [],
    "creditNoteIds": [],
    "ledgerTxnIds": ["txn_01m4tx5nj8emwbyf7y9vcf47yn"],
    "quoteId": "tq_01m4tx5nj8emwbyf7y9vcf47xr",
    "quoteIds": ["tq_01m4tx5nj8emwbyf7y9vcf47xr"],
    "pdf": {
      "status": "pending",
      "fileId": null,
      "sha256": null,
      "size": null,
      "templateVersion": null,
      "renderedAt": null,
      "url": "/api/v1/invoices/inv_01m4tx5nj8emwbyf7y9vcf47yk/pdf"
    },
    "finalizedAt": "2026-10-20T09:00:00.000Z",
    "paidAt": null,
    "payment": null,
    "voidedAt": null,
    "markedUncollectibleAt": null,
    "emailedAt": null,
    "sentAt": null,
    "draft": null,
    "metadata": {
      "contract": "ENT-2026-07"
    },
    "version": 2,
    "createdAt": "2026-10-20T08:30:00.000Z",
    "updatedAt": "2026-10-20T09:00:00.000Z"
  },
  "pendingItems": [],
  "credit": null,
  "subscription": {
    "id": "sub_01m4tx5nj8emwbyf7y9vcf47z5",
    "object": "subscription",
    "livemode": false,
    "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47zm",
    "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
    "customerId": "cus_01m4tx5nj8emwbyf7y9vcf47z4",
    "status": "active",
    "items": [
      {
        "id": "si_01m4tx5nj8emwbyf7y9vcf47za",
        "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y3",
        "productId": "prod_01m4tx5nj8emwbyf7y9vcf47y0",
        "quantity": 3,
        "createdAt": "2026-10-13T12:00:00.000Z"
      }
    ],
    "currency": "EUR",
    "mrr": {
      "amount": "147000000",
      "currency": "EUR"
    },
    "collectionMethod": "charge_automatically",
    "daysUntilDue": null,
    "defaultPaymentMethodId": "pm_01m4tx5nj8emwbyf7y9vcf47zd",
    "billingCycleAnchor": "2026-10-13T12:00:00.000Z",
    "currentPeriodStart": "2026-10-13T12:00:00.000Z",
    "currentPeriodEnd": "2026-11-13T12:00:00.000Z",
    "trialStart": null,
    "trialEnd": null,
    "trialEndBehavior": "convert",
    "cancelAtPeriodEnd": false,
    "cancelAt": null,
    "canceledAt": null,
    "endedAt": null,
    "cancellation": null,
    "pause": null,
    "discountIds": [],
    "pendingUpdate": null,
    "latestInvoiceId": "inv_01m4tx5nj8emwbyf7y9vcf47zn",
    "incompleteExpiresAt": null,
    "testClockId": null,
    "dunning": null,
    "usageThreshold": null,
    "entitlementGraceUntil": null,
    "metadata": {
      "crm_account": "A-1042"
    },
    "version": 2,
    "createdAt": "2026-10-13T12:00:00.000Z",
    "updatedAt": "2026-10-13T12:00:00.000Z"
  },
  "mrrBefore": {
    "amount": "87000000",
    "currency": "EUR"
  },
  "mrrAfter": {
    "amount": "147000000",
    "currency": "EUR"
  },
  "mrrDelta": {
    "amount": "60000000",
    "currency": "EUR"
  }
}
```

## `subscriptions_reactivate`

**Reactivate a subscription.** Operation [`subscriptions.reactivate`](https://ownrecord.io/docs/reference/subscriptions-reactivate.md) · Brand level · permission `subscriptions:write` · risk tier `write` · since M5

Withdraws a cancellation scheduled for the period end (`cancelAtPeriodEnd`): the subscription renews as usual.
A subscription already canceled can't be reactivated: create a new one. Emits `subscription.updated`.

Annotations: `readOnlyHint: false` · `destructiveHint: false` · `idempotentHint: false` · `openWorldHint: false`

### Arguments

| Argument          | Type         | Required | Description                                                                                                                                                                                              |
| ----------------- | ------------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`              | ID (`sub_…`) | yes      | –                                                                                                                                                                                                        |
| `expectedVersion` | integer      | no       | (1–9007199254740991)                                                                                                                                                                                     |
| `entity_id`       | ID (`ent_…`) | no       | Optional: the brand's legal entity (ent\_…); `brand_id` alone is enough.                                                                                                                                 |
| `brand_id`        | ID (`brd_…`) | no       | The brand to act on (brd\_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand.                                                                 |
| `idempotency_key` | string       | no       | A unique string for this change. Retrying with the same key and arguments never acts twice. When left out, the server generates one and returns it in the result's `idempotency_key`. (1–255 characters) |
| `dry_run`         | boolean      | no       | true: check permissions and rules and compute the result, then roll everything back. Nothing is saved. (default `false`)                                                                                 |

- **Brand:** pass `brand_id` with an organization or entity key; a brand key acts on its own brand.
- **Idempotency:** the result returns the `idempotency_key` used, yours or one the server generated. Retry with it: a call with the same key and arguments never acts twice (keys are kept for 24 hours).
- **Dry run:** supported. `dry_run: true` checks permissions and rules and computes the result, then rolls everything back.

### Errors

- [`validation_failed`](https://ownrecord.io/docs/reference/errors.md#validation_failed): A field is malformed or out of range.
- [`resource_not_found`](https://ownrecord.io/docs/reference/errors.md#resource_not_found): No subscription (or customer, price, coupon) with this ID is visible to the request.
- [`version_conflict`](https://ownrecord.io/docs/reference/errors.md#version_conflict): The subscription changed since you read it (`expectedVersion`), or at the same time; read it and retry.
- [`subscription_status_invalid`](https://ownrecord.io/docs/reference/errors.md#subscription_status_invalid): The subscription's status doesn't allow this (spec §16.1): see `details.reason`.
- [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied): The credentials can't change this brand's subscriptions (`subscriptions:write`).

### Example

**Keep the subscription after all**

Arguments:

```json
{
  "id": "sub_01m4tx5nj8emwbyf7y9vcf47z5",
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
  "idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
```

Result `output`:

```json
{
  "id": "sub_01m4tx5nj8emwbyf7y9vcf47z5",
  "object": "subscription",
  "livemode": false,
  "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47zm",
  "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
  "customerId": "cus_01m4tx5nj8emwbyf7y9vcf47z4",
  "status": "active",
  "items": [
    {
      "id": "si_01m4tx5nj8emwbyf7y9vcf47za",
      "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y2",
      "productId": "prod_01m4tx5nj8emwbyf7y9vcf47y0",
      "quantity": 3,
      "createdAt": "2026-10-13T12:00:00.000Z"
    },
    {
      "id": "si_01m4tx5nj8emwbyf7y9vcf47zb",
      "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y9",
      "productId": "prod_01m4tx5nj8emwbyf7y9vcf47y1",
      "quantity": 1,
      "createdAt": "2026-10-13T12:00:00.000Z"
    }
  ],
  "currency": "EUR",
  "mrr": {
    "amount": "87000000",
    "currency": "EUR"
  },
  "collectionMethod": "charge_automatically",
  "daysUntilDue": null,
  "defaultPaymentMethodId": "pm_01m4tx5nj8emwbyf7y9vcf47zd",
  "billingCycleAnchor": "2026-10-13T12:00:00.000Z",
  "currentPeriodStart": "2026-10-13T12:00:00.000Z",
  "currentPeriodEnd": "2026-11-13T12:00:00.000Z",
  "trialStart": null,
  "trialEnd": null,
  "trialEndBehavior": "convert",
  "cancelAtPeriodEnd": false,
  "cancelAt": null,
  "canceledAt": null,
  "endedAt": null,
  "cancellation": null,
  "pause": null,
  "discountIds": [],
  "pendingUpdate": null,
  "latestInvoiceId": "inv_01m4tx5nj8emwbyf7y9vcf47zn",
  "incompleteExpiresAt": null,
  "testClockId": null,
  "dunning": null,
  "usageThreshold": null,
  "entitlementGraceUntil": null,
  "metadata": {
    "crm_account": "A-1042"
  },
  "version": 4,
  "createdAt": "2026-10-13T12:00:00.000Z",
  "updatedAt": "2026-10-20T09:00:00.000Z"
}
```

## `subscriptions_resume`

**Resume a subscription.** Operation [`subscriptions.resume`](https://ownrecord.io/docs/reference/subscriptions-resume.md) · Brand level · permission `subscriptions:write` · risk tier `write` · since M5

Resumes a paused subscription: it is active again, its current billing period carries on and renewals collect
again. The customer's entitlements come back. Emits `subscription.resumed`.

Annotations: `readOnlyHint: false` · `destructiveHint: false` · `idempotentHint: false` · `openWorldHint: false`

### Arguments

| Argument          | Type         | Required | Description                                                                                                                                                                                              |
| ----------------- | ------------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`              | ID (`sub_…`) | yes      | –                                                                                                                                                                                                        |
| `expectedVersion` | integer      | no       | (1–9007199254740991)                                                                                                                                                                                     |
| `entity_id`       | ID (`ent_…`) | no       | Optional: the brand's legal entity (ent\_…); `brand_id` alone is enough.                                                                                                                                 |
| `brand_id`        | ID (`brd_…`) | no       | The brand to act on (brd\_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand.                                                                 |
| `idempotency_key` | string       | no       | A unique string for this change. Retrying with the same key and arguments never acts twice. When left out, the server generates one and returns it in the result's `idempotency_key`. (1–255 characters) |
| `dry_run`         | boolean      | no       | true: check permissions and rules and compute the result, then roll everything back. Nothing is saved. (default `false`)                                                                                 |

- **Brand:** pass `brand_id` with an organization or entity key; a brand key acts on its own brand.
- **Idempotency:** the result returns the `idempotency_key` used, yours or one the server generated. Retry with it: a call with the same key and arguments never acts twice (keys are kept for 24 hours).
- **Dry run:** supported. `dry_run: true` checks permissions and rules and computes the result, then rolls everything back.

### Errors

- [`validation_failed`](https://ownrecord.io/docs/reference/errors.md#validation_failed): A field is malformed or out of range.
- [`resource_not_found`](https://ownrecord.io/docs/reference/errors.md#resource_not_found): No subscription (or customer, price, coupon) with this ID is visible to the request.
- [`version_conflict`](https://ownrecord.io/docs/reference/errors.md#version_conflict): The subscription changed since you read it (`expectedVersion`), or at the same time; read it and retry.
- [`subscription_status_invalid`](https://ownrecord.io/docs/reference/errors.md#subscription_status_invalid): The subscription's status doesn't allow this (spec §16.1): see `details.reason`.
- [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied): The credentials can't change this brand's subscriptions (`subscriptions:write`).

### Example

**Resume now**

Arguments:

```json
{
  "id": "sub_01m4tx5nj8emwbyf7y9vcf47z5",
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
  "idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
```

Result `output`:

```json
{
  "id": "sub_01m4tx5nj8emwbyf7y9vcf47z5",
  "object": "subscription",
  "livemode": false,
  "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47zm",
  "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
  "customerId": "cus_01m4tx5nj8emwbyf7y9vcf47z4",
  "status": "active",
  "items": [
    {
      "id": "si_01m4tx5nj8emwbyf7y9vcf47za",
      "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y2",
      "productId": "prod_01m4tx5nj8emwbyf7y9vcf47y0",
      "quantity": 3,
      "createdAt": "2026-10-13T12:00:00.000Z"
    },
    {
      "id": "si_01m4tx5nj8emwbyf7y9vcf47zb",
      "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y9",
      "productId": "prod_01m4tx5nj8emwbyf7y9vcf47y1",
      "quantity": 1,
      "createdAt": "2026-10-13T12:00:00.000Z"
    }
  ],
  "currency": "EUR",
  "mrr": {
    "amount": "87000000",
    "currency": "EUR"
  },
  "collectionMethod": "charge_automatically",
  "daysUntilDue": null,
  "defaultPaymentMethodId": "pm_01m4tx5nj8emwbyf7y9vcf47zd",
  "billingCycleAnchor": "2026-10-13T12:00:00.000Z",
  "currentPeriodStart": "2026-10-13T12:00:00.000Z",
  "currentPeriodEnd": "2026-11-13T12:00:00.000Z",
  "trialStart": null,
  "trialEnd": null,
  "trialEndBehavior": "convert",
  "cancelAtPeriodEnd": false,
  "cancelAt": null,
  "canceledAt": null,
  "endedAt": null,
  "cancellation": null,
  "pause": null,
  "discountIds": [],
  "pendingUpdate": null,
  "latestInvoiceId": "inv_01m4tx5nj8emwbyf7y9vcf47zn",
  "incompleteExpiresAt": null,
  "testClockId": null,
  "dunning": null,
  "usageThreshold": null,
  "entitlementGraceUntil": null,
  "metadata": {
    "crm_account": "A-1042"
  },
  "version": 4,
  "createdAt": "2026-10-13T12:00:00.000Z",
  "updatedAt": "2026-10-20T09:00:00.000Z"
}
```

## `subscriptions_update`

**Change a subscription.** Operation [`subscriptions.update`](https://ownrecord.io/docs/reference/subscriptions-update.md) · Brand level · permission `subscriptions:write` · risk tier `financial` · since M5

Changes a subscription's items, quantities, discount, payment method, collection method or metadata.

**Items** (`items[]`): `{ id, priceId }` swaps the price of an item, `{ id, quantity }` changes its seats,
`{ priceId, quantity }` adds an item and `{ id, deleted: true }` removes one; items not named stay. When the change
applies (`effective`) and how it is billed (`prorationBehavior`) follow spec §16.5:

- **Upgrades** (a higher monthly amount) and interval changes default to `now` with `always_invoice`: the unused
  time of the old items is credited, the remaining time of the new ones charged, and the difference invoiced and
  charged at once (an interval change starts a new billing period now). If the payment fails, the change stays and
  the open invoice goes to dunning, unless `paymentBehavior: pending_if_incomplete` keeps the old items until
  the invoice is paid.
- **Downgrades** and lateral changes default to the end of the period: the change is stored as `pendingUpdate`
  and applied at renewal, with no credit.
- `now` with `create_prorations`: a net charge waits for the next invoice as pending invoice items; a net
  credit (fewer seats) goes to the customer's credit balance at once.
- `none`: the items change now and nothing is billed.

Trialing subscriptions change at once with nothing to bill. Proration is exact to the second, rounded once per
line; proration lines are taxed at the rates of the change date. Preview a change first with
`subscriptions.preview_change` (the exact invoice), or dry-run this operation. Emits `subscription.updated`.

Annotations: `readOnlyHint: false` · `destructiveHint: false` · `idempotentHint: true` · `openWorldHint: true`

### Arguments

| Argument                 | Type                                                 | Required | Description                                                                                                                                                                                                    |
| ------------------------ | ---------------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`                     | ID (`sub_…`)                                         | yes      | –                                                                                                                                                                                                              |
| `expectedVersion`        | integer                                              | no       | The `version` you read (optimistic concurrency). (1–9007199254740991)                                                                                                                                          |
| `items`                  | array of object                                      | no       | Item changes: `{ id, priceId }` swaps a price, `{ id, quantity }` changes seats, `{ priceId, quantity }` adds an item, `{ id, deleted: true }` removes one. Items not named stay. (1–40 items)                 |
| `prorationBehavior`      | one of `create_prorations`, `always_invoice`, `none` | no       | `create_prorations` (credit unused time and charge the remaining time on the next invoice; a net credit goes to the customer credit balance), `always_invoice` (invoice the proration now) or `none`.          |
| `effective`              | one of `now`, `period_end`                           | no       | `now`, or at the end of the current period (`period_end`, stored as `pendingUpdate`). Default: upgrades and interval changes now with `always_invoice`, downgrades at the period end.                          |
| `paymentBehavior`        | one of `allow_incomplete`, `pending_if_incomplete`   | no       | For a change invoiced now: `allow_incomplete` (default; the change applies and a failed payment goes to dunning) or `pending_if_incomplete` (the old items stay until the invoice is paid).                    |
| `couponId`               | ID (`cpn_…`)                                         | no       | Apply a coupon to the subscription.                                                                                                                                                                            |
| `promotionCode`          | string                                               | no       | A promotion code as the customer typed it (case doesn't matter). (1–50 characters)                                                                                                                             |
| `collectionMethod`       | one of `charge_automatically`, `send_invoice`        | no       | `charge_automatically` (the default payment method is charged) or `send_invoice` (the invoice is emailed with bank transfer details and paid by the due date).                                                 |
| `daysUntilDue`           | integer or null                                      | no       | –                                                                                                                                                                                                              |
| `defaultPaymentMethodId` | ID (`pm_…`) or null                                  | no       | The payment method charged for this subscription (`null`: the customer's default).                                                                                                                             |
| `cancelPendingUpdate`    | boolean                                              | no       | Drop a change scheduled for the period end (`pendingUpdate`).                                                                                                                                                  |
| `usageThreshold`         | object or null                                       | no       | Invoice metered usage as soon as what it would charge reaches this amount (spec §16.7): limits the credit risk of usage-heavy customers. In the subscription's currency, whole minor units. `null` removes it. |
| `metadata`               | object                                               | no       | Your own key-value pairs (at most 50 keys). On updates the whole set is replaced.                                                                                                                              |
| `entity_id`              | ID (`ent_…`)                                         | no       | Optional: the brand's legal entity (ent\_…); `brand_id` alone is enough.                                                                                                                                       |
| `brand_id`               | ID (`brd_…`)                                         | no       | The brand to act on (brd\_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand.                                                                       |
| `idempotency_key`        | string                                               | no       | A unique string for this change. Retrying with the same key and arguments never acts twice. When left out, the server generates one and returns it in the result's `idempotency_key`. (1–255 characters)       |
| `dry_run`                | boolean                                              | no       | true: check permissions and rules and compute the result, then roll everything back. Nothing is saved. (default `false`)                                                                                       |

- **Brand:** pass `brand_id` with an organization or entity key; a brand key acts on its own brand.
- **Idempotency:** the result returns the `idempotency_key` used, yours or one the server generated. Retry with it: a call with the same key and arguments never acts twice (keys are kept for 24 hours).
- **Dry run:** supported. `dry_run: true` checks permissions and rules and computes the result, then rolls everything back.

### Errors

- [`validation_failed`](https://ownrecord.io/docs/reference/errors.md#validation_failed): A field is malformed or out of range.
- [`resource_not_found`](https://ownrecord.io/docs/reference/errors.md#resource_not_found): No subscription (or customer, price, coupon) with this ID is visible to the request.
- [`version_conflict`](https://ownrecord.io/docs/reference/errors.md#version_conflict): The subscription changed since you read it (`expectedVersion`), or at the same time; read it and retry.
- [`subscription_status_invalid`](https://ownrecord.io/docs/reference/errors.md#subscription_status_invalid): The subscription's status doesn't allow this (spec §16.1): see `details.reason`.
- [`subscription_item_not_found`](https://ownrecord.io/docs/reference/errors.md#subscription_item_not_found): An item `id` isn't one of the subscription's items.
- [`subscription_price_invalid`](https://ownrecord.io/docs/reference/errors.md#subscription_price_invalid): A new price isn't recurring, is archived, is in another currency, or its interval doesn't combine.
- [`subscription_meter_conflict`](https://ownrecord.io/docs/reference/errors.md#subscription_meter_conflict): Another live item of the customer already bills this meter.
- [`subscription_change_invalid`](https://ownrecord.io/docs/reference/errors.md#subscription_change_invalid): A change waits for its invoice to be paid, or `pending_if_incomplete` was asked for a `send_invoice` subscription.
- [`subscription_payment_method_invalid`](https://ownrecord.io/docs/reference/errors.md#subscription_payment_method_invalid): `defaultPaymentMethodId` isn't a saved, attached payment method of the customer.
- [`coupon_not_redeemable`](https://ownrecord.io/docs/reference/errors.md#coupon_not_redeemable): The coupon is archived, expired or used up.
- [`promotion_code_not_redeemable`](https://ownrecord.io/docs/reference/errors.md#promotion_code_not_redeemable): The promotion code can't be used (`details.reason`).
- [`discount_already_applied`](https://ownrecord.io/docs/reference/errors.md#discount_already_applied): The coupon is already applied to this subscription.
- [`registration_required`](https://ownrecord.io/docs/reference/errors.md#registration_required): An invoice issued now can't be taxed: the seller isn't registered where the customer is (a new sale).
- [`jurisdiction_blocked`](https://ownrecord.io/docs/reference/errors.md#jurisdiction_blocked): The customer's location is blocked for new sales.
- [`evidence_conflict`](https://ownrecord.io/docs/reference/errors.md#evidence_conflict): The customer's stored location evidence isn't enough to tax an invoice issued now (§13.3).
- [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied): The credentials can't change this brand's subscriptions (`subscriptions:write`).

### Examples

**Upgrade to Pro now**

The unused Basic time is credited and the Pro time to the period end is invoiced and charged now.

Arguments:

```json
{
  "id": "sub_01m4tx5nj8emwbyf7y9vcf47z5",
  "items": [
    {
      "id": "si_01m4tx5nj8emwbyf7y9vcf47za",
      "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y3"
    }
  ],
  "expectedVersion": 2,
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
  "idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
```

Result `output`:

```json
{
  "id": "sub_01m4tx5nj8emwbyf7y9vcf47z5",
  "object": "subscription",
  "livemode": false,
  "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47zm",
  "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
  "customerId": "cus_01m4tx5nj8emwbyf7y9vcf47z4",
  "status": "active",
  "items": [
    {
      "id": "si_01m4tx5nj8emwbyf7y9vcf47za",
      "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y3",
      "productId": "prod_01m4tx5nj8emwbyf7y9vcf47y0",
      "quantity": 3,
      "createdAt": "2026-10-13T12:00:00.000Z"
    }
  ],
  "currency": "EUR",
  "mrr": {
    "amount": "147000000",
    "currency": "EUR"
  },
  "collectionMethod": "charge_automatically",
  "daysUntilDue": null,
  "defaultPaymentMethodId": "pm_01m4tx5nj8emwbyf7y9vcf47zd",
  "billingCycleAnchor": "2026-10-13T12:00:00.000Z",
  "currentPeriodStart": "2026-10-13T12:00:00.000Z",
  "currentPeriodEnd": "2026-11-13T12:00:00.000Z",
  "trialStart": null,
  "trialEnd": null,
  "trialEndBehavior": "convert",
  "cancelAtPeriodEnd": false,
  "cancelAt": null,
  "canceledAt": null,
  "endedAt": null,
  "cancellation": null,
  "pause": null,
  "discountIds": [],
  "pendingUpdate": null,
  "latestInvoiceId": "inv_01m4tx5nj8emwbyf7y9vcf47zn",
  "incompleteExpiresAt": null,
  "testClockId": null,
  "dunning": null,
  "usageThreshold": null,
  "entitlementGraceUntil": null,
  "metadata": {
    "crm_account": "A-1042"
  },
  "version": 3,
  "createdAt": "2026-10-13T12:00:00.000Z",
  "updatedAt": "2026-10-20T09:00:00.000Z"
}
```

**Two seats fewer from the next period**

Arguments:

```json
{
  "id": "sub_01m4tx5nj8emwbyf7y9vcf47z5",
  "items": [
    {
      "id": "si_01m4tx5nj8emwbyf7y9vcf47za",
      "quantity": 1
    }
  ],
  "effective": "period_end",
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
  "idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
```

Result `output`:

```json
{
  "id": "sub_01m4tx5nj8emwbyf7y9vcf47z5",
  "object": "subscription",
  "livemode": false,
  "entityId": "ent_01m4tx5nj8emwbyf7y9vcf47zm",
  "brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
  "customerId": "cus_01m4tx5nj8emwbyf7y9vcf47z4",
  "status": "active",
  "items": [
    {
      "id": "si_01m4tx5nj8emwbyf7y9vcf47za",
      "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y2",
      "productId": "prod_01m4tx5nj8emwbyf7y9vcf47y0",
      "quantity": 3,
      "createdAt": "2026-10-13T12:00:00.000Z"
    },
    {
      "id": "si_01m4tx5nj8emwbyf7y9vcf47zb",
      "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y9",
      "productId": "prod_01m4tx5nj8emwbyf7y9vcf47y1",
      "quantity": 1,
      "createdAt": "2026-10-13T12:00:00.000Z"
    }
  ],
  "currency": "EUR",
  "mrr": {
    "amount": "87000000",
    "currency": "EUR"
  },
  "collectionMethod": "charge_automatically",
  "daysUntilDue": null,
  "defaultPaymentMethodId": "pm_01m4tx5nj8emwbyf7y9vcf47zd",
  "billingCycleAnchor": "2026-10-13T12:00:00.000Z",
  "currentPeriodStart": "2026-10-13T12:00:00.000Z",
  "currentPeriodEnd": "2026-11-13T12:00:00.000Z",
  "trialStart": null,
  "trialEnd": null,
  "trialEndBehavior": "convert",
  "cancelAtPeriodEnd": false,
  "cancelAt": null,
  "canceledAt": null,
  "endedAt": null,
  "cancellation": null,
  "pause": null,
  "discountIds": [],
  "pendingUpdate": {
    "kind": "period_end",
    "items": [
      {
        "id": "si_01m4tx5nj8emwbyf7y9vcf47za",
        "priceId": "price_01m4tx5nj8emwbyf7y9vcf47y2",
        "productId": "prod_01m4tx5nj8emwbyf7y9vcf47y0",
        "quantity": 1,
        "createdAt": "2026-10-13T12:00:00.000Z"
      }
    ],
    "effectiveAt": "2026-11-13T12:00:00.000Z",
    "requestedAt": "2026-10-20T09:00:00.000Z",
    "prorationBehavior": "none",
    "invoiceId": null,
    "expiresAt": null
  },
  "latestInvoiceId": "inv_01m4tx5nj8emwbyf7y9vcf47zn",
  "incompleteExpiresAt": null,
  "testClockId": null,
  "dunning": null,
  "usageThreshold": null,
  "entitlementGraceUntil": null,
  "metadata": {
    "crm_account": "A-1042"
  },
  "version": 3,
  "createdAt": "2026-10-13T12:00:00.000Z",
  "updatedAt": "2026-10-20T09:00:00.000Z"
}
```
