Skip to main content
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.
Package: @corti/sdk on npm | Source: GitHub | Examples: corti-examples

Prerequisites

  • Node.js 18 or later
  • npm, yarn, or pnpm
  • A Corti API client from the API Console

Installation

npm install @corti/sdk

Initialization

The simplest way to get started is with client credentials (server-side):
JavaScript
import { CortiClient } from "@corti/sdk";

const client = new CortiClient({
    environment: "YOUR_ENVIRONMENT_ID",
    tenantName: "YOUR_TENANT_NAME",
    auth: {
        clientId: "YOUR_CLIENT_ID",
        clientSecret: "YOUR_CLIENT_SECRET",
    },
});
Client credentials authentication is intended for backend / server-side applications only. Never expose your clientSecret in frontend code. For browser apps, use bearer tokens, PKCE, or a proxy.
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.

Authentication

The SDK supports five authentication methods to cover different deployment scenarios:
MethodEnvironmentUse case
Client Credentials (recommended)Backend onlyServer-to-server integrations
Bearer TokenFrontend & BackendWhen you already have a token from another source
Authorization CodeFrontend & BackendInteractive user login (confidential clients)
PKCEFrontend & BackendInteractive user login (public clients, SPAs)
ROPCBackend onlyUsername/password for trusted apps
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 use cases where end-user login is required.
Each method is covered in detail in the Authentication Guide.

Usage examples

Create an interaction

JavaScript
const now = new Date();

const { interactionId, websocketUrl } = await client.interactions.create({
  assignedUserId: "GUID OF YOUR CHOOSING",
  encounter: {
    identifier: "GUID OF YOUR CHOOSING",
    status: "planned",
    type: "first_consultation",
    period: {
      startedAt: now,
      endedAt: now,
    },
    title: "Consultation",
  },
  patient: {
    identifier: "<string>",
    name: "<string>",
    gender: "male",
    birthDate: now,
    pronouns: "<string>",
  },
});
See the full request specification in the API Reference.

Real-time transcription (WebSocket)

JavaScript
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

JavaScript
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 — limit token access to specific endpoints
See the full Proxy Guide for implementation details and examples.

Error handling

The SDK throws typed exceptions you can catch and inspect:
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);
    }
}
ExceptionWhen it’s thrown
CortiErrorAPI returned a non-2xx HTTP response (4xx / 5xx)
CortiSDKErrorSDK infrastructure error (e.g. localStorage unavailable)
ParseErrorInput validation failed (e.g. missing PKCE verifier, invalid JWT)
JsonErrorResponse body could not be parsed as JSON

TypeScript types

All request and response types are exported as TypeScript interfaces under the Corti namespace:
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:
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:
const response = await client.interactions.create(..., {
    timeoutInSeconds: 30,
});

Abort requests

Cancel any request using an AbortSignal:
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():
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:
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:
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:
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:
const response = await client.interactions.create(..., {
    queryParams: { customQueryParamKey: "custom query param value" },
});

File uploads

The SDK accepts a variety of types when uploading files:
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:
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:
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
    },
});
PropertyDescriptionDefault
levelDebug, Info, Warn, or ErrorInfo
loggerLogger implementation (implements logging.ILogger)ConsoleLogger
silentWhether to silence all loggingtrue

Runtime compatibility

The SDK works in the following runtimes:
  • Node.js 18+
  • Vercel
  • Cloudflare Workers
  • Deno v1.25+
  • Bun 1.0+
  • React Native

Resources


For support or questions, reach out through help.corti.app