Get started →
Documentation

TypeScript SDK

@ruut/voice-sdk is a typed, tested client for the Ruut Voice REST API, TwiML builder, and webhook verification. It runs in Node.js and browsers.

Install

npmbash

npm install @ruut/voice-sdk

Quickstart

Make a call with inline TwiMLts

import { RuutVoice, VoiceResponse } from "@ruut/voice-sdk";

const client = new RuutVoice({
  accountSid: process.env.RUUT_ACCOUNT_SID,
  authToken: process.env.RUUT_AUTH_TOKEN,
  baseUrl: "https://voice.ruut.chat",
  timeoutMs: 10_000,
  maxRetries: 2,
});

// Make a call with inline TwiML
const call = await client.calls.create({
  to: "+2348000000001",
  from: "+2348000000002",
  twiml: new VoiceResponse().say("Hello from Ruut Voice!").toXml(),
  statusCallback: "https://app.example.com/calls/status",
});

Client resources

ParameterTypeDescription
client.callsCreate, list, fetch, update, redirect, hold, resume, transfer, move to conference, waitFor.
client.messagesSend and list SMS messages.
client.recordingsList, fetch, and build media URLs (WAV/MP3) — including transcription fields.
client.incomingPhoneNumbersProvision, list, update, remove numbers.
client.availablePhoneNumbersSearch the number inventory.
client.agentExtensionsProvision extensions, get credentials, update presence.
client.twimlBuild TwiML with VoiceResponse.

Calls

Createts

// Create
await client.calls.create({ to, from, twiml | url, statusCallback });
await client.calls.createSipCall({ sipUri, from, url });
await client.calls.createAgentCall({ agentUsername, sipDomain, from, twiml });

// Read
await client.calls.list({ status, pageSize });
await client.calls.get("CA…");

// Control
await client.calls.redirect("CA…", { twiml });
await client.calls.hold("CA…", "https://hold-music.mp3");
await client.calls.resume("CA…", { url });
await client.calls.transfer("CA…", "+2348000000003", { callerId });
await client.calls.moveToConference("CA…", "support-room");

// Poll until a terminal state
const done = await client.calls.waitFor("CA…", {
  statuses: ["completed", "busy", "failed"],
  timeoutMs: 60_000,
});

Recordings & transcripts

Examplets

const recs = await client.recordings.list({ callSid: "CA…" });
const rec = await client.recordings.get("RE…");

console.log(rec.transcription_status);   // "completed"
console.log(rec.transcription_provider); // "whisperx"
for (const seg of rec.transcription_segments ?? []) {
  console.log(`${seg.speaker}: ${seg.text}`);
}

const wav = client.recordings.mediaUrl("RE…", { format: "wav" });
const mp3 = client.recordings.mediaUrl("RE…", { format: "mp3" });

Webhooks

Examplets

import {
  parseWebhook,
  isTerminalWebhook,
  isTranscriptionWebhook,
  parseTranscriptionSegments,
  validateWebhookSignature,
} from "@ruut/voice-sdk";

const valid = await validateWebhookSignature({
  url, params: req.body, signature: req.headers["x-twilio-signature"],
  authToken: process.env.RUUT_AUTH_TOKEN,
});
if (!valid) return res.status(403).end();

const payload = parseWebhook(req.body);
if (isTerminalWebhook(payload)) { /* call done */ }
if (isTranscriptionWebhook(payload)) {
  const segments = parseTranscriptionSegments(payload);
}

Error handling

Examplets

import { RuutApiError, RuutTimeoutError, RuutValidationError } from "@ruut/voice-sdk";

try {
  await client.calls.get("CA…");
} catch (err) {
  if (err instanceof RuutApiError) {
    console.error(`API ${err.status}: ${err.message} (${err.code}, request ${err.requestId})`);
  }
}

Next