# Node.js SDK

> The official TypeScript/JavaScript client — zero dependencies, typed responses, automatic retries and idempotency, auto-pagination and webhook verification. Node 20+, Bun, Deno and edge runtimes.

## Install {#install}

```bash
npm install @checkbox-site/cli
```

> **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.

```node
import Checkbox from '@checkbox-site/cli';

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

const account = await checkbox.account.retrieve();
console.log(checkbox.mode, account.activation.status);
```

`new Checkbox()` without an argument reads `CHECKBOX_API_KEY`. Options: `apiVersion`, `baseUrl` (or
`CHECKBOX_API_BASE`), `maxNetworkRetries` (default 2), `timeout` (ms, default 80 000), `fetch`, `appInfo`, `headers`.

## Methods {#methods}

Every API operation is a method: `checkbox.<resource>.<action>()`. The [API reference](https://checkbox.site/docs/api) shows the method
for each operation (`createSite` → `checkbox.sites.create()`, `checkStripeCheckoutSession` →
`checkbox.checks.stripeCheckoutSession()`). Path parameters come first, then one params object (query and body
together), then request options. Responses are typed objects generated from the OpenAPI document.

Agents and tools that work with operation ids can call any operation by name with flat arguments:

```node
import Checkbox from '@checkbox-site/cli';

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

const site = await checkbox.call('createSite', { url: 'https://joybox.example' });
const plan = await checkbox.call('retrieveCompliancePlan', { site: site.id });
console.log(plan.status, plan.next_action.type);
```

## Pagination {#pagination}

`list()` returns one page when awaited, and walks every page with `for await`:

```node
import Checkbox from '@checkbox-site/cli';

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

const page = await checkbox.sites.list({ limit: 10 });
console.log(page.data.length, page.has_more);

for await (const finding of checkbox.findings.list({ status: 'fail', limit: 100 })) {
  console.log(finding.check_id, finding.severity);
}
```

## Errors {#errors}

Errors are typed (`CheckboxInvalidRequestError`, `CheckboxAuthenticationError`, `CheckboxPermissionError`,
`CheckboxRateLimitError`, `CheckboxIdempotencyError`, `CheckboxAPIError`, `CheckboxConnectionError`) and carry the
API's stable `code`, `param`, `statusCode`, `requestId`, `docUrl` and `nextAction`:

```node
import Checkbox, { CheckboxInvalidRequestError } from '@checkbox-site/cli';

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

try {
  await checkbox.sites.retrieve('site_00000000000000000000000000000000');
} catch (err) {
  if (err instanceof CheckboxInvalidRequestError && err.code === 'resource_missing') {
    console.log('No such site:', err.docUrl);
  } else {
    throw err;
  }
}
```

## Retries and idempotency {#retries}

Network errors, `429` and `5xx` responses are retried with exponential backoff. Every POST is sent with an
`Idempotency-Key` (generated and reused across retries), so a retried create never creates twice. Pass your own to
make a create idempotent across processes:

```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' },
  { idempotencyKey: 'site-joybox-example' },
);
console.log(site.id);
```

## Webhooks {#webhooks}

Verify `Checkbox-Signature` with the **raw** request body and the endpoint's secret. `constructEvent` throws
`CheckboxSignatureVerificationError` when the signature is wrong or older than 5 minutes. (`constructEventAsync` uses
WebCrypto for edge runtimes.)

```node
import Checkbox from '@checkbox-site/cli';

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

// In a test: build a signed delivery the way Checkbox does.
const payload = JSON.stringify({ id: 'evt_123', object: 'event', type: 'site.compliant', data: { object: { id: 'site_123' } } });
const header = checkbox.webhooks.generateTestHeaderString({ payload, secret });

const event = checkbox.webhooks.constructEvent(payload, header, secret);
console.log(event.type);
```

See [Webhooks](https://checkbox.site/docs/webhooks) for a complete handler.
