A web call has two halves. Your server mints a call token with POST /v1/calls/token. Your page joins the call with @talqing/sdk/browser. There is no widget to embed and no script tag — you build the UI, and the SDK gives you the room, the microphone, the transcript and the agent’s state.
POST /v1/calls/token needs the editor role, and a personal access token is a workspace credential: it can read, change and delete every agent, call and phone number in the workspace. Never ship one to a browser, and never call this endpoint from browser code with one. Mint the token on your server, behind your own sign-in, and hand the browser only the response.

1. Mint the token on your server

The token starts nothing by itself. It mints the credential a browser needs to join, and files the call so GET /v1/calls/{session_id} answers immediately — as queued until a browser actually connects. To dial a phone instead, use POST /v1/calls/outbound; see outbound calls.

The request body

uuid
The agent to run. Prefer this over the three inline forms below — an agent that exists in the workspace has an editor, a version history and a cost record.
string
Your own stable id for the person on the call. Omit it and each call mints a single-use key of its own, so two calls from the same person arrive as two strangers. Max 256 characters, and it must not start with a reserved prefix — see text conversations.
object
What this call already knows about the person, read as {{userdata.field}} from the prompt, the greeting and every tool. It is merged onto the contact’s record, so it is there again on their next call. Keys beginning with _talqing are reserved. See userdata.
object
Values for the {{vars.*}} the agents on this call declare — configuration of the session rather than facts about the person. Read-only, gone when the call ends, never written onto anybody’s record. See variables.
The same four per-call configuration fields every call-starting endpoint takes are also accepted here. One line each, in full on per-call configuration: agent_id / agent / agent_version / agent_override and agent_team are mutually exclusive: one agent, or a team of them.

The response

string
The media server this call runs on, chosen per call. Pass it to the browser SDK.
string
The join credential. It names one room — the room this call uses — so it is good for exactly one call and cannot be reused for the next one.
uuid
This call’s id, and the one GET /v1/calls/{session_id} answers to. Keep it if you want to read the transcript, cost or analysis back afterwards.
uuid
The conversation this call belongs to. Whether it is a new one or a continuation of the caller’s last is the agent’s conversation.context setting — see conversation memory.
string
Who the call is with: the key you sent, or the single-use one minted for you.
integer | null
The published version this call will run. Null when it runs an inline definition or a draft, neither of which has a version number.
string[]
Everything the resolved plan could not refuse but you should know about — an unreachable team member, a handoff into an agent that records when this one does not. The same shape publishing returns.

2. Join from the browser

livekit-client and @livekit/components-react come with it; React 18 or 19 is a peer dependency. The browser entrypoint is @talqing/sdk/browser. Point the browser’s client at your own server, not at the API:
The browser SDK calls exactly one endpoint, POST /v1/calls/token, so your proxy needs exactly one route: POST /talqing/v1/calls/token, which checks your own session and forwards the body to https://api.in.talqing.com/v1/calls/token with your personal access token in the Authorization header. Everything else in the API stays on your server.

A complete integration

session.start() publishes the microphone by default and buffers what the caller says before the agent has finished joining, so nothing said in the first second is lost. TalqingSessionProvider renders the room’s audio for you — do not add a second audio element, or the agent is heard twice.

The rules that matter

One session is one call. Start it when the component mounts and end it on the way out. To place a second call, mount a second session — give the component a key that changes per call, as above. Restarting a finished session rejoins the room the last call used, and the API will not let a second call in there; in practice you get a duplicate-stream-handler error from livekit-client before you get that far. Pass contact_key. It is your own id for the person on the call. Leave it out and every call mints its own key, so two calls from the same person arrive as two strangers — and an agent set to carry past conversations has nothing to carry. Keep the same value across calls and the whole history is one contact, readable from GET /v1/conversations?contact_key=…. Leave echo cancellation on. useTalqingSession builds the room with TALQING_AUDIO_CAPTURE_DEFAULTS — echo cancellation, noise suppression and auto gain control, all on. Without echo cancellation the agent hears its own speech through the caller’s microphone and interrupts itself, which sounds exactly like a bad model. You can override them with roomOptions.audioCaptureDefaults, but the object replaces all three rather than merging, so send all three if you send any. A video agent needs somewhere to render. channel: video puts an avatar on the call as a second participant; the caller publishes no camera. Find the track and render it:
Mount it inside TalqingSessionProvider. The avatar’s voice is the room’s audio like any other — never add a separate audio element for it. See video avatars.

When a call does not connect

The token request fails before the browser ever opens a socket, and its error says what to fix: Past that, the two failures worth instrumenting are both readable from the SDK:
  • The room connects and the agent never joins. useTalqingAgent().state goes to failed. The room being up is not the agent being there — a UI keyed off isConnected alone will say “live” to someone nobody is listening to. Wait for the state to leave connecting, pre-connect-buffering and initializing before you tell the caller to speak.
  • Audio is blocked. Browsers refuse to play audio on a page the person has not interacted with. Starting the call from a click, as above, is what avoids it.
Every call is readable afterwards whether or not it went well: GET /v1/calls/{session_id} returns the transcript, every tool call, the per-stage latency breakdown and the cost. See calls.

Next

Web call features

Images, screen share, userdata from the page, and the agent calling back into your UI.

Browser SDK reference

Every hook and component with its signature.

Per-call configuration

Pin a version, run the draft, override one field for one call.