@voice-ai-labs/web-sdk
v1.0.3
Published
Web SDK for Voice.ai - Easy integration of voice agents into JavaScript applications
Downloads
219
Readme
Voice.ai Web SDK
The official Voice.ai SDK for JavaScript/TypeScript applications.
Installation
npm install @voice-ai-labs/web-sdkQuick Start
import VoiceAI from '@voice-ai-labs/web-sdk';
// Initialize with your API key
const voiceai = new VoiceAI({ apiKey: 'vk_your_api_key' });
// Connect to a voice agent
await voiceai.connect({ agentId: 'your-agent-id' });
// Listen for transcriptions
voiceai.onTranscription((segment) => {
console.log(`${segment.role}: ${segment.text}`);
});
// Disconnect when done
await voiceai.disconnect();Features
The SDK provides a unified interface for:
- Real-time Voice — Connect to voice agents with live transcription
- Text-to-Speech — Generate speech and manage voices
- Agent Management — Create, update, deploy, and manage agents
- Managed Tools — Connect first-party managed integrations such as Google Calendar, Sheets, and Gmail
- Knowledge Base — Manage RAG documents for your agents
- Phone Numbers — Search and manage phone numbers
- Analytics — Access call history, transcripts, and recordings
- Webhooks — Receive real-time notifications for call events
- Security — Backend token exchange, endToken, CORS
- Error Handling — Connection and API error handling
Real-time Voice
Connect to an Agent
await voiceai.connect({
agentId: 'agent-123',
autoPublishMic: true // default: true
});
// Test mode: preview paused agents before deploying
await voiceai.connect({ agentId: 'agent-123', testMode: true });connect() supports these top-level request shapes:
agentIdfor a saved agentdynamicVariablesfor optional runtime variables passed at call startagentOverridesfor optional call-scoped runtime config overridestestModeto preview paused agents before deploying
Events
// Transcriptions (user and agent speech)
voiceai.onTranscription((segment) => {
console.log(`${segment.role}: ${segment.text}`);
console.log('Final:', segment.isFinal);
});
// Connection status
voiceai.onStatusChange((status) => {
if (status.connected) console.log('Connected!');
if (status.error) console.error('Error:', status.error);
});
// Agent state (listening, speaking, thinking)
voiceai.onAgentStateChange((state) => {
console.log('Agent is:', state.state);
});
// Audio levels (for visualizations)
voiceai.onAudioLevel((level) => {
console.log('Level:', level.level, 'Speaking:', level.isSpeaking);
});
// Errors
voiceai.onError((error) => {
console.error('Error:', error.message);
});Each handler returns a function to unsubscribe: const stop = voiceai.onTranscription(...); stop();
Microphone Control
await voiceai.setMicrophoneEnabled(true); // Enable
await voiceai.setMicrophoneEnabled(false); // DisableSend Text Message
await voiceai.sendMessage('Hello agent!');Disconnect
await voiceai.disconnect();Status (read-only)
voiceai.isConnected();
voiceai.getStatus(); // { connected, connecting, callId, error }
voiceai.getAgentState(); // { state, agentParticipantId }
voiceai.getMicrophoneState(); // { enabled, muted }Text-to-Speech
The TTS API provides speech generation and voice management.
Generate Speech
// Non-streaming: returns complete audio as Blob
const audio = await voiceai.tts.synthesize({
text: 'Hello, welcome to Voice AI!',
voice_id: 'voice-123',
language: 'en',
audio_format: 'mp3',
});
const url = URL.createObjectURL(audio);
new Audio(url).play();
// Streaming: returns Response with readable body
const response = await voiceai.tts.synthesizeStream({
text: 'Hello, welcome!',
voice_id: 'voice-123',
language: 'en',
});
const reader = response.body!.getReader();
// Read chunks: reader.read()Managed pronunciation dictionaries can be attached to direct TTS requests and saved agent configs with:
const audio = await voiceai.tts.synthesize({
text: 'Schedule a follow-up for Thailand.',
voice_id: 'voice-123',
language: 'en',
dictionary_id: 'dict-123',
dictionary_version: 2,
});Voice Management
// List all available voices
const voices = await voiceai.tts.listVoices();
// Clone a voice from audio file (MP3/WAV/M4A, max 7.5MB)
const voice = await voiceai.tts.cloneVoice({
file: audioFile,
name: 'My Voice',
language: 'en',
voice_visibility: 'PRIVATE',
});
// Get voice status (PENDING -> PROCESSING -> AVAILABLE)
await voiceai.tts.getVoice(voice.voice_id);
// Update voice metadata
await voiceai.tts.updateVoice('voice-123', { name: 'Renamed', voice_visibility: 'PUBLIC' });
// Delete voice
await voiceai.tts.deleteVoice('voice-123');Pronunciation Dictionaries
// List dictionaries
const dictionaries = await voiceai.tts.listPronunciationDictionaries();
// Get one dictionary
const dictionary = await voiceai.tts.getPronunciationDictionary('dict-123');
// Create from rules
const created = await voiceai.tts.createPronunciationDictionaryFromRules({
name: 'Medical Terms',
language: 'en',
rules: [
{ word: 'Thailand', replacement: 'tie-land' },
{ word: 'router', replacement: 'row-ter', ipa: 'ˈraʊtɚ', case_sensitive: false },
],
});
// Create from a .pls file
await voiceai.tts.createPronunciationDictionaryFromFile({
file: dictionaryFile,
name: 'Imported Dictionary',
language: 'en',
});
// Rename
await voiceai.tts.updatePronunciationDictionary('dict-123', { name: 'Medical Terms v2' });
// Replace all rules
await voiceai.tts.setPronunciationDictionaryRules('dict-123', [
{ word: 'SQL', replacement: 'sequel', case_sensitive: false },
]);
// Add rules
await voiceai.tts.addPronunciationDictionaryRules('dict-123', [
{ word: 'gif', replacement: 'jif', case_sensitive: false },
]);
// Remove rules by stable rule ID
await voiceai.tts.removePronunciationDictionaryRules('dict-123', ['rule-1', 'rule-2']);
// Download a specific version as a Blob
const plsBlob = await voiceai.tts.downloadPronunciationDictionaryVersion('dict-123', 3);
// Delete
await voiceai.tts.deletePronunciationDictionary('dict-123');Agent Management
// List agents
const agents = await voiceai.agents.list();
// Create an agent
const agent = await voiceai.agents.create({
name: 'Customer Support',
config: {
prompt: 'You are a helpful customer support agent.',
greeting: 'Hello! How can I help you today?',
recording_enabled: true,
tts_params: {
voice_id: 'my-voice-id',
model: 'voiceai-tts-v1-latest',
language: 'en'
}
}
});
// Deploy the agent
await voiceai.agents.deploy(agent.agent_id);
// Update an agent
await voiceai.agents.update(agent.agent_id, {
name: 'Updated Name'
});
// Pause an agent
await voiceai.agents.pause(agent.agent_id);
// Delete an agent
await voiceai.agents.disable(agent.agent_id);
// Create an outbound call (server-side only)
// NOTE: Outbound is restricted to approved accounts.
// If your account is not approved, this endpoint may return 403.
await voiceai.agents.createOutboundCall({
agent_id: agent.agent_id,
target_phone_number: '+15551234567',
dynamic_variables: { case_id: 'abc-1' },
agent_overrides: {
tts_params: {
voice_id: 'voice_priority_customer',
dictionary_id: 'dict-123',
dictionary_version: 2,
},
},
});Managed Tools
The managed tools surface is generic. Today it covers Google Calendar, Google Sheets, and Gmail.
Managed tools are exposed under voiceai.managedTools.
Today the SDK includes one Google entry:
voiceai.managedTools.google- Use it to start OAuth, check status, and disconnect Google managed tools for an agent
- Pass the individual managed tool configs under
managedTools.google_calendar,managedTools.google_sheets, andmanagedTools.google_gmail
Use the managed Google surface to connect an agent to Google Calendar, Sheets, or Gmail.
For a working browser example, see demo/managed-tools.html.
import VoiceAI, {
GOOGLE_CALENDAR_OPERATION_OPTIONS,
IANA_TIMEZONE_OPTIONS,
getGoogleReconnectState,
hasEnabledGoogleManagedTools,
} from '@voice-ai-labs/web-sdk';
const voiceai = new VoiceAI({ apiKey: 'vk_your_api_key' });
const start = await voiceai.managedTools.google.startOAuth('agent-123', {
returnUrl: window.location.href,
managedTools: {
google_calendar: {
enabled: true,
timezone: 'America/Los_Angeles',
selected_operations: ['google_calendar_check_availability', 'google_calendar_create_event'],
},
},
});
window.open(start.auth_url, 'google-oauth', 'popup,width=540,height=720');
const status = await voiceai.managedTools.google.getStatus('agent-123');
const reconnect = getGoogleReconnectState(
{
google_calendar: {
enabled: true,
selected_operations: ['google_calendar_check_availability', 'google_calendar_create_event'],
},
},
status
);Connection flow:
- Call
startOAuth(...)with the agent ID,returnUrl, and the currently enabled Google managed tool config for the agent. - Open the returned
auth_urlin a popup or browser tab. - Google redirects to the VoiceAI backend callback.
- The backend completes OAuth and then returns the user to your
returnUrl. - Refresh or poll
voiceai.managedTools.google.getStatus(agentId)to confirm the connection state.
Connection semantics:
startOAuth(...)manages Google managed-tools access for the agent- the Google connection is shared across Calendar, Sheets, and Gmail for that agent
- enabling more Google operations later can require reconnecting to grant access for the currently enabled Google tools
disconnect(...)removes Google managed-tools access for all Google tools on that agent
Available helpers:
voiceai.managedTools.google.startOAuth(agentId, { returnUrl, managedTools })voiceai.managedTools.google.getStatus(agentId)voiceai.managedTools.google.disconnect(agentId)GOOGLE_CALENDAR_OPERATION_OPTIONS,GOOGLE_SHEETS_OPERATION_OPTIONS,GOOGLE_GMAIL_OPERATION_OPTIONSgetManagedToolSelectedOperations(...),toggleManagedToolOperation(...)getRequiredGoogleScopes(...),getGoogleReconnectState(...),hasEnabledGoogleManagedTools(...)IANA_TIMEZONE_OPTIONSfor timezone selectors. Each option includes{ value, label, offsetMinutes }, wherevalueis the canonical IANA timezone likeAmerica/Los_Angeles
Managed tool config fields:
google_calendarenabled: booleandefault_calendar_id?: stringtimezone?: stringselected_operations?: GoogleCalendarOperation[]
google_sheetsenabled: booleanspreadsheet_id?: stringsheet_name?: stringselected_operations?: GoogleSheetsOperation[]
google_gmailenabled: booleanselected_operations?: GoogleGmailOperation[]
Supported Calendar operations:
google_calendar_check_availability— Check whether a calendar is free during a time windowgoogle_calendar_list_upcoming_events— Read the next upcoming events from the calendargoogle_calendar_create_event— Create a new calendar eventgoogle_calendar_update_event— Modify an existing calendar eventgoogle_calendar_cancel_event— Cancel or delete an existing calendar event
Supported Sheets operations:
google_sheets_append_row— Write a new row into a spreadsheetgoogle_sheets_list_sheets— List worksheet tabs and spreadsheet metadatagoogle_sheets_read_rows— Read rows from a worksheet range
Supported Gmail operations:
google_gmail_search_messages— Search Gmail and return readable message summariesgoogle_gmail_get_message— Fetch a specific Gmail message by IDgoogle_gmail_send_email— Send an email from the connected Gmail account
Notes:
- Google Calendar, Sheets, and Gmail all use the
voiceai.managedTools.googlesurface. startOAuth(...)uses the Google managed tool config you pass inmanagedToolsto determine the scopes requested for the shared agent-level Google connection.- If you enable additional Google operations later,
getStatus()/getGoogleReconnectState(...)may reportreconnect_requireduntil you reconnect and grant access for the currently enabled Google tools. voiceai.managedTools.google.disconnect(agentId)removes Google managed-tools access for the agent.returnUrlis your app/frontend return target after the VoiceAI backend callback completes. It is not the Google-registered OAuth redirect URI.- Calendar
timezoneshould be an IANA timezone likeAmerica/Los_Angeles - If
selected_operationsis omitted, the SDK helpers treat that managed tool config as “all supported operations selected” - If
selected_operationsis an empty array, the managed tool config remains present but requests no additional provider scopes
Outbound access control:
POST /api/v1/calls/outboundis restricted to approved accounts. If you need outbound enabled for your account/workspace, please contact Voice.ai support.
Update behavior:
voiceai.agents.update()is a partial update. Omit a field to leave it unchanged. For nullable scalar fields likeprompt,greeting,phone_number, or nestedtts_paramsfields, passnullto clear the current value. See section-specific notes below for webhook clearing behavior.
Recording:
config.recording_enableddefaults totruefor new agents. Set it tofalseto disable recording for future calls.
Dynamic Variables
Pass optional dynamic_variables at call start and reference them in your prompt or greeting with {{variable_name}}:
await voiceai.agents.update(agent.agent_id, {
config: {
allow_outbound_calling: true,
prompt: 'You are helping {{customer_name}} with order {{order_id}} for the {{account_tier}} account.',
greeting: 'Hi {{customer_name}}, I can help with your {{city}} delivery today.'
}
});
await voiceai.connect({
agentId: agent.agent_id,
dynamicVariables: {
customer_name: 'Alice',
order_id: '12345',
account_tier: 'gold',
city: 'Seattle'
}
});dynamic_variablesmust be a flat object of string, number, or boolean values.- Extra variables are allowed.
- Variables that are not referenced by the runtime prompt or greeting are ignored.
- The runtime is responsible for interpolating these variables into the prompt and greeting.
- If the same placeholder appears multiple times, the same runtime value is used for every occurrence.
Runtime Agent Overrides
Pass optional agentOverrides at call start when you need a call-scoped config patch rather than prompt interpolation:
await voiceai.connect({
agentId: agent.agent_id,
dynamicVariables: {
customer_name: 'Alice',
},
agentOverrides: {
tts_params: {
voice_id: 'voice_vip_alice',
temperature: 0.8,
},
},
});agentOverridesis separate fromdynamicVariables.dynamicVariablesis for prompt and greeting interpolation.agentOverridesis for allowlisted runtime config changes.- v1 supports only
tts_params.voice_id,temperature,top_p,dictionary_id, anddictionary_version. agentOverridesuses the same nested shape as agent config, so voice overrides live undertts_params.
Knowledge Base
// Create a knowledge base
const kb = await voiceai.knowledgeBase.create({
name: 'Product FAQ',
documents: [
{ content: 'Return policy: 30 days for full refund.' },
{ content: 'Shipping: Free on orders over $50.' }
]
});
// Assign to an agent
await voiceai.agents.assignKnowledgeBase(agentId, kb.kb_id);
// List knowledge bases
const kbs = await voiceai.knowledgeBase.list();
// Update a knowledge base
await voiceai.knowledgeBase.update(kb.kb_id, {
documents: [{ content: 'Updated content' }]
});
// Delete a knowledge base
await voiceai.knowledgeBase.remove(kb.kb_id);Phone Numbers
// Search available numbers
const numbers = await voiceai.phoneNumbers.search({
country_code: 'US',
area_code: '415'
});
// Select a number
await voiceai.phoneNumbers.select('+14155551234');
// List your numbers
const myNumbers = await voiceai.phoneNumbers.list();
// Release a number
await voiceai.phoneNumbers.release('+14155551234');Analytics
// Get call history
const history = await voiceai.analytics.getCallHistory({
page: 1,
limit: 20,
agent_ids: ['agent-123'],
agent_name: 'support',
sort_by: 'duration',
sort_dir: 'desc'
});
// Get transcript URL
const transcript = await voiceai.analytics.getTranscriptUrl(callId);
// Get recording status or URL
const recording = await voiceai.analytics.getRecordingUrl(callId);
if (recording.status === 'ready' && recording.url) {
window.open(recording.url, '_blank');
}
// Get stats summary
const stats = await voiceai.analytics.getStatsSummary();Webhooks
Configure webhooks when creating or updating an agent.
webhooks.events[], webhooks.inbound_call, and webhooks.tools use different contracts:
webhooks.events[]supportssecret(write-only on create/update) andhas_secret(read-only on fetch), with fan-out across enabled endpoints.webhooks.inbound_callsupportssecret(write-only on create/update) andhas_secret(read-only on fetch).webhooks.toolsdefine outbound API calls and do not usesecret.
Configure Webhook Events and Tools
// Create agent with webhook events and tools
const agent = await voiceai.agents.create({
name: 'Support Agent',
config: {
prompt: 'You are a helpful support agent.',
webhooks: {
events: [
{
url: 'https://your-server.com/webhooks/voice-events',
secret: 'your-hmac-secret', // Event webhook signing secret
events: ['call.started', 'call.completed'], // Or omit for all events
timeout: 5,
enabled: true
}
],
inbound_call: {
url: 'https://your-server.com/webhooks/inbound-call',
secret: 'your-inbound-call-secret', // Inbound call webhook signing secret
timeout: 5,
enabled: true
},
tools: [
{
name: 'get_account_status',
description: 'Fetches current account status for a customer.',
url: 'https://your-server.com/webhooks/tools/account-status',
parameters: {
customer_id: 'string'
},
method: 'POST',
execution_mode: 'sync',
auth_type: 'api_key',
auth_token: 'your-api-key',
headers: {
'X-Service-Version': '2026-02'
},
response: {
type: 'object',
properties: {
status: { type: 'string' },
tier: { type: 'string' }
}
},
timeout: 10
}
]
}
}
});
// Update webhook config on existing agent
await voiceai.agents.update(agentId, {
config: {
webhooks: {
events: [
{
url: 'https://your-server.com/webhooks',
events: ['call.completed'], // Only receive call.completed
enabled: true
}
],
tools: [
{
name: 'search_knowledge_base',
description: 'Searches KB and returns ranked snippets.',
url: 'https://your-server.com/webhooks/tools/search-kb',
parameters: {
query: 'string',
top_k: 'number'
},
method: 'GET',
execution_mode: 'async',
auth_type: 'custom_headers',
headers: {
'X-Internal-Token': 'your-internal-token'
},
timeout: 20
}
]
}
}
});Webhook configuration requiredness
webhooks.events[]- Required per endpoint:
url - Optional per endpoint:
secret,events,timeout(default5),enabled(defaulttrue) - On update: omit
webhooks.eventsto preserve the current list, setwebhooks.events: nullto remove it, or pass a full array to replace the list - When replacing the array: omitted
secretvalues are preserved only for entries whoseurlexactly matches an existing endpoint,secret: nullclears the signing secret for that endpoint, and duplicate URLs are invalid - Use
events: []on an endpoint to receive all event types
- Required per endpoint:
webhooks.inbound_call- Required:
url - Optional:
secret,timeout(default5),enabled(defaulttrue) - On update: omit
inbound_callto preserve it, setinbound_call: nullto remove it, and setsecret: nullto clear only the signing secret
- Required:
webhooks.tools- Required per tool:
name,description,parameters,url,method,execution_mode,auth_type - Optional per tool:
auth_token,headers,response,timeout(default10) - On update: omit
toolsto leave the current tool list unchanged, settools: nullto clear all tools, or pass a new array to replace the current list
- Required per tool:
If a field is optional and omitted, the service uses the documented default. Prefer omitting optional fields instead of sending null unless you explicitly intend to clear behavior in a supported way.
Event Types
| Event | Description |
|-------|-------------|
| call.started | Call connected, agent ready |
| call.completed | Call ended, includes transcript and usage data |
Event Webhook Payload
Your event webhook URL receives POST requests with this structure:
interface WebhookEvent {
event: 'call.started' | 'call.completed' | 'test';
timestamp: string; // ISO 8601
call_id: string;
agent_id: string;
data: {
call_type: 'web' | 'sip_inbound' | 'sip_outbound';
// call.started: started_at, from_number?, to_number?
// call.completed: duration_seconds, credits_used, transcript_uri, transcript_summary
};
}Webhook Tool Request Shape
For webhook tools, Voice.ai makes outbound HTTP requests directly to each tool url.
method: 'GET' | 'DELETE': tool arguments are sent as query parameters.method: 'POST' | 'PUT' | 'PATCH': tool arguments are sent as JSON body.- For body methods, Voice.ai always sends
Content-Type: application/json. - If you configure a
Content-Typeheader inheaders, it is ignored for webhook tools. - Metadata headers are always sent:
X-VoiceAI-Request-IdX-VoiceAI-Tool-NameX-VoiceAI-Agent-IdX-VoiceAI-Call-Id
GET /webhooks/tools/search-kb?query=refund+policy&top_k=3
X-VoiceAI-Request-Id: req_123
X-VoiceAI-Tool-Name: search_knowledge_base
X-VoiceAI-Agent-Id: agent_123
X-VoiceAI-Call-Id: call_123POST /webhooks/tools/account-status
Content-Type: application/json
X-VoiceAI-Request-Id: req_456
X-VoiceAI-Tool-Name: get_account_status
X-VoiceAI-Agent-Id: agent_123
X-VoiceAI-Call-Id: call_123
{"customer_id":"cust_789"}Webhook Tool Authentication
auth_type: 'none': no auth headers added.auth_type: 'bearer_token': sendsAuthorization: Bearer <auth_token>.auth_type: 'api_key': sendsX-API-Key: <auth_token>.auth_type: 'custom_headers': sends your configuredheadersmap, exceptContent-Type, which is agent-managed for body methods.
Webhook Tool Response Behavior
execution_mode: 'sync': waits for downstream response body; non-2xx fails the tool call.execution_mode: 'async': treats any 2xx as accepted and does not require a response payload.
Signature Verification (Event Webhooks)
If you configure webhooks.events[].secret, verify the HMAC-SHA256 signature:
import crypto from 'crypto';
function verifyEventWebhook(body: string, headers: Headers, secret: string): boolean {
const signature = headers.get('x-webhook-signature');
const timestamp = headers.get('x-webhook-timestamp');
if (!signature || !timestamp) return false;
const message = `${timestamp}.${body}`;
const expected = crypto.createHmac('sha256', secret).update(message).digest('hex');
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}Inbound Call Webhook Payload
If you configure webhooks.inbound_call, Voice.ai sends inbound call personalization requests with this shape:
interface InboundCallWebhookRequest {
agent_id: string;
call_id: string;
from_number: string;
to_number: string;
}Your endpoint should respond with:
interface InboundCallWebhookResponse {
dynamic_variables?: Record<string, string | number | boolean>;
agent_overrides?: {
tts_params?: {
voice_id?: string;
temperature?: number;
top_p?: number;
dictionary_id?: string;
dictionary_version?: number;
};
};
}If you configure webhooks.inbound_call.secret, verify the HMAC-SHA256 signature using the same
X-Webhook-Timestamp and X-Webhook-Signature headers shown above for event webhooks.
Security
connect() fetches connection details and connects in one call. To keep your API key off the browser, split into two steps:
// Step 1: Backend — get connection details (requires API key)
const details = await voiceai.getConnectionDetails({ agentId: 'agent-123' });
// Returns: { serverUrl, participantToken, callId, endToken }
// Step 2: Frontend — connect with pre-fetched details (no API key needed)
const voiceai = new VoiceAI();
await voiceai.connectRoom(details);Important: Pass endToken from your backend to the frontend. The SDK uses it on disconnect() to free the concurrency slot immediately.
REST methods (agents.*, tts.*, analytics.*, etc.) require an API key and are CORS-blocked from browsers.
Error Handling
Connection errors
The connect() method throws an Error if connection fails. Common error cases:
try {
await voiceai.connect({ agentId: 'agent-123' });
} catch (error) {
if (error.message.includes('insufficient_credits')) {
console.error('Out of credits. Please add more credits to continue.');
} else if (error.message.includes('Authentication failed')) {
console.error('Invalid API key');
} else if (error.message.includes('agent_not_deployed')) {
console.error('Agent is not deployed');
} else {
console.error('Connection failed:', error.message);
}
}Errors are also emitted via onError and reflected in onStatusChange:
voiceai.onError((error) => {
console.error('Error:', error.message);
});
voiceai.onStatusChange((status) => {
if (status.error) {
console.error('Connection error:', status.error);
}
});REST API errors (agents, TTS, analytics, etc.)
REST methods throw VoiceAIError:
import { VoiceAIError } from '@voice-ai-labs/web-sdk';
try {
const agent = await voiceai.agents.getById('nonexistent');
} catch (error) {
if (error instanceof VoiceAIError) {
// error.message, error.status (401, 403, 404, 422), error.code, error.detail
if (error.status === 404) console.error('Agent not found');
}
}
try {
const audio = await voiceai.tts.synthesize({ text: '...', voice_id: 'voice-123' });
} catch (error) {
if (error instanceof VoiceAIError) {
// error.status: 400 (validation), 401 (auth), 404 (voice not found), 422 (invalid request)
if (error.status === 404) console.error('Voice not found');
}
}TypeScript
Full TypeScript support. Exported types:
import VoiceAI, { VoiceAIError } from '@voice-ai-labs/web-sdk';
import type {
VoiceAIConfig,
ConnectionOptions,
ConnectionDetails,
ConnectionStatus,
TranscriptionSegment,
AgentState,
AgentStateInfo,
AudioLevelInfo,
MicrophoneState,
Agent,
VoiceResponse,
VoiceStatus,
VoiceAgentWidgetOptions,
VoiceAgentWidgetTheme,
} from '@voice-ai-labs/web-sdk';Browser Support
Chrome, Firefox, Safari (latest versions). Requires microphone permission for voice features.
License
MIT
