07 / Realtime

Build your own agent. Ship tonight.

The same path you try in the hub is the path that answers a real number. Interruptions work. Tools fire while the caller is still talking. No playground in the middle.

Two first-party packages: Python on PyPI, TypeScript on npm. Mint a key in the hub, create a session, connect. What you hear in the console is what the carrier hears — barge-in, live tools, and a voice that stays present while it looks things up.

Two packages

Python and TypeScript. Same session.

Official clients on PyPI and npm. Same realtime WebSocket, same voices, same server-side tools. Pick the language your service already speaks — you are not choosing a second production stack.

01 / Python

Python

The package is kupe. Create a session with realtime.sessions.create, then connect and stream. Works in a worker, a notebook, or a FastAPI sidecar.

02 / TypeScript

TypeScript

The package is kupe-sdk. Node 18+, ESM. import { Kupe } from "kupe-sdk". sendText and send_text both work so the two SDKs stay in lockstep.

03 / HTTP

HTTP

POST a session to https://x.kupe.in/v1/realtime/sessions, then attach to the WebSocket. The SDKs are convenience. The path is the API.

Same path

The hub is not a playground.

Try the agent in the console. Put it on a number. There is no second prompt and no export step. Interruptions, live tools, and presence on the line are the production path — the one you already heard.

01 / Interruptions

Interruptions

Playground bots die when the caller talks over them. The realtime path stops, listens, and resumes without restarting the script.

02 / Live tools

Live tools

Ledger lookup, ticket, receipt — they fire on the open line. After hangup is a summarizer, not the agent.

03 / Presence

Presence

The agent stays on the line while it looks things up. Then it speaks. Then it stops.

Official SDKs

Two clients. One live path.

Two first-party packages. Same session, same voices, same tools. Python on PyPI as kupe. TypeScript on npm as kupe-sdk. What you hear in the console is what the carrier hears.

TypeScriptrealtime.ts

$ npm install kupe-sdk

import { Kupe } from "kupe-sdk";

const kupe = new Kupe({ apiKey: process.env.KUPE_API_KEY });
const session = await kupe.realtime.sessions.create({
  name: "Priya",
  voice: "priya",
  prompt: "You collect overdue EMIs. Be warm and brief.",
  greeting: "Hi, this is Priya from the bank.",
});
const rt = await kupe.realtime.connect(session);
rt.sendText("Hi Priya — remind this customer their EMI is due tomorrow.");
for await (const event of rt) {
  if (event.type === "response.output_audio_transcript.done") {
    console.log("agent:", event.transcript);
  }
}