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 clocktest_clocks_create: Create a test clocktest_clocks_delete: Delete a test clocktest_clocks_get: Get a test clocktest_clocks_list: List test clocks
test_clocks_advance
Advance a test clock. Operation test_clocks.advance · 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_idwith an organization or entity key; a brand key acts on its own brand. - Idempotency: the result returns the
idempotency_keyused, 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: truechecks permissions and rules and computes the result, then rolls everything back. - Mode: test-mode keys only.
Errors
validation_failed:frozenTimeisn't a valid instant.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: The clock is advancing: wait until itsstatusisready.resource_not_found: No test clock with this ID exists for the brand in test mode.mode_not_supported: The request is in live mode: test clocks exist in test mode only.permission_denied: The credentials can't manage this brand's subscriptions (subscriptions:write).version_conflict: The clock changed at the same time; read it and retry.
Example
Advance a month
Arguments:
{
"id": "clk_01jacq4m3xf0v8w9zq2y7k5n6h",
"frozenTime": "2026-11-21T09:00:00.000Z",
"brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
"idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
Result output:
{
"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 · 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_idwith an organization or entity key; a brand key acts on its own brand. - Idempotency: the result returns the
idempotency_keyused, 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: truechecks permissions and rules and computes the result, then rolls everything back. - Mode: test-mode keys only.
Errors
validation_failed: The name is empty or too long, orfrozenTimeis out of range.mode_not_supported: The request is in live mode: test clocks exist in test mode only.permission_denied: The credentials can't manage this brand's subscriptions (subscriptions:write).
Example
A clock starting now
Arguments:
{
"name": "Monthly renewal",
"frozenTime": "2026-10-20T09:00:00.000Z",
"brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
"idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
Result output:
{
"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 · 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_idwith an organization or entity key; a brand key acts on its own brand. - Idempotency: the result returns the
idempotency_keyused, 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: truechecks permissions and rules and computes the result, then rolls everything back. - Mode: test-mode keys only.
Errors
test_clock_advancing: The clock is advancing: wait until itsstatusisready.resource_not_found: No test clock with this ID exists for the brand in test mode.mode_not_supported: The request is in live mode: test clocks exist in test mode only.permission_denied: The credentials can't manage this brand's subscriptions (subscriptions:write).
Example
Delete a clock
Arguments:
{
"id": "clk_01jacq4m3xf0v8w9zq2y7k5n6h",
"brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
"idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
Result output:
{
"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 · 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_idwith an organization or entity key; a brand key acts on its own brand. - Read-only: changes nothing;
idempotency_keyis ignored. - Mode: test-mode keys only.
Errors
resource_not_found: No test clock with this ID exists for the brand in test mode.mode_not_supported: The request is in live mode: test clocks exist in test mode only.permission_denied: The credentials can't read this brand's subscriptions.
Example
A clock after an advance
Arguments:
{
"id": "clk_01jacq4m3xf0v8w9zq2y7k5n6h",
"brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz"
}
Result output:
{
"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 · 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_idwith an organization or entity key; a brand key acts on its own brand. - Read-only: changes nothing;
idempotency_keyis ignored. - Mode: test-mode keys only.
Errors
validation_failed: A pagination value is malformed.mode_not_supported: The request is in live mode: test clocks exist in test mode only.permission_denied: The credentials can't read this brand's subscriptions.
Example
The brand's clocks
Arguments:
{
"brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz"
}
Result output:
{
"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
}