Skip to content

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 · 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

ArgumentTypeRequiredDescription
idID (clk_…)yes–
frozenTimedate-time (ISO 8601)yesThe time to move the clock to: after its current time, at most 732 days ahead.
entity_idID (ent_…)noOptional: the brand's legal entity (ent_…); brand_id alone is enough.
brand_idID (brd_…)noThe 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_keystringnoA 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_runbooleannotrue: 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

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 · 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

ArgumentTypeRequiredDescription
namestringyesA name for the clock, e.g. the scenario it tests. (1–100 characters)
frozenTimedate-time (ISO 8601)noThe clock's starting time (default: now), within a year back and five years ahead.
entity_idID (ent_…)noOptional: the brand's legal entity (ent_…); brand_id alone is enough.
brand_idID (brd_…)noThe 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_keystringnoA 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_runbooleannotrue: 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: The name is empty or too long, or frozenTime is 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:

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 · 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

ArgumentTypeRequiredDescription
idID (clk_…)yes–
entity_idID (ent_…)noOptional: the brand's legal entity (ent_…); brand_id alone is enough.
brand_idID (brd_…)noThe 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_keystringnoA 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_runbooleannotrue: 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

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 · 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

ArgumentTypeRequiredDescription
idID (clk_…)yes–
entity_idID (ent_…)noOptional: the brand's legal entity (ent_…); brand_id alone is enough.
brand_idID (brd_…)noThe 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

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 · 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

ArgumentTypeRequiredDescription
limitintegerno(1–100)
starting_afterID (clk_…)no–
entity_idID (ent_…)noOptional: the brand's legal entity (ent_…); brand_id alone is enough.
brand_idID (brd_…)noThe 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

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
}