# Test clocks tools

> MCP tools for Test clocks: test_clocks_advance, test_clocks_create, test_clocks_delete, test_clocks_get, test_clocks_list.

- `test_clocks_advance`: Advance a test clock
- `test_clocks_create`: Create a test clock
- `test_clocks_delete`: Delete a test clock
- `test_clocks_get`: Get a test clock
- `test_clocks_list`: List test clocks

## `test_clocks_advance`

**Advance a test clock.** Operation [`test_clocks.advance`](https://ownrecord.io/docs/reference/test-clocks-advance.md) · Brand level · permission `subscriptions:write` · risk tier `write` · since M5

Moves a test clock forward to `frozenTime`. The clock's `status` becomes `advancing` at once; in the background,
every step due on its customers' subscriptions up to that time runs in time order, each at its own time: trial
notices and trial ends, `invoice.upcoming`, renewal drafts an hour before each period end, renewals (invoices
finalized, charged or sent), scheduled changes and price migrations, cancellations at the period end, pause
resumptions, the 23-hour expiry of unpaid subscriptions, and collection: dunning retries and their final action,
send_invoice reminders and overdue, and card-expiry reminders. Then the clock is `ready` at the new time
(`test_clock.ready`).

Read the clock with `test_clocks.get` until it is `ready`. Off-session charges complete through the processor
afterwards, as they do in real time, and their outcome is recorded at the clock's time. If a step fails, the
clock stops at the last step that ran with
`status: internal_failure` and `advance.error`; fix the cause and advance again.

An advance moves the clock at most 732 days; advance several times to go further. Emits
`test_clock.advancing`.

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

### Arguments

| Argument          | Type                 | Required | Description                                                                                                                                                                                              |
| ----------------- | -------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`              | ID (`clk_…`)         | yes      | –                                                                                                                                                                                                        |
| `frozenTime`      | date-time (ISO 8601) | yes      | The time to move the clock to: after its current time, at most 732 days ahead.                                                                                                                           |
| `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.
- **Mode:** test-mode keys only.

### Errors

- [`validation_failed`](https://ownrecord.io/docs/reference/errors.md#validation_failed): `frozenTime` isn't a valid instant.
- [`test_clock_advance_invalid`](https://ownrecord.io/docs/reference/errors.md#test_clock_advance_invalid): The time isn't after the clock's time, or is more than 732 days ahead (`details.reason`).
- [`test_clock_advancing`](https://ownrecord.io/docs/reference/errors.md#test_clock_advancing): The clock is advancing: wait until its `status` is `ready`.
- [`resource_not_found`](https://ownrecord.io/docs/reference/errors.md#resource_not_found): No test clock with this ID exists for the brand in test mode.
- [`mode_not_supported`](https://ownrecord.io/docs/reference/errors.md#mode_not_supported): The request is in live mode: test clocks exist in test mode only.
- [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied): The credentials can't manage this brand's subscriptions (`subscriptions:write`).
- [`version_conflict`](https://ownrecord.io/docs/reference/errors.md#version_conflict): The clock changed at the same time; read it and retry.

### Example

**Advance a month**

Arguments:

```json
{
  "id": "clk_01jacq4m3xf0v8w9zq2y7k5n6h",
  "frozenTime": "2026-11-21T09:00:00.000Z",
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
  "idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
```

Result `output`:

```json
{
  "id": "clk_01jacq4m3xf0v8w9zq2y7k5n6h",
  "object": "test_clock",
  "livemode": false,
  "brandId": "brd_01jacq4m3xf0v8w9zq2y7k5n6b",
  "name": "Monthly renewal",
  "frozenTime": "2026-10-20T09:00:00.000Z",
  "status": "advancing",
  "advance": {
    "from": "2026-10-20T09:00:00.000Z",
    "to": "2026-11-21T09:00:00.000Z",
    "requestedAt": "2026-10-20T09:00:00.000Z",
    "completedAt": null,
    "steps": 0,
    "error": null
  },
  "version": 2,
  "createdAt": "2026-10-20T09:00:00.000Z",
  "updatedAt": "2026-10-20T09:00:00.000Z"
}
```

## `test_clocks_create`

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

Creates a test clock (test mode only): a time of its own that customers can be attached to when they are
created (`customers.create` with `testClockId`). Their subscriptions then bill at the clock's time: renewals,
trial ends, cancellations and notices happen when you advance the clock (`test_clocks.advance`), not when real
time passes. Use it to test billing scenarios end to end in seconds.

`frozenTime` is the clock's starting time (default: now), within a year back and five years ahead. A clock holds
at most 10 customers. Emits `test_clock.created`.

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

### Arguments

| Argument          | Type                 | Required | Description                                                                                                                                                                                              |
| ----------------- | -------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`            | string               | yes      | A name for the clock, e.g. the scenario it tests. (1–100 characters)                                                                                                                                     |
| `frozenTime`      | date-time (ISO 8601) | no       | The clock's starting time (default: now), within a year back and five years ahead.                                                                                                                       |
| `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.
- **Mode:** test-mode keys only.

### Errors

- [`validation_failed`](https://ownrecord.io/docs/reference/errors.md#validation_failed): The name is empty or too long, or `frozenTime` is out of range.
- [`mode_not_supported`](https://ownrecord.io/docs/reference/errors.md#mode_not_supported): The request is in live mode: test clocks exist in test mode only.
- [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied): The credentials can't manage this brand's subscriptions (`subscriptions:write`).

### Example

**A clock starting now**

Arguments:

```json
{
  "name": "Monthly renewal",
  "frozenTime": "2026-10-20T09:00:00.000Z",
  "brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
  "idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
```

Result `output`:

```json
{
  "id": "clk_01jacq4m3xf0v8w9zq2y7k5n6h",
  "object": "test_clock",
  "livemode": false,
  "brandId": "brd_01jacq4m3xf0v8w9zq2y7k5n6b",
  "name": "Monthly renewal",
  "frozenTime": "2026-10-20T09:00:00.000Z",
  "status": "ready",
  "advance": null,
  "version": 1,
  "createdAt": "2026-10-20T09:00:00.000Z",
  "updatedAt": "2026-10-20T09:00:00.000Z"
}
```

## `test_clocks_delete`

**Delete a test clock.** Operation [`test_clocks.delete`](https://ownrecord.io/docs/reference/test-clocks-delete.md) · Brand level · permission `subscriptions:write` · risk tier `write` · since M5

Deletes a test clock with what it simulated: its customers' live subscriptions are canceled at once at the
clock's time (nothing more is billed or credited), its customers are deleted, and the clock is removed. Invoices
and ledger entries made while it ran stay, as test-mode records. Refused while the clock is advancing. Emits
`test_clock.deleted` (and `subscription.canceled`, `customer.updated` for what it ended).

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

### Arguments

| Argument          | Type         | Required | Description                                                                                                                                                                                              |
| ----------------- | ------------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`              | ID (`clk_…`) | 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.                                                                 |
| `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.
- **Mode:** test-mode keys only.

### Errors

- [`test_clock_advancing`](https://ownrecord.io/docs/reference/errors.md#test_clock_advancing): The clock is advancing: wait until its `status` is `ready`.
- [`resource_not_found`](https://ownrecord.io/docs/reference/errors.md#resource_not_found): No test clock with this ID exists for the brand in test mode.
- [`mode_not_supported`](https://ownrecord.io/docs/reference/errors.md#mode_not_supported): The request is in live mode: test clocks exist in test mode only.
- [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied): The credentials can't manage this brand's subscriptions (`subscriptions:write`).

### Example

**Delete a clock**

Arguments:

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

Result `output`:

```json
{
  "id": "clk_01jacq4m3xf0v8w9zq2y7k5n6h",
  "object": "test_clock",
  "livemode": false,
  "brandId": "brd_01jacq4m3xf0v8w9zq2y7k5n6b",
  "name": "Monthly renewal",
  "frozenTime": "2026-10-20T09:00:00.000Z",
  "status": "ready",
  "advance": null,
  "version": 1,
  "createdAt": "2026-10-20T09:00:00.000Z",
  "updatedAt": "2026-10-20T09:00:00.000Z"
}
```

## `test_clocks_get`

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

Returns a test clock: its time (`frozenTime`), its `status` and its latest advance. After
`test_clocks.advance`, read it until `status` is `ready` (or `internal_failure`, with `advance.error`).

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

### Arguments

| Argument    | Type         | Required | Description                                                                                                                              |
| ----------- | ------------ | -------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `id`        | ID (`clk_…`) | 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.
- **Mode:** test-mode keys only.

### Errors

- [`resource_not_found`](https://ownrecord.io/docs/reference/errors.md#resource_not_found): No test clock with this ID exists for the brand in test mode.
- [`mode_not_supported`](https://ownrecord.io/docs/reference/errors.md#mode_not_supported): The request is in live mode: test clocks exist in test mode only.
- [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied): The credentials can't read this brand's subscriptions.

### Example

**A clock after an advance**

Arguments:

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

Result `output`:

```json
{
  "id": "clk_01jacq4m3xf0v8w9zq2y7k5n6h",
  "object": "test_clock",
  "livemode": false,
  "brandId": "brd_01jacq4m3xf0v8w9zq2y7k5n6b",
  "name": "Monthly renewal",
  "frozenTime": "2026-11-21T09:00:00.000Z",
  "status": "ready",
  "advance": {
    "from": "2026-10-20T09:00:00.000Z",
    "to": "2026-11-21T09:00:00.000Z",
    "requestedAt": "2026-10-20T09:00:00.000Z",
    "completedAt": "2026-10-20T09:00:04.000Z",
    "steps": 3,
    "error": null
  },
  "version": 3,
  "createdAt": "2026-10-20T09:00:00.000Z",
  "updatedAt": "2026-10-20T09:00:04.000Z"
}
```

## `test_clocks_list`

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

Lists the brand's test clocks (test mode), newest first.

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                                                                                                                              |
| ---------------- | ------------ | -------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `limit`          | integer      | no       | (1–100)                                                                                                                                  |
| `starting_after` | ID (`clk_…`) | 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.
- **Mode:** test-mode keys only.

### Errors

- [`validation_failed`](https://ownrecord.io/docs/reference/errors.md#validation_failed): A pagination value is malformed.
- [`mode_not_supported`](https://ownrecord.io/docs/reference/errors.md#mode_not_supported): The request is in live mode: test clocks exist in test mode only.
- [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied): The credentials can't read this brand's subscriptions.

### Example

**The brand's clocks**

Arguments:

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

Result `output`:

```json
{
  "object": "list",
  "data": [
    {
      "id": "clk_01jacq4m3xf0v8w9zq2y7k5n6h",
      "object": "test_clock",
      "livemode": false,
      "brandId": "brd_01jacq4m3xf0v8w9zq2y7k5n6b",
      "name": "Monthly renewal",
      "frozenTime": "2026-10-20T09:00:00.000Z",
      "status": "ready",
      "advance": null,
      "version": 1,
      "createdAt": "2026-10-20T09:00:00.000Z",
      "updatedAt": "2026-10-20T09:00:00.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}
```
