Quickstart

Two ways in.
Both end in a call.

The fast path is your coding agent: connect it to the TalkWith MCP and ask for video. The manual path is three small files. Either way you'll need an account — sign up atthe dashboard first.

Path A · recommended

Point your agent.

Mint an account token in the dashboard atapp.talkwith.online, then add the TalkWith MCP to your agent's config.

Claude Code

claude mcp add talkwith \
  --env TALKWITH_API_URL=https://api.eu.talkwith.online \
  --env TALKWITH_ACCOUNT_TOKEN=vt_at_your_token \
  -- npx -y @talkwith/mcp

Cursor — .cursor/mcp.json

{
  "mcpServers": {
    "talkwith": {
      "command": "npx",
      "args": ["-y", "@talkwith/mcp"],
      "env": {
        "TALKWITH_API_URL": "https://api.eu.talkwith.online",
        "TALKWITH_ACCOUNT_TOKEN": "vt_at_your_token"
      }
    }
  }
}

Then, in your project, one prompt:

> add video calling to this app

The agent provisions a project, wires the keys into your environment, and scaffolds a<VideoRoom /> page plus a server-only token route — inside spend caps you set. Open two tabs on the scaffolded page and you're on a call.

Path B · manual

Wire it by hand.

Create a project in the dashboard to get a publishable key and asecret key, then it's an install, a token route, and a component.

  1. 01

    Install the embed

    npm install @talkwith/embed
  2. 02

    Add a server token route

    Next.js App Router shown — app/api/video-token/route.ts. The secret key stays on the server; createToken refuses to run in a browser.

    import { createToken } from "@talkwith/embed/server";
    
    export async function GET(req: Request) {
      // TODO: verify the caller's session here — as written, anyone who can
      // reach this route can mint a token and join the room.
      const secretKey = process.env.TALKWITH_SECRET_KEY;
      if (!secretKey) {
        return Response.json({ error: "video_unconfigured" }, { status: 503 });
      }
      const url = new URL(req.url);
      const { token, serverUrl } = await createToken({
        endpoint: "https://token.eu.talkwith.online/token",
        publishableKey: "pk_...", // your project's publishable key
        secretKey,
        room: url.searchParams.get("room") ?? "demo",
        identity: url.searchParams.get("identity") ?? "guest",
        template: "group", // "one_to_one" | "group" | "recording"
      });
      return Response.json({ token, serverUrl });
    }
  3. 03

    Render the room

    app/call/page.tsx<VideoRoom /> ships a complete call UI; pass children to go fully headless with theuseVideoRoom / useParticipantMedia hooks instead.

    "use client";
    import { VideoRoom } from "@talkwith/embed";
    import { useEffect, useState } from "react";
    
    export default function CallPage() {
      const [creds, setCreds] = useState<{ token: string; serverUrl: string } | null>(null);
      useEffect(() => {
        const identity = "guest-" + Math.random().toString(36).slice(2, 8);
        fetch("/api/video-token?room=demo&identity=" + encodeURIComponent(identity))
          .then((r) => r.json())
          .then(setCreds);
      }, []);
      if (!creds) return <p>Joining…</p>;
      return <VideoRoom serverUrl={creds.serverUrl} token={creds.token} />;
    }

before you shipGate the token route behind your own auth — derive identity androom from the signed-in session instead of trusting query params.