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.

WebRTC softphone

Give every agent a business line in their browser. Provision extensions, register a SIP client, and accept or place calls — no desk phones, no installs.

How it works

  1. Each agent is assigned an agent extension on your carrier (e.g. agent-1001).
  2. The browser registers that extension over WebSocket (SIP over WSS) through the client gateway.
  3. Calls to the extension — or ring-group dials — arrive as SIP INVITEs straight to the browser.

Provision an extension

Create an agent extension and get its ephemeral SIP credentials:
import { RuutVoice } from "@ruut/voice-sdk"; const client = new RuutVoice({ accountSid, authToken, baseUrl }); // Create + fetch credentials in one call const creds = await client.agentExtensions.provision({ agentName: "Adaeze", }); console.log(creds.username, creds.password, creds.ws_url); // agent-1001 ******** wss://voice.ruut.chat:8443
Or create the extension first, then fetch credentials:
const ext = await client.agentExtensions.create({ agentName: "Adaeze" }); const creds = await client.agentExtensions.credentials(ext.sid);
Extensions can have an expiry when a TTL is configured. Check expires_at, re-fetch or rotate credentials as needed, and do not assume every extension has a default expiry.
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.

Register the browser device

Use the SDK's browser client (@ruut/voice-sdk/browser) to register and answer calls:
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"), }); device.on("registered", () => console.log("Ready to take calls")); device.on("incoming", (call) => { // Show an Answer button, then: call.accept(); }); device.on("callEnded", () => console.log("Call ended")); await device.start();

Ring groups

Assign the account's numbers to a ring group so every online, registered agent in the group rings simultaneously. The first to answer claims the call; the others are released. Agents must be marked online and registered to be dialed.

Dial an agent from the API

Route an inbound call (or an API-created call) to an agent extension using <Dial> with the agent's SIP URI:
<Response> <Dial>sip:agent-1001@sip.ruut.chat</Dial> </Response>
Or use the SDK helper:
await client.calls.createAgentCall({ agentUsername: "agent-1001", sipDomain: "sip.ruut.chat", from: "+2348000000002", twiml: new VoiceResponse().say("Connecting you to an agent.").toXml(), });

Presence & status

Update an agent's availability (which ring groups consider when dialing):
await client.agentExtensions.update("AE…", { status: "online", ttlSeconds: 3600 });
Statuses: online, offline, busy, away, dnd.