Skip to main content

SDK samples

Short, focused snippets for the most common tasks with the @4players/odin-cortex SDK. Each is runnable on its own — set CORTEX_API_KEY and your project id, then run with npx tsx <file>.ts.

Every sample starts from the same client:

import { CortexClient } from "@4players/odin-cortex";

const PROJECT_ID = "__YOUR_PROJECT_ID__";

const client = new CortexClient({
baseUrl: process.env.BASE_URL ?? "https://ots.odin.4players.io",
apiKey: process.env.CORTEX_API_KEY, // ots_live_...
});

const project = client.project(PROJECT_ID);

Create and start a session

const session = await project.sessions.create({
title: "Script Test Session",
externalRoomId: "room-1",
idleTimeout: 60,
autoStart: true, // start the bot immediately
});

console.log("Session created:", session.id);

If you don’t pass autoStart, start it yourself:

await session.start();

List sessions, then collect a transcript

// List existing sessions
const sessions = await project.sessions.list();
for (const s of sessions) {
console.log(`[${s.status}] ${s.id}`);
}

// Create, start, wait, stop, read messages
const session = await project.sessions.create({
title: "Script Test",
externalRoomId: "hello",
idleTimeout: 60,
});

await session.start();
await new Promise((r) => setTimeout(r, 30_000)); // let it collect audio
await session.stop();

const messages = await session.getMessages();
console.log(`Got ${messages.length} message(s)`);

Update the bot’s user data

The bot’s userData (the profile it presents in the ODIN room) lives in project settings. Use the partial update() to change just that one field — everything else is preserved:

const botUserData = {
name: "Transcription Bot",
role: "bot",
avatar: "https://example.com/bot.png",
};

const updated = await project.settings.update({ botUserData });
console.log("Updated bot userData:", updated.botUserData);

Use project.settings.upsert() instead when you want to set the full configuration (including the token provider).

Watch a session and its transcript live

const sessionId = process.env.SESSION_ID ?? "__YOUR_SESSION_ID__";

// The session document — fires on any change, undefined if deleted.
const sessionSub = project.sessions.watch(sessionId);
sessionSub.onSnapshot((session) => {
if (!session) return console.log("[session] deleted or not found");
console.log(`[session] ${session.title} — status=${session.status}`);
});

// The transcript — initial messages via REST, new ones streamed live.
const session = await project.sessions.get(sessionId);
const messageSub = session.watchMessages();
messageSub.onSnapshot((messages, changes) => {
for (const change of changes) {
if (change.type === "added") {
console.log(` + ${change.data.senderName}: ${change.data.content}`);
}
}
});

process.on("SIGINT", () => {
sessionSub.unsubscribe();
messageSub.unsubscribe();
process.exit(0);
});

Watch the whole sessions collection

const sub = project.sessions.watch();

sub.onSnapshot((sessions, changes) => {
console.log(`\n[snapshot] ${sessions.length} session(s)`);
for (const change of changes) {
console.log(` ${change.type.padEnd(8)} ${change.id} (${change.data.status})`);
}
});

sub.onError((err) => console.error("[error]", err));

process.on("SIGINT", () => {
sub.unsubscribe();
process.exit(0);
});