Docs › Build
Realtime events
Every event your webhooks receive can also arrive over a WebSocket, the moment it commits — the low-latency channel UIs want. Webhooks stay the durable record; the stream is the refresh signal.
1. Mint a token from your backend
Your API key never reaches the browser. Your server mints a short-lived token (one hour) and hands it to the client:
# → { "token": "hsrt_…", "url": "wss://media.handset.dev/v1/events", "expires_at": … }
curl -X POST https://api.handset.dev/v1/realtime/tokens \
-H "Authorization: Bearer $HANDSET_API_KEY"import { mintRealtimeToken } from "@handset/sdk"; const grant = await mintRealtimeToken(); // grant.data → { token, url, expires_at }
from handset.api.events import mint_realtime_token grant = mint_realtime_token.sync(client=client) # grant.token, grant.url, grant.expires_at
Keys scoped to a tenant mint tenant-scoped tokens — the stream only ever carries that tenant's events.
2. Connect and listen
Each frame is the same envelope your webhook endpoints receive — one event catalog everywhere (see Webhooks):
const ws = new WebSocket(`${grant.url}?token=${grant.token}`); ws.onmessage = (msg) => { const event = JSON.parse(msg.data); // { id, type: "message.received", tenant_id, created_at, data } if (event.type === "call.transcript") render(event.data); };
Tokens expire after an hour and the socket closes — reconnect with a fresh mint. Delivery is best-effort by design: treat events as a signal to refetch, keep a slow poll as the safety net, and let webhooks remain the durable channel.
Zero-code option: Handset UI
If you use Handset UI, one prop does all of the above — token minting through your proxy, connection management, and instant hook refreshes:
<HandsetProvider baseUrl="/api/handset" realtime>
<App />
</HandsetProvider>What arrives
Everything in the event catalog:
message.received, message.delivered,
call.started, call.transcript (per utterance,
mid-call), call.summary, call.stream.*,
voicemail.created, and the rest. Account-scoped by your key,
tenant-filtered when the token is tenant-scoped.