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.
Prerequisites
- Node.js 18 or later
- npm, yarn, or pnpm
- A Corti API client from the API Console
Installation
Initialization
The simplest way to get started is with client credentials (server-side):
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:
| 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 |
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
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>",
},
});
Real-time transcription (WebSocket)
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
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);
}
}
| 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:
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"]);
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
});
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
},
});
| 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