JavaScript SDK
The @cortex/sdk package is the same client the embed widget uses internally — exposed as an npm module for cases where you want a fully custom UI rather than the floating launcher.
It’s tree-shakable, zero-dep at runtime (re-exports types from @cortex/shared only), and weighs <10 KB gzip on the core client. The framework adapters (React, Next.js) are separate entry points so you only pay for what you import.
Install
npm install @cortex/sdk# orpnpm add @cortex/sdkWorks in browsers, Node ≥18, Cloudflare Workers, Deno, and any Web-standard runtime — no shims needed.
Core client
import { createCortexClient } from '@cortex/sdk';
const client = createCortexClient({ baseUrl: 'https://api.cortexlayer.dev', auth: { apiKey: process.env.CORTEX_API_KEY },});
// Server-side: mint a session for the browser.const session = await client.mintSession('agt_abc123...', { origin: 'https://your-site.com',});
// Browser-side: stream a chat. Set `auth.sessionToken` on a fresh client.const browserClient = createCortexClient({ baseUrl: 'https://api.cortexlayer.dev', auth: { sessionToken: session.session_token },});
for await (const event of browserClient.chat({ agentId: 'agt_abc123...', messages: [{ role: 'user', content: 'Hi' }],})) { if (event.type === 'delta') console.log(event.text); if (event.type === 'done') break;}createCortexClient requires baseUrl — there’s no default. The SDK runs in widgets loaded from arbitrary origins, and silently defaulting to a production URL is a security footgun.
Rotating the session token without re-creating the client
Pass sessionToken per call instead of re-instantiating:
for await (const event of browserClient.chat( { agentId: 'agt_abc123...', messages }, { sessionToken: freshlyMintedToken },)) { /* ... */ }The widget uses this pattern internally — its MountHandle.setSessionToken() updates a ref the next chat() call reads — so a token refresh doesn’t unmount the conversation.
React hook
npm install @cortex/sdk reactimport { useCortexChat } from '@cortex/sdk/react';
function Chat({ client }) { const { messages, send, busy } = useCortexChat({ client, agentId: 'agt_abc123...', });
return ( <div> {messages.map((m, i) => <div key={i}>{m.role}: {m.content}</div>)} <button onClick={() => send('Hello!')} disabled={busy}>Send</button> </div> );}useCortexChat aborts in-flight streams on unmount, so you can mount/unmount freely without leaking requests. Preact users can use the same hook by aliasing react → preact/compat.
Next.js (App Router)
The mint route handler is a one-liner that forwards the browser’s Origin header to Cortex (otherwise the API’s allowlist check sees a server-to-server call with no origin and rejects):
import { createCortexClient } from '@cortex/sdk';import { createMintRouteHandler } from '@cortex/sdk/next';
const client = createCortexClient({ baseUrl: 'https://api.cortexlayer.dev', auth: { apiKey: process.env.CORTEX_API_KEY! },});
export const POST = createMintRouteHandler({ client, agentId: 'agt_abc123...', // Optional: 401 unauthenticated callers before they hit Cortex. requireAuth: async (req) => { const session = await getSession(req); if (!session) return new Response(null, { status: 401 }); },});The same handler works in Cloudflare Workers, Deno Deploy, and any Web-standard runtime — it’s (req: Request) => Promise<Response>.
Vanilla streamer
If you don’t want the full client, streamChat is the one-call low-level streamer:
import { streamChat } from '@cortex/sdk/vanilla';
const stream = streamChat({ baseUrl: 'https://api.cortexlayer.dev', sessionToken: 'cs_...', agentId: 'agt_abc123...', messages: [{ role: 'user', content: 'Hi' }],});
for await (const event of stream) { console.log(event);}Errors
Every API failure throws CortexApiError:
import { CortexApiError } from '@cortex/sdk';
try { await client.mintSession('agt_...');} catch (err) { if (err instanceof CortexApiError) { console.error(err.code, err.status, err.requestId); }}code matches the API error codes (agent_not_found, rate_limit_exceeded, …) and is stable across versions. requestId matches the request_id in the API envelope — include it in support tickets.
Bundle budgets
Enforced in CI via size-limit:
| Entry | Budget |
|---|---|
@cortex/sdk (core) | <10 KB gzip |
@cortex/sdk/react | <3 KB gzip |
@cortex/sdk/next | <2 KB gzip |
@cortex/sdk/vanilla | <2 KB gzip |
Regressions >5% need an explicit sizebot-override PR label.