API · Conventions
Test clocks
Advance simulated wall-clock time to exercise calendar-driven logic — vesting cliffs, franchise-tax windows, 83(b) deadlines — without waiting real time.
Last updated
TL;DR. Test-mode only. POST /v1/test_clocks with a frozen_time. Attach an
entity at creation by setting Entity.test_clock. POST /v1/test_clocks/{id}/advance
to jump forward — all calendar-driven events that would have fired in the traversed
window fire in order. Pair with X-Matter-Test-Speed: instant for synchronous CI.
Matter's test mode simulates the full lifecycle on a controllable timeline. Two controls compose:
X-Matter-Test-Speed: instant | fast | real— entity-lifetime simulation. Governs how long filings and state responses take.TestClock— calendar-driven simulation. Governs what wall-clock time an entity thinks it is.
Use X-Matter-Test-Speed when you want filings to settle synchronously in CI. Use
TestClock when you want to see what happens on the 30-day 83(b) deadline, the
12-month franchise-tax window, or a four-year vesting cliff — without waiting real
time.
Create a clock
POST /v1/test_clocks
{
"name": "FY26 year-end",
"frozen_time": 1735689600
}Response:
{
"id": "clk_Qw5xY2bR",
"object": "test_clock",
"name": "FY26 year-end",
"frozen_time": 1735689600,
"status": "ready",
"attached_entity_count": 0,
"livemode": false,
"created": 1745251200
}Attach an entity
Set test_clock on entity creation:
POST /v1/entities
{
"type": "c_corp",
"jurisdiction": "US-DE",
"legal_name": "Clockwork Inc.",
"test_clock": "clk_Qw5xY2bR",
"founders": [ /* ... */ ]
}All date math on this entity — vesting, deadlines, annual reports, franchise-tax windows — derives from the clock, not wall-clock time.
Why only at creation?
Attaching a clock to an existing entity would make its existing filings, grants, and
audit entries inconsistent with its new date-math source. Matter rejects
retro-attachment with 409 test_clock_retro_attach_unsupported. Create a fresh
entity when you need a clocked test run.
Advance
POST /v1/test_clocks/clk_Qw5xY2bR/advance
{
"frozen_time": 1767225600
}Returns 202 Accepted. clock.status becomes advancing while Matter materializes
every deadline event that would have fired in the traversed window, in order, with
strict per-entity sequence numbers — just like real time. When everything has
emitted, status: ready and a test_clock.advanced event fires.
Cannot rewind. frozen_time must be ≥ the current frozen_time. Create a fresh
clock if you need to replay a past window.
What fires on advance
For every attached entity, these event categories are replayed in wall-clock order
between the old frozen_time and the new one:
compliance.deadline_approaching,compliance.deadline_missedgrant.vested(monthly vest events cross the window)grant.cliff_passedfiling.due,filing.overdueeighty_three_b.window_closedboi.update_duefranchise_tax.window_opened,franchise_tax.dueannual_report.due,annual_report.late
Common patterns
Test a four-year vesting cliff
# Create a clocked entity on 2026-04-22
POST /v1/test_clocks { "frozen_time": 1745251200 } # -> clk_A
POST /v1/entities { ..., "test_clock": "clk_A" } # -> ent_B
# Issue a grant with standard 4yr/1yr-cliff vesting
POST /v1/entities/ent_B/grants { ..., "vesting": { "schedule": "4y-1y-cliff" } }
# Jump forward 13 months to exercise the cliff
POST /v1/test_clocks/clk_A/advance { "frozen_time": 1779494400 }
# → grant.cliff_passed fires
# → grant.vested fires (25% of shares vest)Test a missed franchise-tax deadline
# Form a Delaware C-Corp
POST /v1/test_clocks { "frozen_time": 1735689600 } # Jan 1 2026 -> clk_A
POST /v1/entities { "jurisdiction": "US-DE", ..., "test_clock": "clk_A" } # -> ent_B
# Jump past the March 1 franchise-tax deadline without filing
POST /v1/test_clocks/clk_A/advance { "frozen_time": 1741900800 } # Mar 15 2026
# → franchise_tax.due fires
# → franchise_tax.overdue fires
# → entity.state_changed (active → suspended) fires
# → compliance.deadline_missed firesReplay an 83(b) window expiring
# Entity formed, founder grants issued, 83(b) not yet submitted
POST /v1/test_clocks { "frozen_time": NOW } # -> clk_A
POST /v1/entities { ..., "test_clock": "clk_A" } # -> ent_B
POST /v1/entities/ent_B/grants { ..., "eighty_three_b_required": true } # -> grt_C
# Jump forward 31 days
POST /v1/test_clocks/clk_A/advance { "frozen_time": NOW + 31*86400 }
# → eighty_three_b.window_closed fires
# → grant status -> ordinary_income_hazardComposition with X-Matter-Test-Speed
The two controls compose. A clocked entity still obeys X-Matter-Test-Speed for
async response timing:
# Advance the clock by 12 months, but settle every resulting filing synchronously
curl -X POST https://api.mattermode.com/v1/test_clocks/clk_A/advance \
-H "Matter-Version: 2026-05-01" \
-H "X-Matter-Test-Speed: instant" \
-H "Content-Type: application/json" \
-d '{"frozen_time": 1767225600}'This is the canonical CI pattern — X-Matter-Test-Speed: instant so the advance
response blocks until every simulated event has landed, then assert on the resulting
state.
Delete
DELETE /v1/test_clocks/{id}Detaches from any attached entities; detached entities fall back to wall-clock time.
Returns 204 No Content.
Live mode
Test clocks are strictly test-mode. Creating one with a live key returns
403 test_mode_required. This is intentional — calendar manipulation on a live
entity would corrupt its filing cadence and compliance history.