Getting started
Install @kortix/sdk, create a client, authenticate, and make your first calls.
Install
pnpm add @kortix/sdkreact (≥18) and @tanstack/react-query (≥5) are optional peers — needed only
if you use the @kortix/sdk/react hooks. The core client is framework-free and
runs in Node ≥ 18, Bun, modern browsers, and edge runtimes such as Cloudflare
Workers — see Streaming & runtime support for the full
matrix (React Native is REST-only today; live streaming is not supported there).
No build step? The SDK also ships CDN bundles — an ESM module and a
window.Kortix <script> global — see Distribution.
Create a client
createKortix(config) wires the platform seam once and returns one client. The
only required config is backendUrl and a getToken that returns your Kortix
token.
import { createKortix } from '@kortix/sdk';
export const kortix = createKortix({
backendUrl: 'https://api.kortix.com/v1',
getToken: async () => process.env.KORTIX_API_KEY!, // your Kortix API key
});Config
| field | type | required | what |
|---|---|---|---|
backendUrl | string | yes | Kortix API base, e.g. https://api.kortix.com/v1 |
getToken | () => Promise<string | null> | yes | Returns the bearer token — a Kortix API key, a PAT (kortix_pat_…), or a Supabase JWT |
getUserId | () => Promise<string | null> | no | Current user id, when the host knows it |
billingEnabled | boolean | no | Toggles billing-gated behaviour |
onError · onToast · onNotify | callbacks | no | Host sinks for errors, toasts, and notifications |
sandboxId | string | null | no | Default sandbox id for local/single-sandbox hosts |
featureFlags | object | no | Per-flag overrides for @kortix/sdk/feature-flags — see Modules |
createKortix calls configureKortix for you — the one global seam every SDK module reads. Call
it once at app startup.
Authentication
The SDK sends Authorization: Bearer <token> on every request; getToken supplies
it. The default is an API key — open your avatar menu → User settings →
API keys (under Account) → Create API key. Pick account-wide or a single
project as the scope, copy the kortix_pat_… (it is shown once), store it as a
secret, and return it:
const kortix = createKortix({
backendUrl: 'https://api.kortix.com/v1',
getToken: async () => process.env.KORTIX_API_KEY!,
});The key acts only on that project (rejected 403 elsewhere). Building a web app on
Kortix's own login instead? Return the user's Supabase session token. Full detail —
scopes, rotation, web vs backend — is on the Authentication
page.
Keys never live inside the SDK — getToken is called on demand, and the host owns storage,
caching, and refresh.
Your first calls
// list your projects
const projects = await kortix.projects.list();
// open a project, read its detail
const detail = await kortix.project(projectId).detail();
// create + start a session (one agent run, in its own sandbox on its own branch)
const created = await kortix.project(projectId).sessions.create();
const s = kortix.session(projectId, created.session_id);
await s.start();
// talk to the running agent — the typed opencode runtime, reached via the SDK
await s.runtime.session.prompt({
sessionID: (await s.ensureReady()).opencodeSessionId,
parts: [{ type: 'text', text: 'Add a README' }],
});Don't import @opencode-ai/sdk, backendApi, or authenticatedFetch in app code. Everything is
reachable through createKortix or a @kortix/sdk/* subpath.
In a React app
For a live UI, don't drive the runtime by hand — one hook runs a session:
import { useSession } from '@kortix/sdk/react';
function Chat({ projectId, sessionId }: { projectId: string; sessionId: string }) {
const s = useSession(projectId, sessionId);
if (s.phase !== 'ready') return <Booting stage={s.stage} onRetry={s.retry} />;
return (
<>
{s.messages.map(({ info, parts }) => (
<Message key={info.id} info={info} parts={parts} />
))}
<Composer busy={s.isBusy} onSend={(t) => s.send(t)} onStop={s.cancel} />
</>
);
}useSession owns /start, the runtime switch, the SSE stream, readiness, and the
canonical id — no provider to mount, no poller, no server store. See
React hooks.
Next
- Full example — zero to a streaming agent reply in one file.
- The client — the full facade surface.
- Sessions — lifecycle, runtime health, previews, and the opencode runtime.
- Streaming — live events, the readiness handshake, and runtime support.
- React hooks — live, reactive data for your UI.
- Distribution — npm, CDN bundles, and the stability tiers.