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/cli';
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/cli';
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/cli';
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/cli';
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/cli';
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/cli';
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/cli';
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/cli';
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",
"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": {
"score": 82,
"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
},
"next_action": {
"type": "verify_domain",
"message": "Verify your site domain to turn on live mode.",
"operation_id": "createDomainVerification",
"mcp_tool": "call_api",
"url": "https://checkbox.site/docs/api/activation"
}
}
],
"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 |
|---|---|---|
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. |
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 | Cancel on your own page instead of the Stripe customer portal (it must work for the test subscriber). |
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/cli';
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",
"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": {
"score": 82,
"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
},
"next_action": {
"type": "verify_domain",
"message": "Verify your site domain to turn on live mode.",
"operation_id": "createDomainVerification",
"mcp_tool": "call_api",
"url": "https://checkbox.site/docs/api/activation"
}
}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/cli';
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",
"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": {
"score": 82,
"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
},
"next_action": {
"type": "verify_domain",
"message": "Verify your site domain to turn on live mode.",
"operation_id": "createDomainVerification",
"mcp_tool": "call_api",
"url": "https://checkbox.site/docs/api/activation"
}
}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/cli';
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",
"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": {
"score": 82,
"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
},
"next_action": {
"type": "verify_domain",
"message": "Verify your site domain to turn on live mode.",
"operation_id": "createDomainVerification",
"mcp_tool": "call_api",
"url": "https://checkbox.site/docs/api/activation"
}
}Checkbox is compliance software, not a law firm; nothing in these docs is legal advice (details). For AI agents: every page is available as Markdown at the same URL plus .md; the index is /llms.txt.