> ## Documentation Index
> Fetch the complete documentation index at: https://docs.rumik.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# register a call

> mint a single-use token so a browser never holds your api key.

`POST /v1/register-call` mints a call's id and exchanges your api key for a
short-lived token that starts exactly one call — a [realtime
socket](/realtime-agent) or a [web call](/web-call). the token is spent the
moment it is redeemed, so leaking one costs you a single call rather than an
account.

call it from your server, hand the token to the client, and let the client
connect. because the id comes back before anything runs, it is also the way to
know a call's id before the agent's before-call tools receive it as
`{call_id}` — see [knowing the call id first](/web-call#knowing-the-call-id-first).

## request

<ParamField body="agent_id" type="string" required>
  the agent to run — its UUID or its `ua_…` handle. `agentId` is accepted too.
</ParamField>

```bash curl theme={null}
curl -X POST https://silk-api.rumik.ai/v1/register-call \
  -H "Authorization: Bearer rk_live_•••••••••" \
  -H "Content-Type: application/json" \
  -d '{ "agent_id": "ua_fe3277d8" }'
```

## response

returns `201 Created`.

<ResponseField name="access_token" type="string">
  the single-use token, prefixed `wct_`. pass it as the `token` query parameter
  when opening the socket, or as `accessToken` to `POST /v1/webcall`.
</ResponseField>

<ResponseField name="expires_in" type="integer">
  how many seconds the token stays redeemable. it only has to survive the trip
  from your server to the client starting the call.
</ResponseField>

<ResponseField name="sample_rate" type="integer">
  the audio sample rate a realtime session will use, in Hz. a web call
  negotiates its own and ignores this.
</ResponseField>

<ResponseField name="call_id" type="string">
  the call's id, minted now so you hold it before anything runs. it is the same
  value `session.created` carries once a socket call is live and `callId` in a
  web call's response, what shows up in **conversations** and your usage, and
  what your tools receive as `{call_id}` — including the before-call tools,
  which run when the call starts, not now.
</ResponseField>

```json theme={null}
{
  "access_token": "wct_9f8c2b1e4d5a4e6fa7b8c9d0e1f2a3b4",
  "expires_in": 300,
  "sample_rate": 24000,
  "call_id": "01a05b4e-2c1d-7a3e-9f10-5b6c7d8e9f01"
}
```

## what it does not do

registering a call **does not start one**. nothing is billed, no capacity slot
is taken, no before-call tool runs and no agent is spawned until the token is
redeemed — the socket connects, or `/v1/webcall` is called with it — so a
token your user never redeems costs nothing and blocks nobody.

that also means a `429` cannot happen here. if you are out of capacity, you find
out at the start: the socket accepts, sends an `error` frame, and closes with
code `4000` (see [connection errors](/realtime-agent#connection-errors)); the
web call answers `429` — but unlike a one-hop start the token is already spent
by then, so retrying means registering again, under a new `call_id`.

## the agent must be deployed

registering checks that the agent has a live version and returns
`409 agent_not_deployed` if not. that check happens here rather than at the
socket on purpose: the token is single-use, so a caller refused *after*
redeeming one would have to come back for another.

## single use

```python theme={null}
token = register_call(agent)["access_token"]

open_socket(token)   # works
open_socket(token)   # 4401 — the token was already spent
start_web_call(token)   # 401 — same token, same answer
```

one token is one call, whichever surface starts it: a token spent on
`/v1/webcall` cannot open the socket, and vice versa.

a redeemed, expired or unknown token are indistinguishable from one another, on
purpose. mint a fresh token per call; they are cheap.

## example

<CodeGroup>
  ```python python theme={null}
  import requests

  API_KEY = "rk_live_•••••••••"
  BASE = "https://silk-api.rumik.ai"

  def register_call(agent: str) -> dict:
      r = requests.post(
          f"{BASE}/v1/register-call",
          headers={"Authorization": f"Bearer {API_KEY}"},
          json={"agent_id": agent},
          timeout=30,
      )
      r.raise_for_status()
      return r.json()      # {access_token, expires_in, sample_rate, call_id}
  ```

  ```javascript node theme={null}
  // Your endpoint: mint a token for the browser, keep the API key on the server.
  app.post("/api/agent-token", async (req, res) => {
    const upstream = await fetch("https://silk-api.rumik.ai/v1/register-call", {
      method: "POST",
      headers: {
        Authorization: `Bearer ${process.env.RUMIK_API_KEY}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ agent_id: "ua_fe3277d8" }),
    });
    res.status(upstream.status).json(await upstream.json());
  });
  ```
</CodeGroup>

next: [open the socket](/realtime-agent).
