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

# JavaScript SDK

> Install, configure, and use the Corti JavaScript SDK

The `@corti/sdk` package is the official JavaScript SDK for the Corti API. It provides full coverage of every REST endpoint and WebSocket connection, with built-in authentication, automatic token refresh, type safety, and error handling.

<Info>
  **Package:** [@corti/sdk on npm](https://www.npmjs.com/package/@corti/sdk) | **Source:** [GitHub](https://github.com/corticph/corti-sdk-javascript) | **Examples:** [corti-examples](https://github.com/corticph/corti-examples)
</Info>

## Prerequisites

* **Node.js 18** or later
* **npm**, **yarn**, or **pnpm**
* A Corti API client from the [Corti Console](https://console.corti.app/)

## Installation

<CodeGroup>
  ```bash npm theme={null}
  npm install @corti/sdk
  ```

  ```bash yarn theme={null}
  yarn add @corti/sdk
  ```

  ```bash pnpm theme={null}
  pnpm add @corti/sdk
  ```
</CodeGroup>

## Initialization

The simplest way to get started is with **client credentials** (server-side):

```ts title="JavaScript" theme={null}
import { CortiClient } from "@corti/sdk";

// Replace these with your values
const CLIENT_ID = "<your-client-id>";
const CLIENT_SECRET = "<your-client-secret>";
const ENVIRONMENT = "<eu-or-us>";
const TENANT = "<your-tenant-name>";

const client = new CortiClient({
    environment: ENVIRONMENT,
    tenantName: TENANT,
    auth: {
        clientId: CLIENT_ID,
        clientSecret: CLIENT_SECRET,
    },
});
```

<Warning>Client credentials authentication is intended for **backend / server-side** applications only. Never expose your `clientSecret` in frontend code. For browser apps, use [bearer tokens](/sdk/js/authentication#bearer-token), [PKCE](/sdk/js/authentication#authorization-code-flow-with-pkce), or a [proxy](/sdk/js/proxy).</Warning>

<Tip>Create a single `CortiClient` instance and reuse it throughout your application. The SDK handles token refresh automatically -- there is no need to re-initialize for each request.</Tip>

## Authentication

The SDK supports five authentication methods to cover different deployment scenarios:

| Method                               | Environment        | Use case                                          |
| :----------------------------------- | :----------------- | :------------------------------------------------ |
| **Client Credentials** (recommended) | Backend only       | Server-to-server integrations                     |
| **Bearer Token**                     | Frontend & Backend | When you already have a token from another source |
| **Authorization Code**               | Frontend & Backend | Interactive user login (confidential clients)     |
| **PKCE**                             | Frontend & Backend | Interactive user login (public clients, SPAs)     |
| **ROPC**                             | Backend only       | Username/password for trusted apps                |

<Warning>**Client Credentials is the recommended authentication method.** Your backend should handle all data access checks and never expose the service-account token or client secret to the browser. The other flows (Authorization Code, PKCE, ROPC) are primarily intended for [Embedded Assistant](/assistant/authentication) use cases where end-user login is required.</Warning>

Each method is covered in detail in the [Authentication Guide](/sdk/js/authentication).

## Usage examples

### Create an interaction

```ts title="JavaScript" theme={null}
// Replace these with your values
const ASSIGNED_USER_ID = "<uuid-of-your-choosing>";
const IDENTIFIER = "<id-of-your-choosing>";

const now = new Date();

const { interactionId, websocketUrl } = await client.interactions.create({
  assignedUserId: ASSIGNED_USER_ID,
  encounter: {
    identifier: IDENTIFIER,
    status: "planned",
    type: "first_consultation",
    period: {
      startedAt: now,
      endedAt: now,
    },
    title: "Consultation",
  },
  patient: {
    identifier: "<string>",
    name: "<string>",
    gender: "male",
    birthDate: new Date("1990-01-15T00:00:00Z"),
    pronouns: "<string>",
  },
});
```

<Tip>See the full request specification in the [API Reference](/api-reference/interactions/create-interaction).</Tip>

### Real-time transcription (WebSocket)

```ts title="JavaScript" theme={null}
const socket = await client.transcribe.connect({
  configuration: {
    primaryLanguage: "en",
    automaticPunctuation: true,
  },
});

socket.on("message", (message) => {
  if (message.type === "transcript") {
    console.log("Transcript:", message.data.text);
  }
});

// Send audio data (e.g. from a microphone stream)
socket.sendAudio(audioBuffer);
```

### Text generation

```ts title="JavaScript" theme={null}
const document = await client.documents.create(interactionId, {
  context: [
    {
      type: "transcript",
      data: {
        text: "tell me a bit about what’s been going on? When did you first start feeling unwell?\n\n- Erm, I think it was probably about a week ago.\n\n- Right, okay. And when you say achy, was it more like muscle aches, or joint pain?",
      },
    },
  ],
  templateKey: "corti-brief-clinical-note",
  name: "test brief note from transcript",
  outputLanguage: "en",
});
```

## Proxy support

When you need to route SDK traffic through your own backend (for security or access control), the SDK supports:

* **`baseUrl`** -- redirect all REST and WebSocket traffic to your proxy
* **Custom environment URLs** -- fine-grained control over REST, WebSocket, auth, and agent endpoints
* **`CortiWebSocketProxyClient`** -- lightweight WebSocket-only proxy client
* **[Scoped tokens](/sdk/js/authentication#scoped-tokens)** -- limit token access to specific endpoints

See the full [Proxy Guide](/sdk/js/proxy) for implementation details and examples.

## Error handling

The SDK throws typed exceptions you can catch and inspect:

```ts theme={null}
import { CortiError, CortiSDKError, CortiSDKErrorCodes, ParseError, JsonError } from "@corti/sdk";

try {
    await client.interactions.create(...);
} catch (err) {
    if (err instanceof CortiError) {
        console.log(err.statusCode);
        console.log(err.message);
        console.log(err.body);
        console.log(err.rawResponse);
    } else if (err instanceof CortiSDKError) {
        console.log(err.code);    // e.g. CortiSDKErrorCodes.LOCAL_STORAGE_ERROR
        console.log(err.message);
        console.log(err.cause);
    } else if (err instanceof ParseError) {
        console.log(err.errors);  // ValidationError[]
        console.log(err.message);
    } else if (err instanceof JsonError) {
        console.log(err.errors);  // ValidationError[]
        console.log(err.message);
    }
}
```

| Exception       | When it's thrown                                                  |
| :-------------- | :---------------------------------------------------------------- |
| `CortiError`    | API returned a non-2xx HTTP response (4xx / 5xx)                  |
| `CortiSDKError` | SDK infrastructure error (e.g. localStorage unavailable)          |
| `ParseError`    | Input validation failed (e.g. missing PKCE verifier, invalid JWT) |
| `JsonError`     | Response body could not be parsed as JSON                         |

## TypeScript types

All request and response types are exported as TypeScript interfaces under the `Corti` namespace:

```ts theme={null}
import { Corti } from "@corti/sdk";

const request: Corti.InteractionsListRequest = {
    ...
};
```

## Advanced configuration

### Retries

The SDK automatically retries on `408`, `429`, and `5xx` status codes with exponential backoff. The default retry limit is 2. Override per request:

```ts theme={null}
const response = await client.interactions.create(..., {
    maxRetries: 0, // disable retries for this request
});
```

### Timeouts

The SDK defaults to a 60-second timeout. Override per request:

```ts theme={null}
const response = await client.interactions.create(..., {
    timeoutInSeconds: 30,
});
```

### Abort requests

Cancel any request using an `AbortSignal`:

```ts theme={null}
const controller = new AbortController();
const response = await client.interactions.create(..., {
    abortSignal: controller.signal,
});
controller.abort();
```

### Raw responses

Access the underlying HTTP response alongside parsed data using `.withRawResponse()`:

```ts theme={null}
const { data, rawResponse } = await client.interactions.create(...).withRawResponse();

console.log(data);
console.log(rawResponse.headers["X-My-Header"]);
```

### Pagination

List endpoints are paginated. The SDK provides an async iterator so you can loop over items automatically:

```ts theme={null}
const response = await client.interactions.list();
for await (const item of response) {
    console.log(item);
}

// Or iterate page-by-page manually
let page = await client.interactions.list();
while (page.hasNextPage()) {
    page = page.getNextPage();
}

// Access the underlying response
const raw = page.response;
```

### Custom fetch client

Supply your own `fetch` implementation if you're running in an unsupported environment or need custom behavior:

```ts theme={null}
const client = new CortiClient({
    // ... auth options
    fetcher: // provide your implementation here
});
```

### Additional headers

Add headers to every request via the constructor, or per request as a request option:

```ts theme={null}
const client = new CortiClient({
    // ... auth options
    headers: { "X-Custom-Header": "custom value" },
});

const response = await client.interactions.create(..., {
    headers: { "X-Custom-Header": "custom value" },
});
```

### Additional query parameters

Add extra query string parameters per request:

```ts theme={null}
const response = await client.interactions.create(..., {
    queryParams: { customQueryParamKey: "custom query param value" },
});
```

## File uploads

The SDK accepts a variety of types when uploading files:

```ts theme={null}
import { createReadStream } from "fs";

await client.recordings.upload(createReadStream("path/to/file"), ...);
await client.recordings.upload(new ReadableStream(), ...);
await client.recordings.upload(Buffer.from("binary data"), ...);
await client.recordings.upload(new Blob(["binary data"], { type: "audio/mpeg" }), ...);
await client.recordings.upload(new File(["binary data"], "file.mp3"), ...);
await client.recordings.upload(new ArrayBuffer(8), ...);
await client.recordings.upload(new Uint8Array([0, 1, 2]), ...);
```

Supported types:

* **Stream types:** `fs.ReadStream`, `stream.Readable`, `ReadableStream`
* **Buffered types:** `Buffer`, `Blob`, `File`, `ArrayBuffer`, `ArrayBufferView`, `Uint8Array`

You can also attach metadata:

```ts theme={null}
import { Uploadable } from "@corti/sdk";

const file: Uploadable.WithMetadata = {
    data: createReadStream("path/to/file"),
    filename: "my-file",
    contentType: "audio/mpeg",
    contentLength: 1949,
};

// Or upload directly from a file path
const file: Uploadable.FromPath = {
    path: "path/to/file",
    filename: "my-file",
    contentType: "audio/mpeg",
    contentLength: 1949,
};
```

## Logging

The SDK supports configurable logging:

```ts theme={null}
import { CortiClient, logging } from "@corti/sdk";

const client = new CortiClient({
    // ... auth options
    logging: {
        level: logging.LogLevel.Debug,
        logger: new logging.ConsoleLogger(),
        silent: false, // defaults to true, set to false to enable logging
    },
});
```

| Property | Description                                          | Default         |
| :------- | :--------------------------------------------------- | :-------------- |
| `level`  | `Debug`, `Info`, `Warn`, or `Error`                  | `Info`          |
| `logger` | Logger implementation (implements `logging.ILogger`) | `ConsoleLogger` |
| `silent` | Whether to silence all logging                       | `true`          |

## Runtime compatibility

The SDK works in the following runtimes:

* Node.js 18+
* Vercel
* Cloudflare Workers
* Deno v1.25+
* Bun 1.0+
* React Native

## Resources

* **[npm package](https://www.npmjs.com/package/@corti/sdk)** -- latest version, changelog, and install info
* **[GitHub source](https://github.com/corticph/corti-sdk-javascript)** -- SDK source code
* **[Examples repository](https://github.com/corticph/corti-examples)** -- working code for authentication, streaming, text generation, and more
* **[Authentication Guide](/sdk/js/authentication)** -- all five auth flows with code examples
* **[Proxy Guide](/sdk/js/proxy)** -- secure frontend integration patterns
* **[API Reference](/api-reference/welcome)** -- full endpoint specifications

***

<Note>For support or questions, reach out through [help.corti.app](https://help.corti.app)</Note>
