> ## Documentation Index
> Fetch the complete documentation index at: https://boxrouter.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Use the TypeScript SDK

> Install the BoxRouter TypeScript SDK, configure it, close it, and handle its errors.

`@boxrouter/sdk` is a promise-based client with bundled type declarations. It supports Node.js 22.18 or later.
Node.js 22.18 strips types from `.mts` files by default. Direct `.mts` examples that use `await using` need Node.js 24 or later.
`npm ls @boxrouter/sdk` prints the version you have.

## Install

```bash theme={"theme":"css-variables"}
npm install @boxrouter/sdk
```

Import the named exports from an `.mjs` file or a `"type": "module"` project; a `.cjs` file can
`require` them. Your first sandbox is in the [quickstart](https://boxrouter.ai/docs/quickstart.md#run-a-command-and-clean-up).

## Configure the Client

Each setting comes from the option, then the environment variable, then the default.

| Option | Environment Variable | Default |
| - | - | - |
| `apiKey` | `BOXROUTER_API_KEY` | None. The constructor throws without one. |
| `baseUrl` | `BOXROUTER_BASE_URL` | `https://api.boxrouter.ai/api/v1` |
| `fetch` | None | The global `fetch` |
| `userAgentSuffix` | None | None |
| `maxRetries` | None | 2. The client resends a call whose error says `retry: safe`; `0` turns it off. |

There is no timeout option. The client resends an API call only when the error says `retry: safe`, up to
`maxRetries` times, with the same idempotency key. To bound an API request, pass a `fetch` that adds an
abort signal. An aborted call throws `RequestError`; [Recover from Errors](https://boxrouter.ai/docs/errors.md) says when resending
is safe.

```typescript theme={"theme":"css-variables"}
import { BoxRouter } from '@boxrouter/sdk';

const client = new BoxRouter({
  fetch: (input, init) => fetch(input, { ...init, signal: AbortSignal.timeout(60_000) }),
});
```

## Close the Client

Client and sandbox handles support asynchronous disposal. `await using` closes the client and destroys
the sandbox at the end of their scopes, even when the workload throws. The sandbox is disposed before
the client. Disposing the client alone closes its local connection pool and leaves sandboxes running.

Run `.mts` files that use `await using` directly with Node.js 24 or later. The syntax needs TypeScript 5.2
or later and the `esnext.disposable` library (or `esnext`) in `tsconfig`. See the
[TypeScript 5.2 release notes](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-2.html#using-declarations-and-explicit-resource-management).

```typescript theme={"theme":"css-variables"}
import { BoxRouter } from '@boxrouter/sdk';

await using client = new BoxRouter();
await using box = await client.sandboxes.create();
process.stdout.write((await box.exec('echo hello')).stdout);
```

Output

```text theme={"theme":"css-variables"}
hello
```

If both the workload and disposal fail, TypeScript's async-disposal handling preserves both errors.

## Handle Errors

| Failure | Thrown As | What It Carries |
| - | - | - |
| BoxRouter refused or could not finish the call | `APIError` | `status`, `code`, `outcome`, `retry`, `retryAfterSeconds`, `fix`, `details`, `operationId`, `sandboxId`, `requestId`, `idempotencyKey`, `response` |
| No usable BoxRouter API response | `RequestError` | `request`, `cause`, `idempotencyKey`, `requestId`, and `response` when one arrived |
| A volume transfer link fails | `TransferError` | A message and, for an HTTP response, `status` |
| No API key | `TypeError` | The option to set |

A command that exits nonzero or reaches its timeout is a result: read `exit_code` and `timed_out`, because nothing is
thrown. Pass `{ check: true }` to throw `CommandFailed` for either. Save this example as `errors.mts`. It runs a command in a
sandbox that does not exist and prints the error's `code` and `outcome`:

```typescript theme={"theme":"css-variables"}
import { APIError, BoxRouter } from '@boxrouter/sdk';

const client = new BoxRouter();
try {
  await client.api.commands.run({ path: { sandbox_id: 'sb_missing' }, body: { command: 'echo hello' } });
} catch (error) {
  if (!(error instanceof APIError)) throw error;
  console.log(error.code, error.outcome);
  console.log(error.fix);
} finally {
  await client.close();
}
```

```bash theme={"theme":"css-variables"}
node errors.mts
```

Output

```text theme={"theme":"css-variables"}
not_found not_started
Check the ID or path: it may be misspelled, removed, or in another workspace.
```

A `retry` of `check_outcome` means BoxRouter cannot tell whether the call ran. Read the operation before resending
([Recover from Errors](https://boxrouter.ai/docs/errors.md#check-whether-your-work-started) has the steps), and quote `requestId` to
[support](https://boxrouter.ai/support).

## Where Each Task Lives

* [Files](https://boxrouter.ai/docs/files.md): `read` and `write` sandbox files.
* [Volumes](https://boxrouter.ai/docs/volumes.md): upload and download files outside a sandbox.
* [Commands](https://boxrouter.ai/docs/commands.md) and [background processes](https://boxrouter.ai/docs/processes.md).
* [Pause and resume](https://boxrouter.ai/docs/pause-resume.md).

## Next Steps

> [card] [Find an SDK or CLI Call](https://boxrouter.ai/docs/sdk.md)
>
> The TypeScript call for each sandbox task.

> [card] [Recover from Errors](https://boxrouter.ai/docs/errors.md)
>
> When resending a failed call is safe.

> [card] [Use the Python SDK](https://boxrouter.ai/docs/python.md)
>
> The same tasks in Python.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.