Quickstart

Your first call in five steps

This page answers one question: how do I make the first thing work? One happy path: authenticate, create a room, place a real WebRTC call from the browser, and listen for events. Set BASE to your deployment (e.g. https://dev.somvad.com).

1 · Get access & a token

Request platform access at info@somvad.com. Then exchange credentials for a bearer token. The token's tenant_id selects which per-tenant profile you act as. Microsoft Entra (OIDC) tokens are accepted on the same endpoints when enabled.

curl

# public endpoint: returns a JWT
TOKEN=$(curl -s $BASE/auth/login -H 'content-type: application/json' \
  -d '{"email":"trader@bank.com","tenant_id":"<TENANT_ID>","password":"<pw>"}' \
  | jq -r .access_token)

curl -s $BASE/auth/me -H "Authorization: Bearer $TOKEN"
# -> {"user_id":"…","role":"member","tenant_id":"…"}

Every request below sends Authorization: Bearer $TOKEN unless marked public.

2 · Create a conference

A Conference is the platform's voice primitive: an ad-hoc call, a private call, a hoot, a line. Create one with visibility: "tenant" so anyone on the desk may see and join it.

curl

CID=$(curl -s $BASE/conferences -H "Authorization: Bearer $TOKEN" \
  -H 'content-type: application/json' \
  -d '{"name":"London Rates","visibility":"tenant"}' | jq -r .id)

3 · Ask where to connect

Audio never touches this API. The control plane assigns a media mixer and hands back its own wss:// endpoint and room. status:"spawning" means a mixer is autoscaling. Poll /join until "ready".

curl

curl -s -X POST $BASE/conferences/$CID/join -H "Authorization: Bearer $TOKEN"
# -> {"room":"7003","mixer_id":"mixer-1",
#     "ws_url":"wss://mixer-1.sip.<domain>","status":"ready"}

4 · Connect audio from the browser

Use the SDK. conferences.join gives you the placement; browser.config gives you a fresh per-call SIP credential plus ICE/TURN servers; connect() registers SIP-over-WSS against the assigned mixer and returns a Phone. AEC/echo constraints are applied for you, and call() rejects honestly on failure, no optimistic "connected".

typescript · @somvad/sdk-core

import { SomvadClient, connect } from '@somvad/sdk-core'

const client = new SomvadClient({ baseUrl: BASE, token })

const placement = await client.conferences.join(conferenceId)
const cfg       = await client.browser.config()
const phone     = await connect(cfg, placement.ws_url)

await phone.call(placement.room, document.querySelector('audio')!)
phone.setMuted(false)   // you're live

5 · Listen for realtime events

One WebSocket carries presence, chat, targeted signals (incoming calls, line state), and live captions. It replays missed frames on reconnect and re-delivers still-ringing calls on connect.

typescript · @somvad/sdk-core

import { SomvadEvents } from '@somvad/sdk-core'

const events = new SomvadEvents({ baseUrl: BASE, token }).connect()

events.on('signal', (s) => {
  if (s.event === 'incoming_call') ring(s)
})
events.on('presence', updateDirectory)
events.on('chat', appendMessage)

React in 40 lines

Prefer hooks?

@somvad/sdk-react wraps all of this behind one provider and a useCall() hook that runs join → placement → SIP/WebRTC → mute → hang-up → QoS report for you. See the SDK page.

Next steps