Bring your own agent.
Add Krava as your privacy backend.
~15 minutes. Works with any Node/Bun/Deno runtime. Four steps — the last one verifies the whole chain end-to-end against the live Krava API.
- 01
01. Install the SDK
Zero dependencies. Dual ESM/CJS. TypeScript types included.
npm install @kravalabs/api-clientnpm install @kravalabs/api-clientWorks with Node 18+, Bun, Deno, and any modern runtime that implements
fetch. - 02
02. Get your Krava appKey
Server-side only. We'll generate a ready-to-use .env.local for you.
Get your API keyGenerate your
KRAVA_APP_KEYThe Krava Platform is where you register your app and grab your App Key (your server-side secret). Open it in a new tab, register an app, copy the App Key shown once in the amber banner, and paste it below.
- 01Open /platform
Opens in a new tab. Sign in with a passkey if it's your first time.
First time? You'll see an “Identity Created” screen with a backup token — save it to your password manager immediately. It's your passkey recovery key and won't be shown again.
- 02Click
+ New app, give it a name, then click Create. An amber banner will appear — click Copy App Key.⚠ Shown once only. Save this to a password manager, encrypted note, or print and store offline. If you lose it, register a new app.
- 03
Paste it here:
Stays in your browser. Never sent to a server.
- 04
Drop it at the root of your project. Your app reads
KRAVA_APP_KEYfrom there.
Verify it works: after dropping the file, runnpx @kravalabs/api-client doctor— it pings the live API end-to-end and prints a 7-probe pass/fail report. - 01
- 03
03. Provision a user and stream chat
Two SDK calls. One integration.
Server-side — map your user id to an encrypted Krava userToken:
// server.ts import { createKravaPlatformClient } from "@kravalabs/api-client"; const krava = createKravaPlatformClient({ appKey: process.env.KRAVA_APP_KEY!, }); // Map your user id (Postgres, Clerk, whatever) → a Krava userToken. // Token is encrypted and safe to hand to the browser. const { userToken } = await krava.users.getOrCreate("user_42"); console.log("user is ready:", userToken.slice(0, 12) + "…");// server.ts import { createKravaPlatformClient } from "@kravalabs/api-client"; const krava = createKravaPlatformClient({ appKey: process.env.KRAVA_APP_KEY!, }); // Map your user id (Postgres, Clerk, whatever) → a Krava userToken. // Token is encrypted and safe to hand to the browser. const { userToken } = await krava.users.getOrCreate("user_42"); console.log("user is ready:", userToken.slice(0, 12) + "…");The first call to
users.getOrCreatecreates the user; subsequent calls with the sameexternalUserIdreturn the same identity. Tokens are encrypted server-to-server and safe to forward to the browser.Once you have the
userToken, pass it to the chat call:// chat.ts // userToken came from your server-side provisioning step above. const res = await fetch("https://krava.io/api/platform/chat", { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${userToken}`, }, body: JSON.stringify({ message: "Hello from my agent.", system: "You are a concise, helpful AI assistant.", }), }); if (!res.ok) throw new Error(`Chat failed (${res.status})`); if (!res.body) throw new Error("Streaming not supported"); const reader = res.body.getReader(); const decoder = new TextDecoder(); let buf = ""; while (true) { const { done, value } = await reader.read(); if (done) break; buf += decoder.decode(value, { stream: true }); const lines = buf.split("\n"); buf = lines.pop() ?? ""; for (const line of lines) { if (!line.startsWith("data: ")) continue; const data = line.slice(6).trim(); if (data === "[DONE]") break; const parsed = JSON.parse(data); if (parsed.text) process.stdout.write(parsed.text); } }// chat.ts // userToken came from your server-side provisioning step above. const res = await fetch("https://krava.io/api/platform/chat", { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${userToken}`, }, body: JSON.stringify({ message: "Hello from my agent.", system: "You are a concise, helpful AI assistant.", }), }); if (!res.ok) throw new Error(`Chat failed (${res.status})`); if (!res.body) throw new Error("Streaming not supported"); const reader = res.body.getReader(); const decoder = new TextDecoder(); let buf = ""; while (true) { const { done, value } = await reader.read(); if (done) break; buf += decoder.decode(value, { stream: true }); const lines = buf.split("\n"); buf = lines.pop() ?? ""; for (const line of lines) { if (!line.startsWith("data: ")) continue; const data = line.slice(6).trim(); if (data === "[DONE]") break; const parsed = JSON.parse(data); if (parsed.text) process.stdout.write(parsed.text); } }Memory writes happen automatically — Krava extracts salient facts from the conversation and stores them encrypted under the user's key. They become available on the next call.
- 04
04. Verify with `krava doctor`
One command. Green = ship.
KRAVA_APP_KEY=your_app_key_here npx @kravalabs/api-client doctorKRAVA_APP_KEY=your_app_key_here npx @kravalabs/api-client doctorDoctor runs 7 probes against the live API. Output looks like:
krava doctor — verifying https://krava.io hasAppKey: true baseUrlReachable: true userProvisioned: true chatStatus: 200 chatIdReceived: true textDeltaEvents: 5 finalTextLength: 42 ✓ Krava integration verified.krava doctor — verifying https://krava.io hasAppKey: true baseUrlReachable: true userProvisioned: true chatStatus: 200 chatIdReceived: true textDeltaEvents: 5 finalTextLength: 42 ✓ Krava integration verified.You shipped. Your agent is running on Krava's privacy infrastructure. Encrypted memory, passkey identity, model-agnostic routing — all live. Tweet at us with what you built.