VoiceDock Docs
SDKs

Node.js SDK

Official TypeScript/Node.js SDK for the HMS Sovereign Voice AI Platform with zero dependencies and full type safety.

Official TypeScript/Node.js SDK for the HMS Sovereign Voice AI Platform. Zero dependencies, full type safety, and support for all API endpoints.

Installation

npm install hmsovereign

Requires Node.js 20 or later.

Quick Start

import { HmsSovereign } from 'hmsovereign';

const client = new HmsSovereign({
  apiKey: 'fl_live_...',
});

// List all assistants
const assistants = await client.assistants.list();

// Create an assistant
const assistant = await client.assistants.create({
  name: 'Customer Support',
  first_message: 'Hello, how can I help you?',
  llm_config: {
    provider: 'openai',
    model: 'gpt-4o-mini',
    messages: [{ role: 'system', content: 'You are a friendly customer service agent.' }],
  },
  stt_config: {
    provider: 'deepgram',
    model: 'nova-3-general',
    language: 'en',
  },
  tts_config: {
    provider: 'elevenlabs',
    voice_id: 'ukiwGs47sHyibruHJ1vg',
  },
});

Resources

All resources are available as properties on the client:

ResourceDescription
client.assistantsCRUD for AI voice assistants
client.callsList calls, make outbound calls, call control
client.numbersPhone number management
client.campaignsOutbound call campaigns with leads
client.sipTrunksSIP trunk configuration
client.voicesList available TTS voices
client.usageUsage logs and billing
client.byokBring Your Own Key management
client.toolTemplatesReusable tool/function templates
client.analysisTemplatesPost-call analysis schemas
client.domainsCustom domain configuration
client.organizationsOrganization management

Outbound Calls

Three configuration modes for outbound calls:

Reference mode — use a saved assistant

const call = await client.calls.create({
  destination: '+31612345678',
  assistant_id: 'uuid-of-saved-assistant',
});

console.log(`Call started: ${call.call_id}`);

Transient mode — one-time assistant config

const call = await client.calls.create({
  destination: '+31612345678',
  assistant: {
    first_message: 'Hello John, this is a reminder about your appointment.',
    llm_config: { provider: 'openai', model: 'gpt-4o-mini' },
    stt_config: { provider: 'deepgram', model: 'nova-3-general', language: 'en' },
    tts_config: { provider: 'elevenlabs', voice_id: 'ukiwGs47sHyibruHJ1vg' },
  },
});

Hybrid mode — saved assistant with overrides

const call = await client.calls.create({
  destination: '+31612345678',
  assistant_id: 'uuid-of-saved-assistant',
  assistant_override: {
    first_message: 'Good afternoon John, I'm calling about your order.',
    metadata: { order_id: '12345', customer_tier: 'premium' },
  },
});

The metadata object is passed through to all webhook events at message.assistant.metadata.


Call Control

Control active calls in real-time:

// Inject context (invisible to caller, visible to LLM)
await client.calls.injectContext(callId, 'Customer is a VIP member', true);

// Make the assistant say something
await client.calls.say(callId, 'One moment please, let me look that up for you.');

