Sandbox testing
Sandbox workspaces let you exercise billing flows without real money movement. Two test artifacts are available in sandbox and return 403 FORBIDDEN in live workspaces: test clocks simulate the passage of time, and payment simulations pin deterministic charge outcomes. Sandbox keys use the sk_test_... prefix - see Workspace context.
Test clocks
In a sandbox workspace, a test clock simulates the passage of time so you can exercise renewals, phase changes, dunning and trial ends without waiting. A sandbox has at most one test clock: creating a second one answers 409 CONFLICT naming the existing clock, so advance or delete that one instead.
Code
Request body:
| Field | Type | Default | Notes |
|---|---|---|---|
name | string | "Default Clock" | Optional label. |
frozen_at | RFC 3339 timestamp | now | The instant the clock starts at. |
Response (201) returns the clock with fields id, workspace_id, name, frozen_at, status, created_at, updated_at, and advancing_to while an advance is in progress.
Code
frozen_at is required on advance and must be after the clock's current frozen_at: a test clock moves forward only, and asking for an instant at or before where it stands answers 409 CONFLICT. So does advancing a clock that is already advancing.
The advance runs in the background. The clock steps from one due instant to the next and lets everything due at that instant run (invoice runs, phase transitions, dunning steps) before it moves on, so work that one job schedules for a later instant inside the window still fires. Poll GET /v1/test-clocks/{id} to follow it:
status | Meaning |
|---|---|
active | The clock stands at frozen_at. |
advancing | An advance is stepping it towards advancing_to. |
failed | An advance hit its run budget and stopped at frozen_at, short of advancing_to. The work done up to there stays; advancing again resumes from where it stopped. |
Requests in the workspace keep working while the clock advances; they see the instant the clock currently stands at.
Other test-clock endpoints: GET /v1/test-clocks, GET /v1/test-clocks/{id}, DELETE /v1/test-clocks/{id}.
Payment simulations
Assign a fixed outcome to a payment method so that any charge against it resolves to that outcome instead of being sent to a real gateway.
Code
| Field | Required | Notes |
|---|---|---|
payment_method_id | yes | UUID of an existing sandbox payment method. |
outcome | yes | One of: success, decline, insufficient_funds, expired_card, fraud, processing_error, network_error, requires_action, mandate_failure. |
The response (201) returns the simulation with id, workspace_id, payment_method_id, outcome, created_at, and last_used_at once a charge has used it.
Other endpoints: GET /v1/test-payment-simulations, DELETE /v1/test-payment-simulations/{id}.
Combine the two to rehearse dunning: pin a failing outcome on the customer's payment method, then advance the clock past the invoice's due date and through the dunning steps, and watch the invoice.payment_attempt_failed and subscription.dunning_entered webhook events arrive.
Demo data
Seeding a sandbox with demo data and resetting it are dashboard features; there is no API for them.