Test runs API
Synthetic test subscriptions ("CMS preview" of your subscription lifecycle): Checkbox subscribes a test customer in your billing platform's TEST mode, receives your emails at its own inbox, fast-forwards a Stripe test clock through trial end and renewal, cancels online, and reports every step with e
vidence, check results and fixes. Nothing is charged.
| Operation | Endpoint |
|---|---|
| List billing test-mode keys of a site | GET /v1/sites/{site}/test_credentials |
| Store a billing test-mode key | POST /v1/sites/{site}/test_credentials |
| Delete a billing test-mode key | DELETE /v1/sites/{site}/test_credentials/{test_credential} |
| List registered checkout configs | GET /v1/sites/{site}/stripe_checkout_configs |
| Register the Checkout Session params your code uses | POST /v1/sites/{site}/stripe_checkout_configs |
| Retrieve a registered checkout config | GET /v1/stripe_checkout_configs/{stripe_checkout_config} |
| Delete a registered checkout config | DELETE /v1/stripe_checkout_configs/{stripe_checkout_config} |
| List test runs of a site | GET /v1/sites/{site}/test_runs |
| Start a lifecycle test run | POST /v1/sites/{site}/test_runs |
| Retrieve a test run | GET /v1/test_runs/{test_run} |
| Cancel a test run | POST /v1/test_runs/{test_run}/cancel |
The StripeCheckoutConfig object
Checkout Session parameters your code uses, registered so test runs mirror exactly your checkout into Stripe test mode.
| Field | Type | Description |
|---|---|---|
id | string | Unique identifier of the stripe checkout config (scc_…). |
object | enum | String representing the object's type. Always "stripe_checkout_config". |
livemode | boolean | true for live-mode objects, false for test mode (ck_test_ keys act on an isolated sandbox). |
site | string | The site the config belongs to. |
name | string | null | Your name for the config. |
params | object | The mirrored Checkout Session parameters (the subset of what your code passes to stripe.checkout.sessions.create that shapes what customers see). |
params_hash | string | sha256 of the canonical params; changes whenever the registered parameters change. |
ignored_params | array of strings | Parameters that were dropped because they are not mirrored (customer, URLs, metadata…). |
metadata | object | Up to 20 key/value string pairs you can attach to the object. |
created | integer | When the config was registered. Unix timestamp in seconds. |
List billing test-mode keys of a site
GET /v1/sites/{site}/test_credentials
The site's stored test-mode keys (hints only).
Scope test_runs:read · Operation listTestCredentials
SDK: checkbox.testCredentials.list() (Node) · checkbox.test_credentials.list() (Python). MCP / agents: operation listTestCredentials.
Parameters
| Parameter | In | Type | Description |
|---|---|---|---|
site required | path | string | Unique identifier of the site (site_…). |
Returns
Returns a list ({ object: "list", data, has_more, url }) of TestCredential objects.
Errors use the standard envelope with a stable code and, where useful, next_action.
curl https://app.checkbox.site/v1/sites/site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b/test_credentials \
-u "$CHECKBOX_SECRET_KEY:"import Checkbox from '@checkbox-site/node';
const checkbox = new Checkbox(process.env.CHECKBOX_SECRET_KEY);
const testCredentials = await checkbox.testCredentials.list('site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b');
console.log(testCredentials.data);import os
from checkbox import Checkbox
checkbox = Checkbox(os.environ["CHECKBOX_SECRET_KEY"])
test_credentials = checkbox.test_credentials.list("site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b")
print(test_credentials["data"]){
"object": "list",
"data": [
{
"id": "tcred_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
"object": "test_credential",
"livemode": false,
"site": "site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
"type": "stripe_test",
"key_hint": "rk_test_…a1b2",
"verified": true,
"last_used": 1793318400,
"last_error": null,
"created": 1793318400
}
],
"has_more": false,
"url": "/v1/sites"
}Store a billing test-mode key
POST /v1/sites/{site}/test_credentials
Stores the site's Stripe TEST-mode key (rk_test_… preferred) used by test runs, after checking it with Stripe. Live keys are refused (test_key_not_test_mode). Least privilege: Write on Customers, Checkout Sessions, Subscriptions, Test clocks and Customer portal; Read on Prices, Products and Billing portal configuration. Replaces an existing key. Next: createTestRun.
Scope test_runs:write · Idempotent (send Idempotency-Key) · Operation createTestCredential
SDK: checkbox.testCredentials.create() (Node) · checkbox.test_credentials.create() (Python). MCP / agents: operation createTestCredential.
Parameters
| Parameter | In | Type | Description |
|---|---|---|---|
site required | path | string | Unique identifier of the site (site_…). |
Body
| Field | Type | Description |
|---|---|---|
type required | enum | Kind of key. Only "stripe_test". |
secret_key required | string | The Stripe test-mode restricted (rk_test_…) or secret (sk_test_…) key. Stored encrypted; never returned. |
Returns
Returns a TestCredential object.
Errors use the standard envelope with a stable code and, where useful, next_action.
curl https://app.checkbox.site/v1/sites/site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b/test_credentials \
-u "$CHECKBOX_SECRET_KEY:" \
-H "Content-Type: application/json" \
-d '{
"type": "stripe_test",
"secret_key": "rk_test_51Hx…"
}'import Checkbox from '@checkbox-site/node';
const checkbox = new Checkbox(process.env.CHECKBOX_SECRET_KEY);
const testCredential = await checkbox.testCredentials.create('site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b', { type: 'stripe_test', secret_key: 'rk_test_51Hx…' });
console.log(testCredential);import os
from checkbox import Checkbox
checkbox = Checkbox(os.environ["CHECKBOX_SECRET_KEY"])
test_credential = checkbox.test_credentials.create("site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b", type="stripe_test", secret_key="rk_test_51Hx…")
print(test_credential){
"id": "tcred_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
"object": "test_credential",
"livemode": false,
"site": "site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
"type": "stripe_test",
"key_hint": "rk_test_…a1b2",
"verified": true,
"last_used": 1793318400,
"last_error": null,
"created": 1793318400
}Delete a billing test-mode key
DELETE /v1/sites/{site}/test_credentials/{test_credential}
Deletes the stored key. Running test runs fail at their next Stripe call.
Scope test_runs:write · Operation deleteTestCredential
SDK: checkbox.testCredentials.del() (Node) · checkbox.test_credentials.delete() (Python). MCP / agents: operation deleteTestCredential.
Parameters
| Parameter | In | Type | Description |
|---|---|---|---|
site required | path | string | Unique identifier of the site (site_…). |
test_credential required | path | string | Unique identifier of the test credential (tcred_…). |
Returns
Returns a DeletedTestCredential object.
Errors use the standard envelope with a stable code and, where useful, next_action.
curl https://app.checkbox.site/v1/sites/site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b/test_credentials/tcred_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b \
-u "$CHECKBOX_SECRET_KEY:" \
-X DELETEimport Checkbox from '@checkbox-site/node';
const checkbox = new Checkbox(process.env.CHECKBOX_SECRET_KEY);
const testCredential = await checkbox.testCredentials.del('site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b', 'tcred_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b');
console.log(testCredential);import os
from checkbox import Checkbox
checkbox = Checkbox(os.environ["CHECKBOX_SECRET_KEY"])
test_credential = checkbox.test_credentials.delete("site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b", "tcred_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b")
print(test_credential){
"id": "tcred_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
"object": "test_credential",
"deleted": true
}List registered checkout configs
GET /v1/sites/{site}/stripe_checkout_configs
Registered Checkout Session configs of the site, newest first (test runs mirror the newest by default).
Scope test_runs:read · Operation listStripeCheckoutConfigs
SDK: checkbox.stripeCheckoutConfigs.list() (Node) · checkbox.stripe_checkout_configs.list() (Python). MCP / agents: operation listStripeCheckoutConfigs.
Parameters
| Parameter | In | Type | Description |
|---|---|---|---|
site required | path | string | Unique identifier of the site (site_…). |
limit | query | integer | Number of objects to return, 1-100 (default 10). |
starting_after | query | string | Cursor: an object id; returns the objects after it (older). |
ending_before | query | string | Cursor: an object id; returns the objects before it (newer). |
Returns
Returns a list ({ object: "list", data, has_more, url }) of StripeCheckoutConfig objects.
Errors use the standard envelope with a stable code and, where useful, next_action.
curl -G https://app.checkbox.site/v1/sites/site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b/stripe_checkout_configs \
-u "$CHECKBOX_SECRET_KEY:" \
-d limit=3import Checkbox from '@checkbox-site/node';
const checkbox = new Checkbox(process.env.CHECKBOX_SECRET_KEY);
const stripeCheckoutConfigs = await checkbox.stripeCheckoutConfigs.list('site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b', { limit: 3 });
console.log(stripeCheckoutConfigs.data);import os
from checkbox import Checkbox
checkbox = Checkbox(os.environ["CHECKBOX_SECRET_KEY"])
stripe_checkout_configs = checkbox.stripe_checkout_configs.list("site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b", limit=3)
print(stripe_checkout_configs.data){
"object": "list",
"data": [
{
"id": "scc_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
"object": "stripe_checkout_config",
"livemode": false,
"site": "site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
"name": "Pro monthly with 14-day trial",
"params": {
"mode": "subscription",
"line_items": [
{
"price": "price_1Pro",
"quantity": 1
}
],
"subscription_data": {
"trial_period_days": 14
},
"consent_collection": {
"terms_of_service": "required"
}
},
"params_hash": "9f2c…",
"ignored_params": [
"success_url"
],
"metadata": {
"order_ref": "A-1001"
},
"created": 1793318400
}
],
"has_more": false,
"url": "/v1/sites"
}Register the Checkout Session params your code uses
POST /v1/sites/{site}/stripe_checkout_configs
Registers exactly the object your code passes to stripe.checkout.sessions.create (customer, URLs and secrets are not needed and are ignored). Test runs mirror it into Stripe test mode; when it matches your latest live checkout, the scanned test page counts as an observation of your live checkout. Re-register after changing your checkout code, then call createTestRun.
Scope test_runs:write · Idempotent (send Idempotency-Key) · Operation createStripeCheckoutConfig
SDK: checkbox.stripeCheckoutConfigs.create() (Node) · checkbox.stripe_checkout_configs.create() (Python). MCP / agents: operation createStripeCheckoutConfig.
Parameters
| Parameter | In | Type | Description |
|---|---|---|---|
site required | path | string | Unique identifier of the site (site_…). |
Body
| Field | Type | Description |
|---|---|---|
params required | object | The Checkout Session parameters (mode "subscription", line_items, custom_text, consent_collection, subscription_data…). |
name | string | Your name for it. |
metadata | object | Up to 20 key/value string pairs you can attach to the object. |
Returns
Returns a StripeCheckoutConfig object.
Errors use the standard envelope with a stable code and, where useful, next_action.
curl https://app.checkbox.site/v1/sites/site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b/stripe_checkout_configs \
-u "$CHECKBOX_SECRET_KEY:" \
-H "Content-Type: application/json" \
-d '{
"params": {
"mode": "subscription",
"line_items": [
{
"price": "price_1Pro",
"quantity": 1
}
],
"subscription_data": {
"trial_period_days": 14
}
}
}'import Checkbox from '@checkbox-site/node';
const checkbox = new Checkbox(process.env.CHECKBOX_SECRET_KEY);
const stripeCheckoutConfig = await checkbox.stripeCheckoutConfigs.create('site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b', {
params: {
mode: 'subscription',
line_items: [{ price: 'price_1Pro', quantity: 1 }],
subscription_data: { trial_period_days: 14 },
},
});
console.log(stripeCheckoutConfig);import os
from checkbox import Checkbox
checkbox = Checkbox(os.environ["CHECKBOX_SECRET_KEY"])
stripe_checkout_config = checkbox.stripe_checkout_configs.create(
"site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
params={
"mode": "subscription",
"line_items": [{"price": "price_1Pro", "quantity": 1}],
"subscription_data": {"trial_period_days": 14},
},
)
print(stripe_checkout_config){
"id": "scc_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
"object": "stripe_checkout_config",
"livemode": false,
"site": "site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
"name": "Pro monthly with 14-day trial",
"params": {
"mode": "subscription",
"line_items": [
{
"price": "price_1Pro",
"quantity": 1
}
],
"subscription_data": {
"trial_period_days": 14
},
"consent_collection": {
"terms_of_service": "required"
}
},
"params_hash": "9f2c…",
"ignored_params": [
"success_url",
"customer_email"
],
"metadata": {
"order_ref": "A-1001"
},
"created": 1793318400
}Retrieve a registered checkout config
GET /v1/stripe_checkout_configs/{stripe_checkout_config}
One registered Checkout Session config.
Scope test_runs:read · Operation retrieveStripeCheckoutConfig
SDK: checkbox.stripeCheckoutConfigs.retrieve() (Node) · checkbox.stripe_checkout_configs.retrieve() (Python). MCP / agents: operation retrieveStripeCheckoutConfig.
Parameters
| Parameter | In | Type | Description |
|---|---|---|---|
stripe_checkout_config required | path | string | Unique identifier of the stripe checkout config (scc_…). |
Returns
Returns a StripeCheckoutConfig object.
Errors use the standard envelope with a stable code and, where useful, next_action.
curl https://app.checkbox.site/v1/stripe_checkout_configs/scc_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b \
-u "$CHECKBOX_SECRET_KEY:"import Checkbox from '@checkbox-site/node';
const checkbox = new Checkbox(process.env.CHECKBOX_SECRET_KEY);
const stripeCheckoutConfig = await checkbox.stripeCheckoutConfigs.retrieve('scc_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b');
console.log(stripeCheckoutConfig);import os
from checkbox import Checkbox
checkbox = Checkbox(os.environ["CHECKBOX_SECRET_KEY"])
stripe_checkout_config = checkbox.stripe_checkout_configs.retrieve("scc_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b")
print(stripe_checkout_config){
"id": "scc_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
"object": "stripe_checkout_config",
"livemode": false,
"site": "site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
"name": "Pro monthly with 14-day trial",
"params": {
"mode": "subscription",
"line_items": [
{
"price": "price_1Pro",
"quantity": 1
}
],
"subscription_data": {
"trial_period_days": 14
},
"consent_collection": {
"terms_of_service": "required"
}
},
"params_hash": "9f2c…",
"ignored_params": [
"success_url",
"customer_email"
],
"metadata": {
"order_ref": "A-1001"
},
"created": 1793318400
}Delete a registered checkout config
DELETE /v1/stripe_checkout_configs/{stripe_checkout_config}
Deletes the config; later runs mirror the next newest one (or your live checkout).
Scope test_runs:write · Operation deleteStripeCheckoutConfig
SDK: checkbox.stripeCheckoutConfigs.del() (Node) · checkbox.stripe_checkout_configs.delete() (Python). MCP / agents: operation deleteStripeCheckoutConfig.
Parameters
| Parameter | In | Type | Description |
|---|---|---|---|
stripe_checkout_config required | path | string | Unique identifier of the stripe checkout config (scc_…). |
Returns
Returns a DeletedStripeCheckoutConfig object.
Errors use the standard envelope with a stable code and, where useful, next_action.
curl https://app.checkbox.site/v1/stripe_checkout_configs/scc_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b \
-u "$CHECKBOX_SECRET_KEY:" \
-X DELETEimport Checkbox from '@checkbox-site/node';
const checkbox = new Checkbox(process.env.CHECKBOX_SECRET_KEY);
const stripeCheckoutConfig = await checkbox.stripeCheckoutConfigs.del('scc_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b');
console.log(stripeCheckoutConfig);import os
from checkbox import Checkbox
checkbox = Checkbox(os.environ["CHECKBOX_SECRET_KEY"])
stripe_checkout_config = checkbox.stripe_checkout_configs.delete("scc_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b")
print(stripe_checkout_config){
"id": "scc_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
"object": "stripe_checkout_config",
"deleted": true
}List test runs of a site
GET /v1/sites/{site}/test_runs
Test runs of the site, newest first.
Scope test_runs:read · Operation listTestRuns
SDK: checkbox.testRuns.list() (Node) · checkbox.test_runs.list() (Python). MCP / agents: operation listTestRuns.
Parameters
| Parameter | In | Type | Description |
|---|---|---|---|
site required | path | string | Unique identifier of the site (site_…). |
limit | query | integer | Number of objects to return, 1-100 (default 10). |
starting_after | query | string | Cursor: an object id; returns the objects after it (older). |
ending_before | query | string | Cursor: an object id; returns the objects before it (newer). |
Returns
Returns a list ({ object: "list", data, has_more, url }) of TestRun objects.
Errors use the standard envelope with a stable code and, where useful, next_action.
curl -G https://app.checkbox.site/v1/sites/site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b/test_runs \
-u "$CHECKBOX_SECRET_KEY:" \
-d limit=3import Checkbox from '@checkbox-site/node';
const checkbox = new Checkbox(process.env.CHECKBOX_SECRET_KEY);
const testRuns = await checkbox.testRuns.list('site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b', { limit: 3 });
console.log(testRuns.data);import os
from checkbox import Checkbox
checkbox = Checkbox(os.environ["CHECKBOX_SECRET_KEY"])
test_runs = checkbox.test_runs.list("site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b", limit=3)
print(test_runs.data){
"object": "list",
"data": [
{
"id": "run_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
"object": "test_run",
"livemode": false,
"site": "site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
"type": "stripe",
"mode": "real_checkout",
"status": "running",
"phase": "await_ack",
"test_mode": true,
"inbox_address": "k3y9+run-3f9a1c2e7b4d@in.checkbox.site",
"created": 1793318400,
"started": 1793318400,
"finished": 1793318400,
"steps": [],
"failure": {
"code": "price_not_in_test_mode",
"message": "Price price_1Live does not exist in Stripe test mode.",
"detail": {
"prices": []
},
"fix": {
"summary": "Send the acknowledgment from your checkout.session.completed webhook.",
"steps": [
"Handle checkout.session.completed…"
],
"where": "https://dashboard.stripe.com/test/apikeys",
"operation_id": "createTestRun",
"stripe_params": {
"features": {}
},
"command": "stripe prices create --unit-amount=1900 --currency=usd -d \"recurring[interval]=month\"",
"docs_url": "https://checkbox.site/docs/test-runs#acknowledgment"
}
},
"result": {
"summary": {
"passed": 9,
"failed": 2,
"needs_review": 1,
"warnings": 1
},
"checks": [],
"monitoring": {
"checkout_page_counted": true,
"cancellation_flow_counted": true,
"emails_counted": 3,
"reminder_events": 1,
"notes": []
}
},
"stripe": {
"test_clock": "clock_1Q…",
"customer": "cus_Q…",
"subscription": "sub_1Q…",
"checkout_session": "cs_test_a1…",
"mirrored_from": "registered",
"checkout_config": null,
"config_hash": "4be1…",
"matches_live": true,
"cleaned_up": true
},
"proof": {
"mode": "real_checkout",
"what_it_proves": "Your real checkout, webhook handlers and email code ran in Stripe test mode…",
"notices": "merchant",
"notices_sender": "merchant",
"payment_link": null,
"webhook_endpoints": [
{
"host": "staging.acme.example",
"enabled_events": [],
"status": "enabled"
}
],
"stripe_events": [
{
"id": "evt_1",
"type": "checkout.session.completed",
"created": 1767225600,
"pending_webhooks": 0
}
],
"cancellation": {
"via": "merchant_flow",
"declared_by_merchant": true,
"confirmed_in_stripe": true,
"subscription": "sub_1Q…",
"note": null
}
},
"next_action": {
"type": "verify_domain",
"message": "Verify your site domain to turn on live mode.",
"operation_id": "createDomainVerification",
"mcp_tool": "call_api",
"endpoint": "POST /v1/sites/{site}/domain_verification",
"url": "https://checkbox.site/docs/concepts/activation#verify"
}
}
],
"has_more": false,
"url": "/v1/sites"
}Start a lifecycle test run
POST /v1/sites/{site}/test_runs
Starts a synthetic test subscription in TEST mode and returns it queued. Stripe runs mirror your checkout into a test-mode Checkout Session, subscribe a test customer (card 4242) whose email is a Checkbox inbox, wait for your acknowledgment, advance a test clock through every legal notice window before trial end and renewal, cancel online in the customer portal and wait for the confirmation; then delete the test clock. Takes about 5-20 minutes: poll retrieveTestRun (next_action says when) or listen for test_run.completed. Each step reports observations, check results and agent-readable fixes; apply them and run again to verify.
Scope test_runs:write · Idempotent (send Idempotency-Key) · Live mode needs activation · Operation createTestRun
SDK: checkbox.testRuns.create() (Node) · checkbox.test_runs.create() (Python). MCP / agents: operation createTestRun.
Parameters
| Parameter | In | Type | Description |
|---|---|---|---|
site required | path | string | Unique identifier of the site (site_…). |
Body
| Field | Type | Description |
|---|---|---|
mode | enum | Stripe runs. mirror (default): Checkbox mirrors your checkout into test mode and moves a test clock through every legal notice window. real_checkout ("Run proof"): the shopper buys through YOUR checkout on your test deployment (stripe.checkout_url or stripe.payment_link) with card 4242 and the run inbox, so your own webhook handlers and email code fire; Checkbox watches the inbox, Stripe's events and your cancel flow. Needs your test deployment on Stripe TEST keys with a test-mode webhook endpoint. One of mirror, real_checkout. |
type | enum | stripe (default when a Stripe test key is stored or the site uses Stripe) or generic (test coupon / test account, no time travel). One of stripe, generic. |
email_wait_seconds | integer | How long to wait for each email (acknowledgment, reminders, cancellation), 15-900 seconds (default 120). |
advance_time | boolean | Advance a Stripe test clock through the trial end and the first renewal (default true). |
cancel | boolean | Cancel online at the end (default true). |
region | enum | State the synthetic shopper visits from (default: the site's first scan region). One of US-FED, US-AL, US-AK, US-AZ, US-AR, US-CA, US-CO, US-CT, US-DE, US-DC, US-FL, US-GA, US-HI, US-ID, US-IL, US-IN, US-IA, US-KS, US-KY, US-LA, US-ME, US-MD, US-MA, US-MI, US-MN, US-MS, US-MO, US-MT, US-NE, US-NV, US-NH, US-NJ, US-NM, US-NY, US-NC, US-ND, US-OH, US-OK, US-OR, US-PA, US-RI, US-SC, US-SD, US-TN, US-TX, US-UT, US-VT, US-VA, US-WA, US-WV, US-WI, US-WY. |
stripe | object | Stripe options. |
stripe.checkout_config | string | Registered checkout config (scc_…) to mirror; default: the newest one, else your latest live Checkout Session. "none" skips the registered configs (mirror your live checkout, stripe.price or stripe.payment_link instead). |
stripe.price | string | A test-mode price to subscribe to when nothing is registered. |
stripe.trial_period_days | integer | Trial for price (registered configs carry their own). |
stripe.price_map | object | Live price id -> test-mode price id, when they differ. |
stripe.checkout_steps | array of ScanSteps | Steps that complete your hosted checkout with card 4242 4242 4242 4242 when it differs from Stripe's default page. |
stripe.cancel_url | string | Your cancellation page (after login with test_account, or public). Checkbox never falls back to the Stripe portal when your flow fails. |
stripe.cancel_steps | array of ScanSteps | Clicks that cancel in your flow (after login / cancel_url), e.g. [{ "action": "click", "text": "Cancel subscription" }, { "action": "click", "text": "Confirm" }]. |
stripe.cancel_via | enum | How your customers cancel. Default: your flow when test_account / cancel_url / cancel_steps describe it, else the Stripe portal reported as a warning (cancel_flow_not_configured). One of merchant_flow, stripe_portal. |
stripe.test_account | object | A test account the shopper logs into: to buy as a logged-in user (real_checkout) and to cancel through your in-app flow. Mail to its address counts when you BCC the site's Checkbox address. |
stripe.payment_link | string | A Stripe Payment Link (plink_… or its buy.stripe.com URL): mirror mode mirrors its prices, custom_text, consent_collection and trial; real_checkout buys through it (test-mode links only). |
stripe.checkout_url | string | real_checkout: the page of your TEST deployment that leads to your Stripe test-mode checkout (a pricing page, or a route that creates the Checkout Session and redirects). |
stripe.pre_checkout_steps | array of ScanSteps | real_checkout: clicks from checkout_url to the payment page, e.g. [{ "action": "click", "text": "Start free trial" }]. |
stripe.cleanup_url | string | A page of your test deployment Checkbox opens before the checkout (after logging in) that CLEANS UP the test account (ends its subscription), so every run starts without one. Mirror mode opens it before cancelling the test account's subscription. (Round 3: renamed from reset_url, which meant the opposite of the site's test_account.reactivate_url.) |
stripe.reset_url | string | Deprecated alias of cleanup_url. |
generic | object | Generic (non-Stripe) options. |
generic.checkout_url | string | Checkout page (default: the site's scan settings). |
generic.checkout_steps | array of ScanSteps | Steps to reach the final pre-payment screen. |
generic.complete_purchase | object | Complete a real sign-up with a test coupon. |
generic.account | object | Test account used to cancel online. |
generic.cancel_steps | array of ScanSteps | Explicit cancellation steps (otherwise auto-discovered). |
Returns
Returns a TestRun object.
In live mode before activation: 403 account_not_activated with next_action.operation_id: "createDomainVerification".
Errors use the standard envelope with a stable code and, where useful, next_action.
curl https://app.checkbox.site/v1/sites/site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b/test_runs \
-u "$CHECKBOX_SECRET_KEY:" \
-H "Content-Type: application/json" \
-d '{}'import Checkbox from '@checkbox-site/node';
const checkbox = new Checkbox(process.env.CHECKBOX_SECRET_KEY);
const testRun = await checkbox.testRuns.create('site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b');
console.log(testRun);import os
from checkbox import Checkbox
checkbox = Checkbox(os.environ["CHECKBOX_SECRET_KEY"])
test_run = checkbox.test_runs.create("site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b")
print(test_run){
"id": "run_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
"object": "test_run",
"livemode": false,
"site": "site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
"type": "stripe",
"mode": "real_checkout",
"status": "running",
"phase": "await_ack",
"test_mode": true,
"inbox_address": "k3y9+run-3f9a1c2e7b4d@in.checkbox.site",
"created": 1793318400,
"started": 1793318400,
"finished": 1793318400,
"steps": [],
"failure": {
"code": "price_not_in_test_mode",
"message": "Price price_1Live does not exist in Stripe test mode.",
"detail": {
"prices": []
},
"fix": {
"summary": "Send the acknowledgment from your checkout.session.completed webhook.",
"steps": [
"Handle checkout.session.completed…"
],
"where": "https://dashboard.stripe.com/test/apikeys",
"operation_id": "createTestRun",
"stripe_params": {
"features": {
"subscription_cancel": {
"enabled": true
}
}
},
"command": "stripe prices create --unit-amount=1900 --currency=usd -d \"recurring[interval]=month\"",
"docs_url": "https://checkbox.site/docs/test-runs#acknowledgment"
}
},
"result": {
"summary": {
"passed": 9,
"failed": 2,
"needs_review": 1,
"warnings": 1
},
"checks": [],
"monitoring": {
"checkout_page_counted": true,
"cancellation_flow_counted": true,
"emails_counted": 3,
"reminder_events": 1,
"notes": []
}
},
"stripe": {
"test_clock": "clock_1Q…",
"customer": "cus_Q…",
"subscription": "sub_1Q…",
"checkout_session": "cs_test_a1…",
"mirrored_from": "registered",
"checkout_config": null,
"config_hash": "4be1…",
"matches_live": true,
"cleaned_up": true
},
"proof": {
"mode": "real_checkout",
"what_it_proves": "Your real checkout, webhook handlers and email code ran in Stripe test mode…",
"notices": "merchant",
"notices_sender": "merchant",
"payment_link": null,
"webhook_endpoints": [
{
"host": "staging.acme.example",
"enabled_events": [
"checkout.session.completed"
],
"status": "enabled"
}
],
"stripe_events": [
{
"id": "evt_1",
"type": "checkout.session.completed",
"created": 1767225600,
"pending_webhooks": 0
}
],
"cancellation": {
"via": "merchant_flow",
"declared_by_merchant": true,
"confirmed_in_stripe": true,
"subscription": "sub_1Q…",
"note": null
}
},
"next_action": {
"type": "verify_domain",
"message": "Verify your site domain to turn on live mode.",
"operation_id": "createDomainVerification",
"mcp_tool": "call_api",
"endpoint": "POST /v1/sites/{site}/domain_verification",
"url": "https://checkbox.site/docs/concepts/activation#verify"
}
}Retrieve a test run
GET /v1/test_runs/{test_run}
The run with every step's status, observations, check results and fixes. While it runs, next_action.type is "wait"; when it finished, next_action says what to fix (apply_fixes / review_warnings) or "none".
Scope test_runs:read · Operation retrieveTestRun
SDK: checkbox.testRuns.retrieve() (Node) · checkbox.test_runs.retrieve() (Python). MCP / agents: operation retrieveTestRun.
Parameters
| Parameter | In | Type | Description |
|---|---|---|---|
test_run required | path | string | Unique identifier of the test run (run_…). |
Returns
Returns a TestRun object.
Errors use the standard envelope with a stable code and, where useful, next_action.
curl https://app.checkbox.site/v1/test_runs/run_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b \
-u "$CHECKBOX_SECRET_KEY:"import Checkbox from '@checkbox-site/node';
const checkbox = new Checkbox(process.env.CHECKBOX_SECRET_KEY);
const testRun = await checkbox.testRuns.retrieve('run_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b');
console.log(testRun);import os
from checkbox import Checkbox
checkbox = Checkbox(os.environ["CHECKBOX_SECRET_KEY"])
test_run = checkbox.test_runs.retrieve("run_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b")
print(test_run){
"id": "run_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
"object": "test_run",
"livemode": false,
"site": "site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
"type": "stripe",
"mode": "real_checkout",
"status": "running",
"phase": "await_ack",
"test_mode": true,
"inbox_address": "k3y9+run-3f9a1c2e7b4d@in.checkbox.site",
"created": 1793318400,
"started": 1793318400,
"finished": 1793318400,
"steps": [],
"failure": {
"code": "price_not_in_test_mode",
"message": "Price price_1Live does not exist in Stripe test mode.",
"detail": {
"prices": []
},
"fix": {
"summary": "Send the acknowledgment from your checkout.session.completed webhook.",
"steps": [
"Handle checkout.session.completed…"
],
"where": "https://dashboard.stripe.com/test/apikeys",
"operation_id": "createTestRun",
"stripe_params": {
"features": {
"subscription_cancel": {
"enabled": true
}
}
},
"command": "stripe prices create --unit-amount=1900 --currency=usd -d \"recurring[interval]=month\"",
"docs_url": "https://checkbox.site/docs/test-runs#acknowledgment"
}
},
"result": {
"summary": {
"passed": 9,
"failed": 2,
"needs_review": 1,
"warnings": 1
},
"checks": [],
"monitoring": {
"checkout_page_counted": true,
"cancellation_flow_counted": true,
"emails_counted": 3,
"reminder_events": 1,
"notes": []
}
},
"stripe": {
"test_clock": "clock_1Q…",
"customer": "cus_Q…",
"subscription": "sub_1Q…",
"checkout_session": "cs_test_a1…",
"mirrored_from": "registered",
"checkout_config": null,
"config_hash": "4be1…",
"matches_live": true,
"cleaned_up": true
},
"proof": {
"mode": "real_checkout",
"what_it_proves": "Your real checkout, webhook handlers and email code ran in Stripe test mode…",
"notices": "merchant",
"notices_sender": "merchant",
"payment_link": null,
"webhook_endpoints": [
{
"host": "staging.acme.example",
"enabled_events": [
"checkout.session.completed"
],
"status": "enabled"
}
],
"stripe_events": [
{
"id": "evt_1",
"type": "checkout.session.completed",
"created": 1767225600,
"pending_webhooks": 0
}
],
"cancellation": {
"via": "merchant_flow",
"declared_by_merchant": true,
"confirmed_in_stripe": true,
"subscription": "sub_1Q…",
"note": null
}
},
"next_action": {
"type": "verify_domain",
"message": "Verify your site domain to turn on live mode.",
"operation_id": "createDomainVerification",
"mcp_tool": "call_api",
"endpoint": "POST /v1/sites/{site}/domain_verification",
"url": "https://checkbox.site/docs/concepts/activation#verify"
}
}Cancel a test run
POST /v1/test_runs/{test_run}/cancel
Stops a queued or running test run; the worker deletes its Stripe test clock (and with it the test customer and subscription). Finished runs cannot be canceled (resource_conflict).
Scope test_runs:write · Idempotent (send Idempotency-Key) · Operation cancelTestRun
SDK: checkbox.testRuns.cancel() (Node) · checkbox.test_runs.cancel() (Python). MCP / agents: operation cancelTestRun.
Parameters
| Parameter | In | Type | Description |
|---|---|---|---|
test_run required | path | string | Unique identifier of the test run (run_…). |
Returns
Returns a TestRun object.
Errors use the standard envelope with a stable code and, where useful, next_action.
curl https://app.checkbox.site/v1/test_runs/run_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b/cancel \
-u "$CHECKBOX_SECRET_KEY:" \
-X POSTimport Checkbox from '@checkbox-site/node';
const checkbox = new Checkbox(process.env.CHECKBOX_SECRET_KEY);
const testRun = await checkbox.testRuns.cancel('run_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b');
console.log(testRun);import os
from checkbox import Checkbox
checkbox = Checkbox(os.environ["CHECKBOX_SECRET_KEY"])
test_run = checkbox.test_runs.cancel("run_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b")
print(test_run){
"id": "run_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
"object": "test_run",
"livemode": false,
"site": "site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
"type": "stripe",
"mode": "real_checkout",
"status": "running",
"phase": "await_ack",
"test_mode": true,
"inbox_address": "k3y9+run-3f9a1c2e7b4d@in.checkbox.site",
"created": 1793318400,
"started": 1793318400,
"finished": 1793318400,
"steps": [],
"failure": {
"code": "price_not_in_test_mode",
"message": "Price price_1Live does not exist in Stripe test mode.",
"detail": {
"prices": []
},
"fix": {
"summary": "Send the acknowledgment from your checkout.session.completed webhook.",
"steps": [
"Handle checkout.session.completed…"
],
"where": "https://dashboard.stripe.com/test/apikeys",
"operation_id": "createTestRun",
"stripe_params": {
"features": {
"subscription_cancel": {
"enabled": true
}
}
},
"command": "stripe prices create --unit-amount=1900 --currency=usd -d \"recurring[interval]=month\"",
"docs_url": "https://checkbox.site/docs/test-runs#acknowledgment"
}
},
"result": {
"summary": {
"passed": 9,
"failed": 2,
"needs_review": 1,
"warnings": 1
},
"checks": [],
"monitoring": {
"checkout_page_counted": true,
"cancellation_flow_counted": true,
"emails_counted": 3,
"reminder_events": 1,
"notes": []
}
},
"stripe": {
"test_clock": "clock_1Q…",
"customer": "cus_Q…",
"subscription": "sub_1Q…",
"checkout_session": "cs_test_a1…",
"mirrored_from": "registered",
"checkout_config": null,
"config_hash": "4be1…",
"matches_live": true,
"cleaned_up": true
},
"proof": {
"mode": "real_checkout",
"what_it_proves": "Your real checkout, webhook handlers and email code ran in Stripe test mode…",
"notices": "merchant",
"notices_sender": "merchant",
"payment_link": null,
"webhook_endpoints": [
{
"host": "staging.acme.example",
"enabled_events": [
"checkout.session.completed"
],
"status": "enabled"
}
],
"stripe_events": [
{
"id": "evt_1",
"type": "checkout.session.completed",
"created": 1767225600,
"pending_webhooks": 0
}
],
"cancellation": {
"via": "merchant_flow",
"declared_by_merchant": true,
"confirmed_in_stripe": true,
"subscription": "sub_1Q…",
"note": null
}
},
"next_action": {
"type": "verify_domain",
"message": "Verify your site domain to turn on live mode.",
"operation_id": "createDomainVerification",
"mcp_tool": "call_api",
"endpoint": "POST /v1/sites/{site}/domain_verification",
"url": "https://checkbox.site/docs/concepts/activation#verify"
}
}Checkbox is compliance software, not a law firm; nothing in these docs is legal advice (details). You remain solely responsible for your subscription program, and Checkbox takes on no legal liability for it (Terms). Checkbox is a System1 company; Trust center · Status. For AI agents: every page is available as Markdown at the same URL plus .md; the index is /llms.txt.