---
title: "TypeScript SDK"
description: "Install @arbol-ai/sdk, create a client and call the Arbol API from TypeScript or JavaScript."
---

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

# TypeScript SDK

[`@arbol-ai/sdk`](https://www.npmjs.com/package/@arbol-ai/sdk) is the Arbol API for TypeScript and JavaScript. It is generated from the API's public OpenAPI document and released under the Apache 2.0 license.

## Install

```sh
npm i @arbol-ai/sdk
yarn add @arbol-ai/sdk
pnpm add @arbol-ai/sdk
bun add @arbol-ai/sdk
```

The package is an ES module: load it with `import`.

## Requirements

- **`fetch` and `Temporal`** in the runtime: Node.js 26, Bun 1.4 or a current browser. `date-time` fields are `Temporal.Instant` and `date` fields are `Temporal.PlainDate`.
- **TypeScript** with `"lib": ["ESNext"]` in `tsconfig.json`.

## Create a client

```ts
import { createClient } from '@arbol-ai/sdk';

const arbol = createClient({
  baseUrl: 'https://api.getarbol.com',
  token: process.env.ARBOL_API_KEY!,
});
```

`token` is sent as `Authorization: Bearer <token>`. It is either:

- an Arbol API key, created in Account. Keep it in a secret manager and never ship it to a browser;
- an access token for the audience `https://api.getarbol.com`, such as a person's session in your app.

The SDK holds no sign-in logic: sign people in the way your application does, then create a client with the token you have. See [Authentication](/en/developers/authentication/).

| Option | Meaning |
|---|---|
| `baseUrl` | Required: `https://api.getarbol.com`. |
| `token` | Required: the credential. |
| `fetch` | A function to send requests with, instead of the global `fetch`. |
| `headers`, `query` | Headers and query parameters added to every request. |

## Call an operation

Every operation is `arbol.<service>.<resource>.<verb>(request, options?)`, named after its operation id: `raiz.agents.create` is `arbol.raiz.agents.create()`, and `nueva-eps` is `arbol.nuevaEps`. Requests and responses are typed from the OpenAPI document.

```ts
const { data: agent } = await arbol.raiz.agents.create({
  modality: 'text',
  name: 'Appointment reminders',
  instructions: 'You remind patients of Example Clinic about upcoming appointments.',
  language: 'es-CO',
  timeZone: 'America/Bogota',
});

const { data: appointment } = await arbol.agenda.appointments.get({
  appointmentId: 'eng_0f6b2c1e-7d4a-4c3b-9e8f-1a2b3c4d5e6f',
});
appointment.startsAt; // Temporal.Instant
```

A method resolves with the whole response envelope, `{ success: true, data, error: null, metadata }`, so destructure `data`. The second argument takes `signal` to abort the call, and `headers` or `query` for this request only.

A list answers one page: the items are in `data.data`, and `data.pageInfo.nextCursor` asks for the next one.

```ts
let cursor: string | undefined;
do {
  const { data: page } = await arbol.raiz.agents.list({ status: 'active', cursor });
  for (const item of page.data) console.log(item.id, item.name);
  cursor = page.pageInfo.nextCursor ?? undefined;
} while (cursor);
```

### Import only what you use

Each service and each resource is also an entry of the package, with its own `createClient`, so your application bundles only what it calls:

```ts
import { createClient } from '@arbol-ai/sdk/agenda/appointments';

const appointments = createClient({
  baseUrl: 'https://api.getarbol.com',
  token: process.env.ARBOL_API_KEY!,
});

const { data } = await appointments.get({
  appointmentId: 'eng_0f6b2c1e-7d4a-4c3b-9e8f-1a2b3c4d5e6f',
});
```

`@arbol-ai/sdk/<service>` is one service (`client.<resource>.<verb>`) and `@arbol-ai/sdk/<service>/<resource>` one resource (`client.<verb>`), named as the SDK names them, such as `agenda/appointments` or `nuevaEps/affiliations`. Each entry exports its types and `ApiError`.

## Errors

A response with any status outside 2xx throws `ApiError`, with the `status`, the `response` and, in `details`, the error body the API declares: `{ success: false, error: { code, message, retryable, data }, metadata }`. A failure to reach the API rejects with the error `fetch` throws.

```ts
import { ApiError, type Failure } from '@arbol-ai/sdk';

try {
  await arbol.raiz.agents.get({ agentId: 'agt_01jd8x5k2m7q9r3t6v8w0y4z1b' });
} catch (error) {
  if (!(error instanceof ApiError)) throw error;
  const failure = (error.details as { error?: Failure } | undefined)?.error;
  console.error(error.status, failure?.code, error.response.headers.get('x-request-id'));
}
```

Each call sends one request and is never retried. Before you repeat a write that failed without a clear answer, such as `502 OUTCOME_UNKNOWN`, read the current state. See [Responses and errors](/en/developers/concepts/responses-and-errors/) and [Retries](/en/developers/concepts/retries/).

The API authorizes every call: a method in the client is not a permission.

## Versions

Versions follow semver. A major version brings incompatible changes: 5.0.0, for example, adopted the final names of resources and of the ids in paths. Automatic publications raise the minor version, so pin the exact version and review each release before updating.

Each version records the API release it was generated from:

```bash
npm view @arbol-ai/sdk arbol.openapi          # the latest version
npm view @arbol-ai/sdk@5.0.0 arbol.openapi   # a particular version
```

It prints the release (the OpenAPI document's `info.version`) and a SHA-256 hash of the document's content. Pin the exact version and verify your integration when updating (see [Versions and updates](/en/developers/concepts/versions/)).

Source: https://docs.getarbol.com/en/developers/sdks/typescript/index.mdx
