# Quickstart

> Five minutes, a test key and no credit card — preflight a Stripe Checkout Session, drop in a compliant disclosure, register your site and receive webhooks.

This is the manual path. If you use an AI coding agent, you can skip it: tell the agent *"Add Checkbox to this
project"* and it connects through the MCP server's `setup_checkbox` tool for you ([how that works](https://checkbox.site/docs/agent-loop)).

## 1. Get a test key {#get-a-test-key}

[Sign up](https://app.checkbox.site/sign-up?intent=api_keys) (email, GitHub or Google; free) and copy the **test secret
key** from **Settings → API keys**. Test keys start with `ck_test_`, act on an isolated sandbox and never need
activation. Put the key in your environment:

```bash
export CHECKBOX_SECRET_KEY=ck_test_...
```

Check the key. The response tells you the mode and the next step:

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

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

const account = await checkbox.account.retrieve();
console.log(account.livemode, account.next_action);
```
```python
import os
from checkbox import Checkbox

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

account = checkbox.account.retrieve()
print(account["livemode"], account["next_action"])
```

> **Pre-release packages**
>
> The SDKs, the CLI and the local MCP server are not on npm or PyPI yet, and the package names shown here are
> placeholders (the CLI commands below run from a checkout of the repository today). Until this notice is gone, use the
> HTTP API (curl) or the remote MCP server at `https://app.checkbox.site/mcp`, which are live today. Never install an npm
> package named `checkbox`: it belongs to an unrelated project.

## 2. Preflight your Stripe Checkout Session {#preflight}

Before you deploy, send Checkbox exactly the object your code passes to `stripe.checkout.sessions.create`, plus what
Stripe's params do not say (your brand and where subscribers cancel). No site, no stored data:

```curl
curl https://app.checkbox.site/v1/checks/stripe_checkout_session \
  -u "$CHECKBOX_SECRET_KEY:" \
  -H "Content-Type: application/json" \
  -d '{
    "params": {
      "mode": "subscription",
      "line_items": [{
        "price_data": {
          "currency": "usd",
          "unit_amount": 1999,
          "recurring": { "interval": "month" },
          "product_data": { "name": "Joybox Pro" }
        },
        "quantity": 1
      }],
      "subscription_data": { "trial_period_days": 14 },
      "success_url": "https://joybox.example/welcome"
    },
    "merchant": {
      "merchant_name": "Joybox",
      "cancel_url": "https://joybox.example/account/cancel"
    }
  }'
```
```node
import Checkbox from '@checkbox-site/cli';

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

const params = {
  mode: 'subscription',
  line_items: [{
    price_data: {
      currency: 'usd',
      unit_amount: 1999,
      recurring: { interval: 'month' },
      product_data: { name: 'Joybox Pro' },
    },
    quantity: 1,
  }],
  subscription_data: { trial_period_days: 14 },
  success_url: 'https://joybox.example/welcome',
};

const result = await checkbox.checks.stripeCheckoutSession({
  params,
  merchant: { merchant_name: 'Joybox', cancel_url: 'https://joybox.example/account/cancel' },
});
console.log(result.verdict, result.next_action.message);
// Use result.correction.corrected_params for stripe.checkout.sessions.create.
console.log(result.correction.corrected_params.consent_collection);
```
```python
import os
from checkbox import Checkbox

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

params = {
    "mode": "subscription",
    "line_items": [{
        "price_data": {
            "currency": "usd",
            "unit_amount": 1999,
            "recurring": {"interval": "month"},
            "product_data": {"name": "Joybox Pro"},
        },
        "quantity": 1,
    }],
    "subscription_data": {"trial_period_days": 14},
    "success_url": "https://joybox.example/welcome",
}

result = checkbox.checks.stripe_checkout_session(
    params=params,
    merchant={"merchant_name": "Joybox", "cancel_url": "https://joybox.example/account/cancel"},
)
print(result["verdict"], result["next_action"]["message"])
print(result["correction"]["corrected_params"]["consent_collection"])
```

The response has a verdict per check and per legal requirement, with citations, and a correction:

```json title="Response (trimmed)"
{
  "object": "check_result",
  "kind": "stripe_checkout_session",
  "verdict": "fail",
  "summary": { "pass": 6, "fail": 2, "needs_review": 2, "not_applicable": 0 },
  "checks": [
    {
      "check_id": "signup.consent.affirmative",
      "status": "fail",
      "severity": "critical",
      "requirements": [
        { "id": "US-FED.8403.2", "citation": "15 U.S.C. § 8403(2)" },
        { "id": "US-CA.17602.a.2", "citation": "Cal. Bus. & Prof. Code § 17602(a)(2)" }
      ]
    }
  ],
  "correction": {
    "patch": [
      { "op": "add", "path": "/consent_collection", "value": { "terms_of_service": "required" } },
      { "op": "add", "path": "/custom_text", "value": { "submit": { "message": "Your free trial lasts 14 days, then $19.99 every month…" } } }
    ],
    "corrected_params": { "mode": "subscription", "consent_collection": { "terms_of_service": "required" } }
  },
  "next_action": { "type": "apply_patch", "message": "…Apply correction.patch… then call this check again with the new params." }
}
```

Apply `correction.patch` (RFC 6902 JSON Patch) or use `correction.corrected_params`, and check again until the verdict
is `pass`. One check stays `needs_review` on any Stripe-hosted page: whether the terms are *clear and conspicuous*
depends on styling Stripe controls. [The Stripe Checkout guide](https://checkbox.site/docs/guides/stripe-checkout) explains how to close it.

Other preflight checks work the same way: [disclosure text](https://checkbox.site/docs/api/checks#checkDisclosure),
[Payment Links](https://checkbox.site/docs/api/checks#checkStripePaymentLink), [lifecycle emails](https://checkbox.site/docs/api/checks#checkEmail),
[checkout HTML](https://checkbox.site/docs/api/checks#checkPage) and the [notice schedule](https://checkbox.site/docs/api/checks#checkNoticeSchedule).

## 3. Drop in a compliant disclosure {#elements}

If you build your own checkout page, [Checkbox Elements](https://checkbox.site/docs/elements) renders the locked, compliant disclosure for
your terms in a bordered box directly above your pay button, with an unchecked, required consent checkbox, and records
each consent as evidence. Add the script and the element (use your **publishable** key, `pk_test_…`):

```html
<script src="https://app.checkbox.site/v1/elements.js" defer></script>

<form action="/subscribe" method="post">
  <checkbox-disclosure
    publishable-key="pk_test_..."
    merchant-name="Joybox" amount="1999" currency="usd" interval="month" trial-days="14"
    cancel-url="https://joybox.example/account/cancel">
  </checkbox-disclosure>
  <button type="submit">Start free trial</button>
</form>
```

The pay button stays disabled until the box is ticked. Your server receives `checkbox_consent_id` (`cons_…`) with the
form; store it with the subscription.

## 4. Register your site {#register-your-site}

A site turns one-off checks into monitoring: the synthetic shopper visits your checkout from each state, the snippet
sees what real visitors see, and every result lands in your evidence vault. Only `url` is required:

```curl
curl https://app.checkbox.site/v1/sites \
  -u "$CHECKBOX_SECRET_KEY:" \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://joybox.example", "platform": "stripe" }'
```
```node
import Checkbox from '@checkbox-site/cli';

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

const site = await checkbox.sites.create({ url: 'https://joybox.example', platform: 'stripe' });
console.log(site.id, site.install.script_tag);
```
```python
import os
from checkbox import Checkbox

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

site = checkbox.sites.create(url="https://joybox.example", platform="stripe")
print(site["id"], site["install"]["script_tag"])
```

The response includes `install`: the snippet tag for your pages, an inbound email address to BCC your subscriber
emails to, and webhook URLs for your billing platform. Then ask for the [compliance plan](https://checkbox.site/docs/guides/compliance-plan):
`GET /v1/sites/{site}/plan` returns the ordered list of changes, each with the requirement, the place and the exact fix.

In test mode nothing is monitored on a schedule. To monitor your real site, use a live key and
[verify your domain](https://checkbox.site/docs/concepts/activation) — that is the only activation step.

## 5. Receive webhooks {#webhooks}

Subscribe an HTTPS endpoint to the events you care about. The secret is returned once; keep it with your server's
configuration:

```curl
curl https://app.checkbox.site/v1/webhook_endpoints \
  -u "$CHECKBOX_SECRET_KEY:" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://joybox.example/hooks/checkbox",
    "enabled_events": ["finding.created", "site.compliant", "plan.updated"]
  }'
```
```node
import Checkbox from '@checkbox-site/cli';

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

const endpoint = await checkbox.webhookEndpoints.create({
  url: 'https://joybox.example/hooks/checkbox',
  enabled_events: ['finding.created', 'site.compliant', 'plan.updated'],
});
console.log(endpoint.id, endpoint.secret);
```
```python
import os
from checkbox import Checkbox

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

endpoint = checkbox.webhook_endpoints.create(
    url="https://joybox.example/hooks/checkbox",
    enabled_events=["finding.created", "site.compliant", "plan.updated"],
)
print(endpoint["id"], endpoint["secret"])
```

Verify every delivery's `Checkbox-Signature` header before trusting it: see [Webhooks](https://checkbox.site/docs/webhooks#verify-signatures).

## Next steps {#next}

- [Build with AI](https://checkbox.site/docs/build-with-ai): prompts and repository instructions for Claude Code and Cursor.
- [Requirements and jurisdictions](https://checkbox.site/docs/concepts/requirements): what the law asks for, state by state.
- [Test subscriptions](https://checkbox.site/docs/guides/test-runs): see every lifecycle email and the cancellation flow before customers do.
