# Subscription

URL: /business/nouns/subscription · Id: `noun:subscription`

> A Subscription is a Customer’s standing acceptance of an Offer, billed each Period until canceled.

A Subscription is a [Customer](/business/nouns/customer)’s standing acceptance of a recurring [Offer](/business/nouns/offer), renewed and billed each period until canceled.

## Properties
| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `status` | `string` | Yes | One of `active`, `trialing`, `pastDue`, `paused`, `incomplete`, or `canceled`. |
| `renewsAt` | `datetime` | No | When it next renews. |
| `quantity` | `integer` | No | How many units of the Offer’s Price it holds, such as 12 members; 1 by default. |
| `trialEndsAt` | `datetime` | No | When a trial ends and the first paid period starts. |
| `termEndsAt` | `datetime` | No | When a committed term ends; the Renewal and the renewal notice read it. |

## Object
```json
{
  "$id": "https://api.sb/routewise.dev/subscriptions/subscription_1",
  "$type": "Subscription",
  "status": "active",
  "renewsAt": "2026-10-22T12:00:00Z",
  "quantity": 1,
  "trialEndsAt": "2026-10-22T12:00:00Z",
  "termEndsAt": "2026-10-22T12:00:00Z"
}
```

## Relationships
- <a id="rel-bills"></a>A Subscription **bills** many [Invoices](/business/nouns/invoice): the [Invoices](/business/nouns/invoice) the Subscription issues, one for each period it renews. `bills`, inverse [`billedFor`](/business/nouns/invoice#rel-billed-for).
- <a id="rel-quote"></a>A Subscription **has** one [Quote](/business/nouns/quote): the Subscription for a [Quote](/business/nouns/quote)’s recurring lines, started when the [Customer](/business/nouns/customer) accepts it. `quote`, inverse [`startsSubscription`](/business/nouns/quote#rel-starts-subscription).
- <a id="rel-renewals"></a>A Subscription **has** many [Renewals](/business/nouns/renewal): each [Renewal](/business/nouns/renewal) decides one term of one Subscription; a Subscription has one Renewal per term. `renewals`, inverse [`renews`](/business/nouns/renewal#rel-renews).
- <a id="rel-renews"></a>A Subscription **renews** one [Offer](/business/nouns/offer): a Subscription bills one recurring [Offer](/business/nouns/offer) each [Period](/business/nouns/period) until canceled. `renews`, inverse [`subscriptions`](/business/nouns/offer#rel-subscriptions).
- <a id="rel-subscriber"></a>A Subscription’s **subscriber** is one [Customer](/business/nouns/customer): a [Customer](/business/nouns/customer) holds Subscriptions, each billed once per [Period](/business/nouns/period). `subscriber`, inverse [`maintains`](/business/nouns/customer#rel-maintains).

## Lifecycle

| State | Meaning | Moves to |
| --- | --- | --- |
| `incomplete` (first) | The Subscription exists and its first period is billed but not yet paid. | `trialing` by [Offer.trial](/business/nouns/offer/trial); `active` on [`Invoice.collected`](/business/events/Invoice.collected) when the Invoice bills this Subscription’s first period; `canceled` by [Subscription.unsubscribe](/business/nouns/subscription/unsubscribe) |
| `trialing` | The Customer uses the Offer free until `trialEndsAt`. | `active` by [Subscription.renew](/business/nouns/subscription/renew); `canceled` by [Subscription.unsubscribe](/business/nouns/subscription/unsubscribe) |
| `active` | The Subscription renews each period and its Entitlements hold. | `paused` by [Subscription.pause](/business/nouns/subscription/pause); `pastDue` on [`Invoice.overdue`](/business/nouns/invoice#invoiceoverdue) when the Invoice bills this Subscription; `canceled` by [Subscription.unsubscribe](/business/nouns/subscription/unsubscribe) |
| `pastDue` | A renewal Invoice is unpaid while its retries run; Entitlements still hold. | `active` on [`Invoice.collected`](/business/events/Invoice.collected) when the Invoice bills this Subscription; `canceled` on [`Invoice.overdue`](/business/nouns/invoice#invoiceoverdue) when every retry on the Startup’s retry schedule has failed |
| `paused` | Billing and Entitlements stop until the pause ends, and the term moves by the paused days. | `active` by [Subscription.resume](/business/nouns/subscription/resume); `canceled` by [Subscription.unsubscribe](/business/nouns/subscription/unsubscribe) |
| `canceled` | The Subscription has ended; the Customer starts again with a new one. | None: it ends here. |

## Verbs
| Verb | Description | Subject | Event | Class |
| --- | --- | --- | --- | --- |
| [Subscription.keep](/business/nouns/subscription/keep) | Keep takes back a cancel before the period closes, so the Subscription renews on its date at the same terms. | [Billing Specialist](/agents/finance/billing-specialist) | [`Subscription.kept`](/business/events/Subscription.kept) | Two-way: `try`, `send`, `do` |
| [Subscription.pause](/business/nouns/subscription/pause) | Pause stops billing and Entitlements on a Subscription until a date, without ending it. | [Billing Specialist](/agents/finance/billing-specialist) | [`Subscription.paused`](/business/events/Subscription.paused) | Two-way: `try`, `send`, `do` |
| [Subscription.renew](/business/nouns/subscription/renew) | Renew starts a Subscription’s next period and bills it at the Offer Version the Customer accepted. | [Billing Specialist](/agents/finance/billing-specialist) | [`Subscription.renewed`](/business/events/Subscription.renewed) | Two-way: `try`, `send`, `do` |
| [Subscription.resize](/business/nouns/subscription/resize) | Resize changes how many units a Subscription holds and prorates the current period. | [Billing Specialist](/agents/finance/billing-specialist) | [`Subscription.resized`](/business/events/Subscription.resized) | Two-way: `try`, `send`, `do` |
| [Subscription.resume](/business/nouns/subscription/resume) | Resume restarts billing and Entitlements on a paused Subscription before its pause ends. | [Billing Specialist](/agents/finance/billing-specialist) | [`Subscription.resumed`](/business/events/Subscription.resumed) | Two-way: `try`, `send`, `do` |
| [Subscription.switch](/business/nouns/subscription/switch) | Switch moves a Subscription to another Offer and prorates the current period. | [Billing Specialist](/agents/finance/billing-specialist) | [`Subscription.switched`](/business/events/Subscription.switched) | Two-way: `try`, `send`, `do` |
| [Subscription.unsubscribe](/business/nouns/subscription/unsubscribe) | Unsubscribe ends a Subscription at the close of its current period, and the Customer keeps access until then. | [Billing Specialist](/agents/finance/billing-specialist) | [`Subscription.unsubscribed`](/business/events/Subscription.unsubscribed) | Two-way: `try`, `send`, `do` |
| <a id="create"></a>[Subscription.create](/business/nouns/subscription/create) | Creates a Subscription. Inherited from [Noun](/business/nouns/noun). | None. | `Subscription.created` | Two-way: `try`, `send`, `do` |
| <a id="get"></a>[Subscription.get](/business/nouns/subscription/get) | Returns one Subscription by id. Inherited from [Noun](/business/nouns/noun). | None. | None. | Read: `try`, `do` |
| <a id="list"></a>[Subscription.list](/business/nouns/subscription/list) | Returns Subscriptions, newest first, one page at a time. Inherited from [Noun](/business/nouns/noun). | None. | None. | Read: `try`, `do` |
| <a id="update"></a>[Subscription.update](/business/nouns/subscription/update) | Changes the given properties of a Subscription. Inherited from [Noun](/business/nouns/noun). | None. | `Subscription.updated` | Two-way: `try`, `send`, `do` |

## Events
Events no Verb emits. Each Verb’s Event is in the Verbs table above; every Event is delivered in the same shape.

### Subscription.pastDue
A Subscription moved to `pastDue` because its renewal Invoice went overdue. Raised by a state change.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | `string` | Yes | `Subscription.pastDue`. |
| `at` | `datetime` | Yes | When it happened. |
| `seq` | `integer` | No | Its position in the namespace, one more than the Event before; any seq is a cursor into the history. |
| `data` | `json` | Yes | The Thing as the Action left it. |
| `data.subscription` | [Subscription](/business/nouns/subscription) | Yes | The Subscription as the change left it. |
| `data.subscription.status` | `string` | Yes | One of `active`, `trialing`, `pastDue`, `paused`, `incomplete`, or `canceled`. |
| `data.subscription.renewsAt` | `datetime` | No | When it next renews. |
| `data.subscription.quantity` | `integer` | No | How many units of the Offer’s Price it holds, such as 12 members; 1 by default. |
| `data.subscription.trialEndsAt` | `datetime` | No | When a trial ends and the first paid period starts. |
| `data.subscription.termEndsAt` | `datetime` | No | When a committed term ends; the Renewal and the renewal notice read it. |
| `data.invoice` | [Invoice](/business/nouns/invoice) | Yes | The overdue renewal Invoice. |
| `data.previous.status` | `string` | Yes | The `status` before this Event: `active`. |

```json
{
  "$id": "https://api.sb/routewise.dev/events/event_1",
  "$type": "Event",
  "name": "Subscription.pastDue",
  "at": "2026-10-22T12:00:00Z",
  "data": {
    "subscription": {
      "$id": "https://api.sb/routewise.dev/subscriptions/subscription_1",
      "$type": "Subscription",
      "status": "pastDue",
      "renewsAt": "2026-10-22T12:00:00Z",
      "quantity": 1,
      "trialEndsAt": "2026-10-22T12:00:00Z",
      "termEndsAt": "2026-10-22T12:00:00Z"
    },
    "invoice": {
      "$id": "https://api.sb/routewise.dev/invoices/invoice_1",
      "$type": "Invoice",
      "total": {
        "amount": 25,
        "currency": "USD"
      },
      "due": "2026-10-22"
    },
    "previous": {
      "status": "active"
    }
  },
  "seq": 1
}
```

## Permissions
Which Access level may call each Verb. One-way Verbs wait their delay window.

| Operation | `owner` | `admin` | `member` | `viewer` |
| --- | --- | --- | --- | --- |
| `Subscription.create` | Yes | Yes | Yes | No |
| `Subscription.get` | Yes | Yes | Yes | Yes |
| `Subscription.list` | Yes | Yes | Yes | Yes |
| `Subscription.update` | Yes | Yes | Yes | No |
| `Subscription.keep` | Yes | Yes | Yes | No |
| `Subscription.pause` | Yes | Yes | Yes | No |
| `Subscription.renew` | Yes | Yes | Yes | No |
| `Subscription.resize` | Yes | Yes | Yes | No |
| `Subscription.resume` | Yes | Yes | Yes | No |
| `Subscription.switch` | Yes | Yes | Yes | No |
| `Subscription.unsubscribe` | Yes | Yes | Yes | No |

## Stripe
**Subscription** (`subscription`). The source of truth is db.sb, and Stripe holds a copy written from it.

| Property | Stripe field | Source of truth |
| --- | --- | --- |
| `status` | `status` | Stripe |
| `renewsAt` | `items.data[].current_period_end` | Stripe |
| `quantity` | `items.data[].quantity` | db.sb |
| `trialEndsAt` | `trial_end` | db.sb |

| State | Stripe status |
| --- | --- |
| `incomplete` | `incomplete` |
| `trialing` | `trialing` |
| `active` | `active` |
| `pastDue` | `past_due` |
| `paused` | `paused` |
| `canceled` | `canceled` |

## Call it

**Ask**

```text
Renew the latest subscription.
```

**API**

```bash
curl -X POST https://api.sb/tutorloop.com/subscriptions/subscription_1/renew \
  -H "Authorization: Bearer $STARTUP_BUILDER_API_KEY"
```

```json
{
  "api": "https://api.sb/tutorloop.com",
  "invoice": {
    "$id": "https://api.sb/tutorloop.com/invoices/invoice_1",
    "$type": "Invoice",
    "total": {
      "amount": 60,
      "currency": "USD"
    },
    "due": "2026-10-22"
  },
  "subscription": {
    "$id": "https://api.sb/tutorloop.com/subscriptions/subscription_1",
    "$type": "Subscription",
    "status": "active"
  },
  "action": {
    "$id": "https://api.sb/tutorloop.com/actions/action_1",
    "operation": "Subscription.renew",
    "status": "done"
  },
  "links": {
    "self": "https://api.sb/tutorloop.com/actions/action_1"
  }
}
```

**SDK**

```ts
import { $ } from 'startup-builder'

const { invoice, subscription } = await $.Subscription.renew({ subscription: 'subscription_1' })
```

**CLI**

```bash
npx startup-builder do Subscription.renew --json '{"subscription":"subscription_1"}'
```

**MCP**

```json
{
  "name": "do",
  "arguments": {
    "code": "return await $.Subscription.renew({ subscription: 'subscription_1' })"
  }
}
```

## Example
A dental office's Subscription to the $99 monthly reminders [Offer](/business/nouns/offer) renews on the 1st and bills one [Invoice](/business/nouns/invoice) each month until the office unsubscribes.