// Transfer to a human agent
await client.calls.transfer(callId, '+31201234567', 'I'm transferring you to a colleague.');

// End the call
await client.calls.end(callId, 'Thank you for your call. Goodbye!');

Pagination

List endpoints return a Page with metadata:

// Single page
const page = await client.calls.list({ status: 'ended', limit: 50 });

console.log(page.data);         // Call[]
console.log(page.pagination);   // { total, limit, offset }
console.log(page.hasMore);      // boolean

Auto-pagination

Iterate through all results automatically with listAll():

for await (const call of client.calls.listAll({ status: 'ended' })) {
  console.log(call.id, call.duration_seconds);
}

// Or collect everything into an array
const allCalls = await client.calls.listAll({ status: 'ended' }).toArray();

Auto-pagination is available on client.calls.listAll() and client.usage.listAll().


Campaigns

Run automated outbound call campaigns:

// Create a campaign with leads
const campaign = await client.campaigns.create({
  name: 'Appointment Reminders',
  agent_id: assistant.id,
  system_message_template: 'Call {{name}} about the appointment on {{date}}',
  schedule_start_time: '09:00',
  schedule_end_time: '17:00',
  timezone: 'America/New_York',
  leads: [
    {
      phone_number: '+15551234567',
      name: 'John Smith',
      variables: { date: '2026-03-25', time: '14:00' },
    },
  ],
});

// Add more leads later
await client.campaigns.addLead(campaign.id, {
  phone_number: '+15559876543',
  name: 'Peter Johnson',
  variables: { date: '2026-03-26', time: '10:00' },
});

Webhook Verification

The SDK provides built-in webhook signature verification. See Webhook Security for background.

import { Webhooks } from 'hmsovereign';

// Express example — use raw body for signature verification
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  try {
    const event = Webhooks.verify({
      payload: req.body,
      signature: req.headers['x-webhook-signature'] as string,
      timestamp: req.headers['x-webhook-timestamp'] as string,
      secret: process.env.WEBHOOK_SECRET!,
    });

    switch (event.message.type) {
      case 'assistant-request':
        // Return dynamic config before call is answered
        res.json({ assistant: { first_message: 'Welcome!' } });
        break;

      case 'tool-calls':
        // Handle function calls from the assistant
        const toolCall = event.message.tool_call_list[0];
        res.json({ result: { status: 'ok' } });
        break;

      case 'status-update':
        // Call state: in-progress, ended, ended-with-error
        console.log(event.message.call.status);
        res.sendStatus(200);
        break;

      case 'end-of-call-report':
        // Post-call summary, transcript, analysis
        console.log(event.message.summary);
        res.sendStatus(200);
        break;

      default:
        res.sendStatus(200);
    }
  } catch (error) {
    res.status(400).send('Invalid signature');
  }
});

WarningRaw body required: You must use express.raw() (or equivalent) to get the raw request body. Parsed JSON bodies will fail signature verification because the signature is computed over the original string.


Error Handling

The SDK throws typed errors that you can catch with instanceof:

import {
  AuthenticationError,
  NotFoundError,
  RateLimitError,
  InsufficientCreditsError,
} from 'hmsovereign';

try {
  await client.assistants.get('non-existent-id');
} catch (error) {
  if (error instanceof NotFoundError) {
    console.log('Assistant not found');
  } else if (error instanceof AuthenticationError) {
    console.log('Invalid API key');
  } else if (error instanceof RateLimitError) {
    console.log(`Rate limited, retry after ${error.retryAfter}s`);
  } else if (error instanceof InsufficientCreditsError) {
    console.log('Top up your credits at app.hmsovereign.com');
  }
}

All errors extend HmsSovereignError and include status, message, and code properties.


Configuration

const client = new HmsSovereign({
  apiKey: 'fl_live_...',        // Required
  baseUrl: 'https://...',       // Default: https://api.hmsovereign.com/api/v1
  maxRetries: 2,                // Default: 2 (retries on 5xx and 429)
  timeout: 30_000,              // Default: 30s
  debug: true,                  // Default: false — logs requests and responses
});
OptionDefaultDescription
apiKeyYour HMS Sovereign API key (required)
baseUrlhttps://api.hmsovereign.com/api/v1API base URL
maxRetries2Automatic retries on 5xx and 429 responses
timeout30000Request timeout in milliseconds
debugfalseLog all HTTP requests and responses to console

The SDK automatically retries failed requests with exponential backoff. On 429 responses, it respects the Retry-After header.


TypeScript

The SDK is written in TypeScript and exports types for all resources. Import them directly:

import type {
  Assistant,
  Call,
  Campaign,
  Lead,
  PhoneNumber,
  SipTrunk,
  Voice,
  UsageRecord,
  WebhookPayload,
  SttConfig,
  LlmConfig,
  TtsConfig,
} from 'hmsovereign';

Source & Issues

On this page