# Agent setup API

> One-call onboarding for AI coding agents: the setup_checkbox MCP tool (or the `checkbox init` CLI) signs the human in with one browser approval (device authorization), gets test-mode keys, and drives a setup session (snippet, site, Terms and policies, first checks, Stripe test subscription) until ne

xt_action is "done".

| Operation | Endpoint |
|---|---|
| [Start a device login (setup_checkbox)](#createDeviceAuthorization) | `POST /v1/device/authorize` |
| [Poll a device login for its keys](#createDeviceToken) | `POST /v1/device/token` |
| [List setup sessions](#listSetupSessions) | `GET /v1/setup_sessions` |
| [Start a setup session (agents that already have a key)](#createSetupSession) | `POST /v1/setup_sessions` |
| [Retrieve a setup session](#retrieveSetupSession) | `GET /v1/setup_sessions/{setup_session}` |
| [Report what the agent learned or changed](#updateSetupSession) | `POST /v1/setup_sessions/{setup_session}` |
| [Re-check the site now](#verifySetupSession) | `POST /v1/setup_sessions/{setup_session}/verify` |
| [Finish the setup and notify the human](#completeSetupSession) | `POST /v1/setup_sessions/{setup_session}/complete` |

## The SetupSession object

What an AI coding agent set up for a project, as a checklist with one next_action. Loop: apply next_action, call verifySetupSession, repeat until next_action.type is "done".

| Field | Type | Description |
|---|---|---|
| `id` | string | Unique identifier of the setup session (setup_…). |
| `object` | enum | String representing the object's type. Always "setup_session". |
| `livemode` | boolean | true for live-mode objects, false for test mode (ck_test_ keys act on an isolated sandbox). |
| `status` | enum | open while the agent works; completed after completeSetupSession (checks keep running). One of `open`, `completed`, `canceled`. |
| `created` | integer | When the human approved the setup. Unix timestamp in seconds. |
| `updated` | integer | Last change. Unix timestamp in seconds. |
| `account` | string | The Checkbox account. |
| `site` | string \| null | The test-mode site (null until a site URL is known). |
| `live_site` | string \| null | The live-mode site, once created. |
| `client` | object | Who set it up. |
| `client.name` | string \| null | Client program. |
| `client.version` | string \| null | Client version. |
| `client.agent` | string \| null | AI agent, when known. |
| `project` | object | Facts about the codebase the agent reported (framework, layout_file, checkout_code…). |
| `business` | object | The business as registered. |
| `business.site_url` | string \| null | Site URL. |
| `business.checkout_url` | string \| null | Checkout / pricing page. |
| `business.account_url` | string \| null | Account page. |
| `business.terms_url` | string \| null | Terms of service. |
| `business.privacy_url` | string \| null | Privacy policy. |
| `business.refund_url` | string \| null | Refund policy. |
| `business.cancellation_url` | string \| null | Cancellation policy. |
| `business.support_email` | string \| null | Support email. |
| `business.merchant_name` | string \| null | Merchant (brand) name used in generated legal copy (the site name). |
| `business.billing_platform` | string \| null | Billing platform. |
| `business.plans` | array of SetupPlans | Plans. |
| `discovered` | object | Policy / pricing links Checkbox found in the site's HTML (terms_url, privacy_url, refund_url, cancellation_url, pricing_url, account_url). |
| `install` | object | Install details. |
| `install.script_tag` | string \| null | The exact tag to put in <head> on every page. |
| `install.snippet_key` | string \| null | Public snippet key of the site. |
| `install.publishable_key` | string \| null | Test-mode publishable key (pk_test_…) for Checkbox Elements in the browser. |
| `install.inbound_email` | string \| null | BCC this address on subscription emails (acknowledgment, reminders) so they are checked. |
| `install.installed_in` | string \| null | File the agent added the snippet to. |
| `install.detected_on_site` | boolean \| null | Whether Checkbox saw the snippet on the live site at the last verify (null: not checked). |
| `policies` | array of objects | Policy documents Checkbox fetched (checked by terms.* checks). |
| `stripe` | object | Stripe test mode for lifecycle test runs. |
| `stripe.test_key_consent` | boolean | Whether the human allowed Checkbox to use the project's Stripe TEST key for synthetic subscriptions. |
| `stripe.test_key_hint` | string \| null | Hint of the key the CLI found (never the key). |
| `stripe.test_credential_stored` | boolean | Whether a Stripe test-mode key is stored for test runs. |
| `stripe.checkout_configs` | integer | Registered Checkout Session param sets. |
| `stripe.restricted_key` | object | Restricted-key recommendation. |
| `test_run` | object \| null | Latest lifecycle test run of the site. |
| `test_run.id` | string | Unique identifier of the test run (run_…). |
| `test_run.status` | string | queued, running, succeeded, failed or canceled. |
| `test_run.created` | integer | When it started. Unix timestamp in seconds. |
| `compliance` | object \| null | Latest verdict of the test-mode site. |
| `compliance.score` | number | 0-100. |
| `compliance.insurable` | boolean | No critical/high failure open. |
| `compliance.evaluated` | integer | When it was evaluated. Unix timestamp in seconds. |
| `compliance.failing` | integer | Open failing findings. |
| `compliance.needs_review` | integer | Open needs-review findings. |
| `compliance.top_findings` | array of objects | Most urgent open findings (details: retrieveFinding; ordered tasks: `checkbox plan --json`). |
| `steps` | array of SetupSteps | The setup checklist, in order. |
| `next_action` | SetupNextAction | The single next thing the agent should do. |
| `owner_notified` | boolean | Whether the human got the summary email. |
| `owner_email` | enum \| null | The summary email: sent, or not_configured when this deployment has no SMTP (null before completeSetupSession). One of `sent`, `not_configured`. |
| `review_url` | string | Dashboard page with the setup timeline (for the human). |

## Start a device login (setup_checkbox) {#createDeviceAuthorization}

`POST /v1/device/authorize`

Public (no API key). Returns a device_code (keep it private), a user_code and verification_uri_complete. Show the human ONE line ("Open <verification_uri_complete> and click Approve"), open it in their browser when possible, then poll createDeviceToken every `interval` seconds. New users sign up on that page with an email link or GitHub / Google; nothing is created until they click Approve.

**No API key** (public) · **Operation** `createDeviceAuthorization`

SDK: `checkbox.device.authorize()` (Node) · `checkbox.device.authorize()` (Python). MCP / agents: operation `createDeviceAuthorization`.

#### Body

| Field | Type | Description |
|---|---|---|
| `client` | SetupClient | Who is setting up Checkbox. |
| `site_url` | string | Site URL detected in the project (shown on the approval screen; the test-mode site is created for it). |
| `project_name` | string | Project name. |
| `framework` | string | Detected framework. |
| `package_manager` | string | Package manager. |
| `billing_platform` | string | Detected billing platform. |
| `live` | boolean | Also ask for live-mode keys (live mode activates after domain verification). |
| `stripe_test_key_hint` | string | A HINT of the Stripe TEST key found in the project ("sk_test_…a1b2" — never the key). The human is asked once whether Checkbox may use it for synthetic test subscriptions. |

#### Returns

Returns a `DeviceAuthorization` object.

Errors use the [standard envelope](https://checkbox.site/docs/api/errors) with a stable `code` and, where useful, `next_action`.

```curl
curl https://app.checkbox.site/v1/device/authorize \
  -H "Content-Type: application/json" \
  -d '{}'
```
```node
import Checkbox from '@checkbox-site/cli';

const checkbox = new Checkbox();

const device = await checkbox.device.authorize();
console.log(device);
```
```python
import os
from checkbox import Checkbox

checkbox = Checkbox()

device = checkbox.device.authorize()
print(device)
```

```json title="Response"
{
  "object": "device_authorization",
  "device_code": "cbdev_Q2hlY2tib3g…",
  "user_code": "BKRF-QXTP",
  "verification_uri": "https://app.checkbox.site/device",
  "verification_uri_complete": "https://app.checkbox.site/device?code=BKRF-QXTP",
  "expires_in": 900,
  "interval": 5,
  "next_action": {
    "type": "install_snippet",
    "message": "Add <script async src=\"https://app.checkbox.site/s.js\" data-key=\"k3y9\"></script> to the <head> of every page, then report snippet_installed_in.",
    "operation_id": "updateSetupSession",
    "mcp_tool": "update_setup",
    "command": "checkbox init --verify --json",
    "url": "https://dashboard.stripe.com/test/apikeys/create"
  }
}
```

## Poll a device login for its keys {#createDeviceToken}

`POST /v1/device/token`

Public (no API key). Poll every `interval` seconds with the device_code. Errors (stable codes): authorization_pending (keep polling), slow_down (add 5 s), access_denied (the human clicked Deny: stop), expired_token (start again). On approval returns the keys exactly once, the setup session and the next action.

**No API key** (public) · **Operation** `createDeviceToken`

SDK: `checkbox.device.token()` (Node) · `checkbox.device.token()` (Python). MCP / agents: operation `createDeviceToken`.

#### Body

| Field | Type | Description |
|---|---|---|
| `device_code` **required** | string | The device_code from createDeviceAuthorization. |

#### Returns

Returns a `DeviceToken` object.

Errors use the [standard envelope](https://checkbox.site/docs/api/errors) with a stable `code` and, where useful, `next_action`.

```curl
curl https://app.checkbox.site/v1/device/token \
  -H "Content-Type: application/json" \
  -d '{
  "device_code": "cbdev_Q2hlY2tib3g…"
}'
```
```node
import Checkbox from '@checkbox-site/cli';

const checkbox = new Checkbox();

const device = await checkbox.device.token({ device_code: 'cbdev_Q2hlY2tib3g…' });
console.log(device);
```
```python
import os
from checkbox import Checkbox

checkbox = Checkbox()

device = checkbox.device.token(device_code="cbdev_Q2hlY2tib3g…")
print(device)
```

```json title="Response"
{
  "object": "device_token",
  "token_type": "bearer",
  "secret_key": "ck_test_51Hx…",
  "publishable_key": "pk_test_51Hx…",
  "live_secret_key": null,
  "live_publishable_key": null,
  "account": {
    "id": "acct_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
    "name": "acme.com",
    "email": "founder@acme.com"
  },
  "setup_session": "setup_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "site": "site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "consents": {
    "stripe_test_key": true,
    "live_keys": false
  },
  "next_action": {
    "type": "install_snippet",
    "message": "Add <script async src=\"https://app.checkbox.site/s.js\" data-key=\"k3y9\"></script> to the <head> of every page, then report snippet_installed_in.",
    "operation_id": "updateSetupSession",
    "mcp_tool": "update_setup",
    "command": "checkbox init --verify --json",
    "url": "https://dashboard.stripe.com/test/apikeys/create"
  }
}
```

## List setup sessions {#listSetupSessions}

`GET /v1/setup_sessions`

Setup sessions of the account, newest first. Test keys see the sessions created in test mode (device login, test keys); live keys see all.

**Scope** `setup_sessions:read` · **Operation** `listSetupSessions`

SDK: `checkbox.setupSessions.list()` (Node) · `checkbox.setup_sessions.list()` (Python). MCP / agents: operation `listSetupSessions`.

#### Parameters

| Parameter | In | Type | Description |
|---|---|---|---|
| `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 [SetupSession](https://checkbox.site/docs/api/agent-setup#the-setupsession-object) objects.

Errors use the [standard envelope](https://checkbox.site/docs/api/errors) with a stable `code` and, where useful, `next_action`.

```curl
curl -G https://app.checkbox.site/v1/setup_sessions \
  -u "$CHECKBOX_SECRET_KEY:" \
  -d limit=3
```
```node
import Checkbox from '@checkbox-site/cli';

const checkbox = new Checkbox(process.env.CHECKBOX_SECRET_KEY);

const setupSessions = await checkbox.setupSessions.list({ limit: 3 });
console.log(setupSessions.data);
```
```python
import os
from checkbox import Checkbox

checkbox = Checkbox(os.environ["CHECKBOX_SECRET_KEY"])

setup_sessions = checkbox.setup_sessions.list(limit=3)
print(setup_sessions.data)
```

```json title="Response"
{
  "object": "list",
  "data": [
    {
      "id": "setup_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
      "object": "setup_session",
      "livemode": false,
      "status": "open",
      "created": 1793318400,
      "updated": 1793318400,
      "account": "acct_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
      "site": "site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
      "live_site": "site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
      "client": {
        "name": "checkbox-cli",
        "version": "0.1.0",
        "agent": "Claude Code"
      },
      "project": {
        "framework": "nextjs-app",
        "layout_file": "app/layout.tsx"
      },
      "business": {
        "site_url": "https://acme.com",
        "checkout_url": "https://acme.com/pricing",
        "account_url": null,
        "terms_url": "https://acme.com/terms",
        "privacy_url": "https://acme.com/privacy",
        "refund_url": null,
        "cancellation_url": null,
        "support_email": "support@acme.com",
        "merchant_name": "Acme",
        "billing_platform": "stripe",
        "plans": []
      },
      "discovered": {
        "terms_url": "https://acme.com/terms"
      },
      "install": {
        "script_tag": "<script async src=\"https://app.checkbox.site/s.js\" data-key=\"k3y9\" data-api=\"https://app.checkbox.site\"></script>",
        "snippet_key": "k3y9",
        "publishable_key": "pk_test_3f9a…",
        "inbound_email": "k3y9@in.checkbox.site",
        "installed_in": "app/layout.tsx",
        "detected_on_site": false
      },
      "policies": [],
      "stripe": {
        "test_key_consent": true,
        "test_key_hint": "sk_test_…a1b2",
        "test_credential_stored": false,
        "checkout_configs": 1,
        "restricted_key": {
          "recommended": true,
          "reason": "Give Checkbox a restricted test key with only these permissions.",
          "create_url": "https://dashboard.stripe.com/test/apikeys/create",
          "permissions": [
            {
              "resource": "Test clocks",
              "access": "write"
            }
          ]
        }
      },
      "test_run": {
        "id": "run_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
        "status": "running",
        "created": 1793318400
      },
      "compliance": {
        "score": 72,
        "insurable": false,
        "evaluated": 1793318400,
        "failing": 3,
        "needs_review": 2,
        "top_findings": []
      },
      "steps": [],
      "next_action": {
        "type": "install_snippet",
        "message": "Add <script async src=\"https://app.checkbox.site/s.js\" data-key=\"k3y9\"></script> to the <head> of every page, then report snippet_installed_in.",
        "operation_id": "updateSetupSession",
        "mcp_tool": "update_setup",
        "command": "checkbox init --verify --json",
        "url": "https://dashboard.stripe.com/test/apikeys/create"
      },
      "owner_notified": false,
      "owner_email": "sent",
      "review_url": "https://app.checkbox.site/setup/3f9a1c2e-7b4d-4e0f-9a8b-7c6d5e4f3a2b"
    }
  ],
  "has_more": false,
  "url": "/v1/sites"
}
```

## Start a setup session (agents that already have a key) {#createSetupSession}

`POST /v1/setup_sessions`

For agents that already hold a secret key (no device login): starts a setup session for a project with the same fields as updateSetupSession. `checkbox init` creates the session during the device login instead.

**Scope** `setup_sessions:write` · **Idempotent** (send `Idempotency-Key`) · **Operation** `createSetupSession`

SDK: `checkbox.setupSessions.create()` (Node) · `checkbox.setup_sessions.create()` (Python). MCP / agents: operation `createSetupSession`.

#### Body

| Field | Type | Description |
|---|---|---|
| `site_url` | string | Public URL of the site (production, or a preview deployment). |
| `checkout_url` | string | Page where customers subscribe (pricing page or checkout). |
| `account_url` | string | Account page where subscribers manage / cancel. |
| `terms_url` | string | Terms of service page. Checkbox fetches and checks it. |
| `privacy_url` | string | Privacy policy page. |
| `refund_url` | string | Refund policy page. |
| `cancellation_url` | string | Cancellation policy page (if separate from the Terms). |
| `support_email` | string | Support address subscribers can write to. |
| `merchant_name` | string | The brand subscribers know (it names the seller in generated disclosures and emails). Default: the site's host name, which the plan asks you to replace. |
| `billing_platform` | enum | Billing platform. One of `stripe`, `shopify`, `recharge`, `chargebee`, `recurly`, `paddle`, `woocommerce`, `custom`. |
| `plans` | array of SetupPlans | Plans and prices (sets the free-trial and term facts the law depends on). |
| `project` | object | Facts about the builder's codebase. |
| `project.name` | string | Project name (package.json name). |
| `project.framework` | string | Detected framework: nextjs-app, nextjs-pages, remix, sveltekit, nuxt, astro, express, html, shopify-theme… |
| `project.package_manager` | string | npm, pnpm, yarn or bun. |
| `project.root` | string | Project root (display only). |
| `project.layout_file` | string | Root layout / template where the snippet belongs. |
| `project.env_file` | string | File the keys were written to. |
| `project.public_dir` | string | Static files directory (for /.well-known). |
| `project.checkout_code` | array of SetupCodeRefs | Where checkout sessions / payment links are created. |
| `project.pay_buttons` | array of SetupCodeRefs | Where the subscribe / pay buttons are rendered. |
| `snippet_installed_in` | string | File the snippet tag was added to. |
| `env_written` | string | File the API keys were written to (never committed). |
| `live_site` | string | Live-mode site (site_…) you created with the live key, so the checklist tracks its domain verification. |
| `client` | SetupClient | Who is setting up Checkbox. |
| `refetch_policies` | boolean | Fetch the policy pages again even when their URLs did not change (after editing them). |

#### Returns

Returns a [SetupSession](https://checkbox.site/docs/api/agent-setup#the-setupsession-object) object.

Errors use the [standard envelope](https://checkbox.site/docs/api/errors) with a stable `code` and, where useful, `next_action`.

```curl
curl https://app.checkbox.site/v1/setup_sessions \
  -u "$CHECKBOX_SECRET_KEY:" \
  -H "Content-Type: application/json" \
  -d '{
  "site_url": "https://acme.com"
}'
```
```node
import Checkbox from '@checkbox-site/cli';

const checkbox = new Checkbox(process.env.CHECKBOX_SECRET_KEY);

const setupSession = await checkbox.setupSessions.create({ site_url: 'https://acme.com' });
console.log(setupSession);
```
```python
import os
from checkbox import Checkbox

checkbox = Checkbox(os.environ["CHECKBOX_SECRET_KEY"])

setup_session = checkbox.setup_sessions.create(site_url="https://acme.com")
print(setup_session)
```

```json title="Response"
{
  "id": "setup_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "object": "setup_session",
  "livemode": false,
  "status": "open",
  "created": 1793318400,
  "updated": 1793318400,
  "account": "acct_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "site": "site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "live_site": "site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "client": {
    "name": "checkbox-cli",
    "version": "0.1.0",
    "agent": "Claude Code"
  },
  "project": {
    "framework": "nextjs-app",
    "layout_file": "app/layout.tsx"
  },
  "business": {
    "site_url": "https://acme.com",
    "checkout_url": "https://acme.com/pricing",
    "account_url": null,
    "terms_url": "https://acme.com/terms",
    "privacy_url": "https://acme.com/privacy",
    "refund_url": null,
    "cancellation_url": null,
    "support_email": "support@acme.com",
    "merchant_name": "Acme",
    "billing_platform": "stripe",
    "plans": []
  },
  "discovered": {
    "terms_url": "https://acme.com/terms"
  },
  "install": {
    "script_tag": "<script async src=\"https://app.checkbox.site/s.js\" data-key=\"k3y9\" data-api=\"https://app.checkbox.site\"></script>",
    "snippet_key": "k3y9",
    "publishable_key": "pk_test_3f9a…",
    "inbound_email": "k3y9@in.checkbox.site",
    "installed_in": "app/layout.tsx",
    "detected_on_site": false
  },
  "policies": [],
  "stripe": {
    "test_key_consent": true,
    "test_key_hint": "sk_test_…a1b2",
    "test_credential_stored": false,
    "checkout_configs": 1,
    "restricted_key": {
      "recommended": true,
      "reason": "Give Checkbox a restricted test key with only these permissions.",
      "create_url": "https://dashboard.stripe.com/test/apikeys/create",
      "permissions": [
        {
          "resource": "Test clocks",
          "access": "write"
        }
      ]
    }
  },
  "test_run": {
    "id": "run_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
    "status": "running",
    "created": 1793318400
  },
  "compliance": {
    "score": 72,
    "insurable": false,
    "evaluated": 1793318400,
    "failing": 3,
    "needs_review": 2,
    "top_findings": []
  },
  "steps": [],
  "next_action": {
    "type": "install_snippet",
    "message": "Add <script async src=\"https://app.checkbox.site/s.js\" data-key=\"k3y9\"></script> to the <head> of every page, then report snippet_installed_in.",
    "operation_id": "updateSetupSession",
    "mcp_tool": "update_setup",
    "command": "checkbox init --verify --json",
    "url": "https://dashboard.stripe.com/test/apikeys/create"
  },
  "owner_notified": false,
  "owner_email": "sent",
  "review_url": "https://app.checkbox.site/setup/3f9a1c2e-7b4d-4e0f-9a8b-7c6d5e4f3a2b"
}
```

## Retrieve a setup session {#retrieveSetupSession}

`GET /v1/setup_sessions/{setup_session}`

The setup checklist with one next_action. Agents: do next_action, then call verifySetupSession; stop when next_action.type is "done".

**Scope** `setup_sessions:read` · **Operation** `retrieveSetupSession`

SDK: `checkbox.setupSessions.retrieve()` (Node) · `checkbox.setup_sessions.retrieve()` (Python). MCP / agents: operation `retrieveSetupSession`.

#### Parameters

| Parameter | In | Type | Description |
|---|---|---|---|
| `setup_session` **required** | path | string | Unique identifier of the setup session (setup_…). |

#### Returns

Returns a [SetupSession](https://checkbox.site/docs/api/agent-setup#the-setupsession-object) object.

Errors use the [standard envelope](https://checkbox.site/docs/api/errors) with a stable `code` and, where useful, `next_action`.

```curl
curl https://app.checkbox.site/v1/setup_sessions/setup_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b \
  -u "$CHECKBOX_SECRET_KEY:"
```
```node
import Checkbox from '@checkbox-site/cli';

const checkbox = new Checkbox(process.env.CHECKBOX_SECRET_KEY);

const setupSession = await checkbox.setupSessions.retrieve('setup_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b');
console.log(setupSession);
```
```python
import os
from checkbox import Checkbox

checkbox = Checkbox(os.environ["CHECKBOX_SECRET_KEY"])

setup_session = checkbox.setup_sessions.retrieve("setup_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b")
print(setup_session)
```

```json title="Response"
{
  "id": "setup_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "object": "setup_session",
  "livemode": false,
  "status": "open",
  "created": 1793318400,
  "updated": 1793318400,
  "account": "acct_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "site": "site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "live_site": "site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "client": {
    "name": "checkbox-cli",
    "version": "0.1.0",
    "agent": "Claude Code"
  },
  "project": {
    "framework": "nextjs-app",
    "layout_file": "app/layout.tsx"
  },
  "business": {
    "site_url": "https://acme.com",
    "checkout_url": "https://acme.com/pricing",
    "account_url": null,
    "terms_url": "https://acme.com/terms",
    "privacy_url": "https://acme.com/privacy",
    "refund_url": null,
    "cancellation_url": null,
    "support_email": "support@acme.com",
    "merchant_name": "Acme",
    "billing_platform": "stripe",
    "plans": []
  },
  "discovered": {
    "terms_url": "https://acme.com/terms"
  },
  "install": {
    "script_tag": "<script async src=\"https://app.checkbox.site/s.js\" data-key=\"k3y9\" data-api=\"https://app.checkbox.site\"></script>",
    "snippet_key": "k3y9",
    "publishable_key": "pk_test_3f9a…",
    "inbound_email": "k3y9@in.checkbox.site",
    "installed_in": "app/layout.tsx",
    "detected_on_site": false
  },
  "policies": [],
  "stripe": {
    "test_key_consent": true,
    "test_key_hint": "sk_test_…a1b2",
    "test_credential_stored": false,
    "checkout_configs": 1,
    "restricted_key": {
      "recommended": true,
      "reason": "Give Checkbox a restricted test key with only these permissions.",
      "create_url": "https://dashboard.stripe.com/test/apikeys/create",
      "permissions": [
        {
          "resource": "Test clocks",
          "access": "write"
        }
      ]
    }
  },
  "test_run": {
    "id": "run_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
    "status": "running",
    "created": 1793318400
  },
  "compliance": {
    "score": 72,
    "insurable": false,
    "evaluated": 1793318400,
    "failing": 3,
    "needs_review": 2,
    "top_findings": []
  },
  "steps": [],
  "next_action": {
    "type": "install_snippet",
    "message": "Add <script async src=\"https://app.checkbox.site/s.js\" data-key=\"k3y9\"></script> to the <head> of every page, then report snippet_installed_in.",
    "operation_id": "updateSetupSession",
    "mcp_tool": "update_setup",
    "command": "checkbox init --verify --json",
    "url": "https://dashboard.stripe.com/test/apikeys/create"
  },
  "owner_notified": false,
  "owner_email": "sent",
  "review_url": "https://app.checkbox.site/setup/3f9a1c2e-7b4d-4e0f-9a8b-7c6d5e4f3a2b"
}
```

## Report what the agent learned or changed {#updateSetupSession}

`POST /v1/setup_sessions/{setup_session}`

Reports project facts and business URLs: site_url (creates the test-mode site), checkout_url, terms_url / refund_url / cancellation_url / privacy_url (fetched now, stored as evidence and checked against the law), plans, where checkout code lives, snippet_installed_in, env_written. Returns the updated checklist.

**Scope** `setup_sessions:write` · **Idempotent** (send `Idempotency-Key`) · **Operation** `updateSetupSession`

SDK: `checkbox.setupSessions.update()` (Node) · `checkbox.setup_sessions.update()` (Python). MCP / agents: operation `updateSetupSession`.

#### Parameters

| Parameter | In | Type | Description |
|---|---|---|---|
| `setup_session` **required** | path | string | Unique identifier of the setup session (setup_…). |

#### Body

| Field | Type | Description |
|---|---|---|
| `site_url` | string | Public URL of the site (production, or a preview deployment). |
| `checkout_url` | string | Page where customers subscribe (pricing page or checkout). |
| `account_url` | string | Account page where subscribers manage / cancel. |
| `terms_url` | string | Terms of service page. Checkbox fetches and checks it. |
| `privacy_url` | string | Privacy policy page. |
| `refund_url` | string | Refund policy page. |
| `cancellation_url` | string | Cancellation policy page (if separate from the Terms). |
| `support_email` | string | Support address subscribers can write to. |
| `merchant_name` | string | The brand subscribers know (it names the seller in generated disclosures and emails). Default: the site's host name, which the plan asks you to replace. |
| `billing_platform` | enum | Billing platform. One of `stripe`, `shopify`, `recharge`, `chargebee`, `recurly`, `paddle`, `woocommerce`, `custom`. |
| `plans` | array of SetupPlans | Plans and prices (sets the free-trial and term facts the law depends on). |
| `project` | object | Facts about the builder's codebase. |
| `project.name` | string | Project name (package.json name). |
| `project.framework` | string | Detected framework: nextjs-app, nextjs-pages, remix, sveltekit, nuxt, astro, express, html, shopify-theme… |
| `project.package_manager` | string | npm, pnpm, yarn or bun. |
| `project.root` | string | Project root (display only). |
| `project.layout_file` | string | Root layout / template where the snippet belongs. |
| `project.env_file` | string | File the keys were written to. |
| `project.public_dir` | string | Static files directory (for /.well-known). |
| `project.checkout_code` | array of SetupCodeRefs | Where checkout sessions / payment links are created. |
| `project.pay_buttons` | array of SetupCodeRefs | Where the subscribe / pay buttons are rendered. |
| `snippet_installed_in` | string | File the snippet tag was added to. |
| `env_written` | string | File the API keys were written to (never committed). |
| `live_site` | string | Live-mode site (site_…) you created with the live key, so the checklist tracks its domain verification. |
| `client` | SetupClient | Who is setting up Checkbox. |
| `refetch_policies` | boolean | Fetch the policy pages again even when their URLs did not change (after editing them). |

#### Returns

Returns a [SetupSession](https://checkbox.site/docs/api/agent-setup#the-setupsession-object) object.

Errors use the [standard envelope](https://checkbox.site/docs/api/errors) with a stable `code` and, where useful, `next_action`.

```curl
curl https://app.checkbox.site/v1/setup_sessions/setup_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b \
  -u "$CHECKBOX_SECRET_KEY:" \
  -H "Content-Type: application/json" \
  -d '{
  "site_url": "https://acme.com"
}'
```
```node
import Checkbox from '@checkbox-site/cli';

const checkbox = new Checkbox(process.env.CHECKBOX_SECRET_KEY);

const setupSession = await checkbox.setupSessions.update('setup_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b', { site_url: 'https://acme.com' });
console.log(setupSession);
```
```python
import os
from checkbox import Checkbox

checkbox = Checkbox(os.environ["CHECKBOX_SECRET_KEY"])

setup_session = checkbox.setup_sessions.update("setup_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b", site_url="https://acme.com")
print(setup_session)
```

```json title="Response"
{
  "id": "setup_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "object": "setup_session",
  "livemode": false,
  "status": "open",
  "created": 1793318400,
  "updated": 1793318400,
  "account": "acct_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "site": "site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "live_site": "site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "client": {
    "name": "checkbox-cli",
    "version": "0.1.0",
    "agent": "Claude Code"
  },
  "project": {
    "framework": "nextjs-app",
    "layout_file": "app/layout.tsx"
  },
  "business": {
    "site_url": "https://acme.com",
    "checkout_url": "https://acme.com/pricing",
    "account_url": null,
    "terms_url": "https://acme.com/terms",
    "privacy_url": "https://acme.com/privacy",
    "refund_url": null,
    "cancellation_url": null,
    "support_email": "support@acme.com",
    "merchant_name": "Acme",
    "billing_platform": "stripe",
    "plans": []
  },
  "discovered": {
    "terms_url": "https://acme.com/terms"
  },
  "install": {
    "script_tag": "<script async src=\"https://app.checkbox.site/s.js\" data-key=\"k3y9\" data-api=\"https://app.checkbox.site\"></script>",
    "snippet_key": "k3y9",
    "publishable_key": "pk_test_3f9a…",
    "inbound_email": "k3y9@in.checkbox.site",
    "installed_in": "app/layout.tsx",
    "detected_on_site": false
  },
  "policies": [],
  "stripe": {
    "test_key_consent": true,
    "test_key_hint": "sk_test_…a1b2",
    "test_credential_stored": false,
    "checkout_configs": 1,
    "restricted_key": {
      "recommended": true,
      "reason": "Give Checkbox a restricted test key with only these permissions.",
      "create_url": "https://dashboard.stripe.com/test/apikeys/create",
      "permissions": [
        {
          "resource": "Test clocks",
          "access": "write"
        }
      ]
    }
  },
  "test_run": {
    "id": "run_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
    "status": "running",
    "created": 1793318400
  },
  "compliance": {
    "score": 72,
    "insurable": false,
    "evaluated": 1793318400,
    "failing": 3,
    "needs_review": 2,
    "top_findings": []
  },
  "steps": [],
  "next_action": {
    "type": "install_snippet",
    "message": "Add <script async src=\"https://app.checkbox.site/s.js\" data-key=\"k3y9\"></script> to the <head> of every page, then report snippet_installed_in.",
    "operation_id": "updateSetupSession",
    "mcp_tool": "update_setup",
    "command": "checkbox init --verify --json",
    "url": "https://dashboard.stripe.com/test/apikeys/create"
  },
  "owner_notified": false,
  "owner_email": "sent",
  "review_url": "https://app.checkbox.site/setup/3f9a1c2e-7b4d-4e0f-9a8b-7c6d5e4f3a2b"
}
```

## Re-check the site now {#verifySetupSession}

`POST /v1/setup_sessions/{setup_session}/verify`

Loads the site (is the snippet live? which policy links does it have?), re-fetches the Terms and policies, re-evaluates compliance and queues the first synthetic-shopper scan. Call it after every change the agent made (and after deploying). Returns what was seen plus the updated session.

**Scope** `setup_sessions:write` · **Idempotent** (send `Idempotency-Key`) · **Operation** `verifySetupSession`

SDK: `checkbox.setupSessions.verify()` (Node) · `checkbox.setup_sessions.verify()` (Python). MCP / agents: operation `verifySetupSession`.

#### Parameters

| Parameter | In | Type | Description |
|---|---|---|---|
| `setup_session` **required** | path | string | Unique identifier of the setup session (setup_…). |

#### Returns

Returns a `SetupVerification` object.

Errors use the [standard envelope](https://checkbox.site/docs/api/errors) with a stable `code` and, where useful, `next_action`.

```curl
curl https://app.checkbox.site/v1/setup_sessions/setup_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b/verify \
  -u "$CHECKBOX_SECRET_KEY:" \
  -X POST
```
```node
import Checkbox from '@checkbox-site/cli';

const checkbox = new Checkbox(process.env.CHECKBOX_SECRET_KEY);

const setupSession = await checkbox.setupSessions.verify('setup_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b');
console.log(setupSession);
```
```python
import os
from checkbox import Checkbox

checkbox = Checkbox(os.environ["CHECKBOX_SECRET_KEY"])

setup_session = checkbox.setup_sessions.verify("setup_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b")
print(setup_session)
```

```json title="Response"
{
  "object": "setup_verification",
  "homepage": {
    "ok": true,
    "snippet_detected": true,
    "error": null
  },
  "policies": [],
  "scan": {
    "queued": true,
    "scan": "scan_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
    "reason": null
  },
  "evaluated": true,
  "setup_session": {
    "id": "setup_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
    "object": "setup_session",
    "livemode": false,
    "status": "open",
    "created": 1793318400,
    "updated": 1793318400,
    "account": "acct_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
    "site": "site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
    "live_site": "site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
    "client": {
      "name": "checkbox-cli",
      "version": "0.1.0",
      "agent": "Claude Code"
    },
    "project": {
      "framework": "nextjs-app",
      "layout_file": "app/layout.tsx"
    },
    "business": {
      "site_url": "https://acme.com",
      "checkout_url": "https://acme.com/pricing",
      "account_url": null,
      "terms_url": "https://acme.com/terms",
      "privacy_url": "https://acme.com/privacy",
      "refund_url": null,
      "cancellation_url": null,
      "support_email": "support@acme.com",
      "merchant_name": "Acme",
      "billing_platform": "stripe",
      "plans": []
    },
    "discovered": {
      "terms_url": "https://acme.com/terms"
    },
    "install": {
      "script_tag": "<script async src=\"https://app.checkbox.site/s.js\" data-key=\"k3y9\" data-api=\"https://app.checkbox.site\"></script>",
      "snippet_key": "k3y9",
      "publishable_key": "pk_test_3f9a…",
      "inbound_email": "k3y9@in.checkbox.site",
      "installed_in": "app/layout.tsx",
      "detected_on_site": false
    },
    "policies": [],
    "stripe": {
      "test_key_consent": true,
      "test_key_hint": "sk_test_…a1b2",
      "test_credential_stored": false,
      "checkout_configs": 1,
      "restricted_key": {
        "recommended": true,
        "reason": "Give Checkbox a restricted test key with only these permissions.",
        "create_url": "https://dashboard.stripe.com/test/apikeys/create",
        "permissions": [
          {
            "resource": "Test clocks",
            "access": "write"
          }
        ]
      }
    },
    "test_run": {
      "id": "run_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
      "status": "running",
      "created": 1793318400
    },
    "compliance": {
      "score": 72,
      "insurable": false,
      "evaluated": 1793318400,
      "failing": 3,
      "needs_review": 2,
      "top_findings": []
    },
    "steps": [],
    "next_action": {
      "type": "install_snippet",
      "message": "Add <script async src=\"https://app.checkbox.site/s.js\" data-key=\"k3y9\"></script> to the <head> of every page, then report snippet_installed_in.",
      "operation_id": "updateSetupSession",
      "mcp_tool": "update_setup",
      "command": "checkbox init --verify --json",
      "url": "https://dashboard.stripe.com/test/apikeys/create"
    },
    "owner_notified": false,
    "owner_email": "sent",
    "review_url": "https://app.checkbox.site/setup/3f9a1c2e-7b4d-4e0f-9a8b-7c6d5e4f3a2b"
  }
}
```

## Finish the setup and notify the human {#completeSetupSession}

`POST /v1/setup_sessions/{setup_session}/complete`

Marks the setup finished and emails the person who approved it a summary ("<agent> set up Checkbox for <domain>") with what was created, what is still open and a review link. Idempotent: the email is sent once. Checks keep running afterwards.

**Scope** `setup_sessions:write` · **Idempotent** (send `Idempotency-Key`) · **Operation** `completeSetupSession`

SDK: `checkbox.setupSessions.complete()` (Node) · `checkbox.setup_sessions.complete()` (Python). MCP / agents: operation `completeSetupSession`.

#### Parameters

| Parameter | In | Type | Description |
|---|---|---|---|
| `setup_session` **required** | path | string | Unique identifier of the setup session (setup_…). |

#### Returns

Returns a [SetupSession](https://checkbox.site/docs/api/agent-setup#the-setupsession-object) object.

Errors use the [standard envelope](https://checkbox.site/docs/api/errors) with a stable `code` and, where useful, `next_action`.

```curl
curl https://app.checkbox.site/v1/setup_sessions/setup_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b/complete \
  -u "$CHECKBOX_SECRET_KEY:" \
  -X POST
```
```node
import Checkbox from '@checkbox-site/cli';

const checkbox = new Checkbox(process.env.CHECKBOX_SECRET_KEY);

const setupSession = await checkbox.setupSessions.complete('setup_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b');
console.log(setupSession);
```
```python
import os
from checkbox import Checkbox

checkbox = Checkbox(os.environ["CHECKBOX_SECRET_KEY"])

setup_session = checkbox.setup_sessions.complete("setup_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b")
print(setup_session)
```

```json title="Response"
{
  "id": "setup_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "object": "setup_session",
  "livemode": false,
  "status": "open",
  "created": 1793318400,
  "updated": 1793318400,
  "account": "acct_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "site": "site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "live_site": "site_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
  "client": {
    "name": "checkbox-cli",
    "version": "0.1.0",
    "agent": "Claude Code"
  },
  "project": {
    "framework": "nextjs-app",
    "layout_file": "app/layout.tsx"
  },
  "business": {
    "site_url": "https://acme.com",
    "checkout_url": "https://acme.com/pricing",
    "account_url": null,
    "terms_url": "https://acme.com/terms",
    "privacy_url": "https://acme.com/privacy",
    "refund_url": null,
    "cancellation_url": null,
    "support_email": "support@acme.com",
    "merchant_name": "Acme",
    "billing_platform": "stripe",
    "plans": []
  },
  "discovered": {
    "terms_url": "https://acme.com/terms"
  },
  "install": {
    "script_tag": "<script async src=\"https://app.checkbox.site/s.js\" data-key=\"k3y9\" data-api=\"https://app.checkbox.site\"></script>",
    "snippet_key": "k3y9",
    "publishable_key": "pk_test_3f9a…",
    "inbound_email": "k3y9@in.checkbox.site",
    "installed_in": "app/layout.tsx",
    "detected_on_site": false
  },
  "policies": [],
  "stripe": {
    "test_key_consent": true,
    "test_key_hint": "sk_test_…a1b2",
    "test_credential_stored": false,
    "checkout_configs": 1,
    "restricted_key": {
      "recommended": true,
      "reason": "Give Checkbox a restricted test key with only these permissions.",
      "create_url": "https://dashboard.stripe.com/test/apikeys/create",
      "permissions": [
        {
          "resource": "Test clocks",
          "access": "write"
        }
      ]
    }
  },
  "test_run": {
    "id": "run_3f9a1c2e7b4d4e0f9a8b7c6d5e4f3a2b",
    "status": "running",
    "created": 1793318400
  },
  "compliance": {
    "score": 72,
    "insurable": false,
    "evaluated": 1793318400,
    "failing": 3,
    "needs_review": 2,
    "top_findings": []
  },
  "steps": [],
  "next_action": {
    "type": "install_snippet",
    "message": "Add <script async src=\"https://app.checkbox.site/s.js\" data-key=\"k3y9\"></script> to the <head> of every page, then report snippet_installed_in.",
    "operation_id": "updateSetupSession",
    "mcp_tool": "update_setup",
    "command": "checkbox init --verify --json",
    "url": "https://dashboard.stripe.com/test/apikeys/create"
  },
  "owner_notified": false,
  "owner_email": "sent",
  "review_url": "https://app.checkbox.site/setup/3f9a1c2e-7b4d-4e0f-9a8b-7c6d5e4f3a2b"
}
```
