Skip to main content
POST /v1/webcall starts a call and returns the credentials a browser needs to join it. the media flows browser ↔ agent directly; it never touches your servers.
1

start the call on your server

your backend calls /v1/webcall with your api key and the agent to run.
2

pass the credentials to the page

send the host, token and roomName down to the browser. the token is short-lived and scoped to this one room.
3

join

the page connects with a livekit client and enables the microphone. the agent greets the caller as soon as it sees them join.
if a before-call tool of the agent needs to know the call’s id, start the call in two steps instead — see knowing the call id first.

request

exactly one of:
string
the agent to run — its UUID or its ua_… handle. agent_id is accepted too. needs your api key in Authorization. the call’s id is minted inside this request: the agent’s before-call tools run with it before you get it back.
string
the single-use wct_ token a register-call returned. it is the credential on its own — send no api key — and the call starts under the call_id that response already gave you. access_token is accepted too.

response

string
short-lived livekit access token. give it to the browser client; do not reuse it for a second call.
string
the livekit websocket URL to connect to.
string
the room that was created for this call.
string
the call’s id. it is what shows up in conversations and in your usage, so store it if you want to correlate a call with your own records later. your tools receive the same value as {call_id}. for a registered call it is the call_id you were already given.

knowing the call id first

a one-hop start does everything inside the request: it mints the call’s id, runs the agent’s before-call tools (which receive it as {call_id}), starts the agent, and only then answers. so if a before-call tool of yours is meant to look the call up by its id, that request reaches your endpoint before callId has reached you, and there is nothing yet to match it against. start such a call in two steps. register it first: that mints the id and starts nothing. record the id against your own session, then start the call with the token — the before-call tools run now, under an id you already hold.
1

register

POST /v1/register-call with your api key. store the call_id it returns next to whatever your tool will need when it is asked about it.
2

start

POST /v1/webcall with { "accessToken": "wct_…" } and no api key. this is where billing and the before-call tools happen; callId in the response equals the registered call_id.
3

join

as before: hand host, token and roomName to the page.
the token is single-use and expires in minutes, and it does not carry your key, so the page may run step 2 itself: register on your server, give the page the token, and let it call /v1/webcall directly.
any non-200 from step 2 spends the token — 429, 409 and 402 included. do not retry with the same token; it answers 401. recovery is a fresh /v1/register-call, which gives you a new call_id — discard the one you stored for the failed start.

joining from the browser

install a livekit client (npm i livekit-client, or the CDN build below) and connect with the host and token you were given.

ending a call

the call ends when the caller leaves the room — room.disconnect(), closing the tab, or losing the network. it also ends on its own when it reaches the agent’s maximum session length, or the length your balance can fund, whichever is shorter. you are billed for the seconds the call actually ran. the transcript and recording land in conversations shortly after it ends.

errors

see the error table. the ones you will meet in normal operation:
the accessToken is unknown, expired or already spent — the three are deliberately indistinguishable. register again; tokens are cheap.
the agent was saved but never deployed, so no version is live to answer. press deploy in the dashboard; nothing is started or billed until you do. a registered call’s token is spent by this answer: register again once the agent is deployed.
the account cannot fund a usable call. top up, or enable auto top-up in the dashboard so this does not interrupt live traffic. a registered call’s token is spent by this answer: register again after topping up.
every concurrent slot is in use. the body carries active_requests and limit. for a one-hop start, queue the caller and retry the same request when a slot frees, or raise your plan capacity. for a registered call the token is already spent: retry with a fresh /v1/register-call, under the new call_id it returns.