Agent-readable docs index: /docs/llms.txt. Full docs in one file: /docs/llms-full.txt. Download /docs/docs.zip to grep all markdown files locally.

Browser SDK

@ruut/voice-sdk/browser provides a WebRTC softphone device that registers an agent extension over SIP/WSS and handles incoming and outgoing calls in the browser.

Install

npm install @ruut/voice-sdk

Create a device

Provision an extension and fetch its credentials from your server, then create a RuutDevice:
import { RuutDevice } from "@ruut/voice-sdk/browser"; const device = new RuutDevice({ credentials: { username: creds.username, password: creds.password, domain: creds.domain, wsUrl: creds.ws_url, }, autoPresence: false, // Keep the account Auth Token on your server. audioElement: document.querySelector("audio"), logLevel: "info", // "debug" to trace SIP traceSip: false, });
The server SDK’s agentExtensions.credentials() result also contains restAuthToken, restAccountSid, and restBaseUrl. Do not return the full object to a browser. Return only the SIP credentials and WebSocket URL to an authenticated user. Set autoPresence: false and update presence through your own authenticated server endpoint; the default auto-presence implementation requires REST credentials in the browser.

Device events

Subscribe to lifecycle events:
device.on("registered", () => setStatus("online")); device.on("unregistered", () => setStatus("offline")); device.on("stateChanged", (state, prev) => console.log(state, prev)); device.on("transportDisconnected", (err) => console.warn("WSS dropped", err)); device.on("error", (err) => console.error(err)); device.on("incoming", (call) => { // Show an Accept / Reject UI, then: call.accept(); // or call.reject(); }); device.on("callStarted", (call) => showCall(call)); device.on("callEnded", (call) => clearCall(call));

Register

await device.start(); // connects + registers await device.register(); // re-register await device.unregister(); // unregister (idle) await device.stop(); // teardown

Place an outbound call

const call = await device.connect("+2348000000001"); // E.164 number const call2 = await device.connect("agent-1001"); // extension const call3 = await device.connect("sip:trunk@pbx.example.com"); // SIP URI
During a call, use the returned RuutCall:
call.accept(); call.reject(); call.disconnect(); // hang up call.mute(); / call.unmute(); call.hold(); / call.unhold(); call.sendDigits("123#"); call.transfer("+2348000000003");

Accept an inbound call

device.on("incoming", async (call) => { const accepted = await call.accept(); if (accepted) console.log("Call connected"); });

Presence

Keep the device registered while the agent is available so inbound calls and ring groups reach them. Set the agent's presence server-side with client.agentExtensions.update(sid, { status: "online" }) so ring-group routing includes them.