SDKs
JavaScript / TypeScript SDK
Full reference for the official Voisnap JS/TS SDK — installation, TypeScript types, async iterators, and error handling.
JavaScript / TypeScript SDK
The official Voisnap JavaScript/TypeScript SDK is fully typed and works in Node.js 18+, Deno, Bun, and edge runtimes (Cloudflare Workers, Vercel Edge).
Installation
npm install @voisnap/sdk
# or
yarn add @voisnap/sdk
# or
pnpm add @voisnap/sdk
Initialization
import { VoisnapClient } from '@voisnap/sdk';
// API key
const client = new VoisnapClient({ apiKey: 'vsnp_live_...' });
// JWT
const client = new VoisnapClient({ accessToken: 'eyJhbGci...' });
// Sandbox
const client = new VoisnapClient({
apiKey: 'vsnp_sb_...',
baseUrl: 'https://sandbox.api.voisnap.ai',
});
// From environment variable VOISNAP_API_KEY
const client = new VoisnapClient();
TypeScript types
All request and response types are exported:
import type {
Agent,
CreateAgentRequest,
UpdateAgentRequest,
Conversation,
ConversationTranscript,
OutboundCall,
CreateOutboundCallRequest,
TelephonyNumber,
KnowledgeBaseDocument,
WebhookConfig,
AgentStats,
PaginatedResponse,
} from '@voisnap/sdk';
Agents
Create an agent
import type { CreateAgentRequest } from '@voisnap/sdk';
const request: CreateAgentRequest = {
name: 'Aria – Support Agent',
persona: { name: 'Aria', personality: 'friendly, professional' },
voice: {
provider: 'elevenlabs',
voiceId: 'EXAVITQu4vr4xnSDxMaL',
stability: 0.5,
similarityBoost: 0.75,
},
llm: { provider: 'openai', model: 'gpt-4o', temperature: 0.7, maxTokens: 300 },
transcription: { provider: 'deepgram', model: 'nova-2', language: 'en-US' },
systemPromptTemplate: 'You are Aria, a friendly support agent...',
firstMessage: 'Hello! How can I help you today?',
firstMessageMode: 'assistant_speaks_first',
endCallPhrases: ['goodbye', 'thank you, bye'],
maxDurationSeconds: 600,
recording: { enabled: true, format: 'mp3', storageRetentionDays: 90 },
};
const agent = await client.agents.create(request);
console.log(`Created: ${agent.id}`);
List agents (async iterator)
// Iterate all pages
for await (const agent of client.agents.list({ status: 'active' })) {
console.log(`${agent.name} — ${agent.status}`);
}
// Collect to array
const agents = await client.agents.list({ status: 'active' }).toArray();
// First page only
const page = await client.agents.listPage({ page: 1, pageSize: 50 });
console.log(`${page.total} agents total`);
page.data.forEach(a => console.log(a.name));
Get, update, delete
// Get
const agent = await client.agents.get('agt_01HXK8Z3MNPQRS');
// Update
const updated = await client.agents.update('agt_01HXK8Z3MNPQRS', {
systemPromptTemplate: 'Updated prompt...',
llm: { temperature: 0.5 },
});
// Delete
await client.agents.delete('agt_01HXK8Z3MNPQRS');
Lifecycle
await client.agents.activate('agt_01HXK8Z3MNPQRS');
await client.agents.deactivate('agt_01HXK8Z3MNPQRS');
await client.agents.publish('agt_01HXK8Z3MNPQRS', { notes: 'Improved prompt' });
const copy = await client.agents.duplicate('agt_01HXK8Z3MNPQRS', {
name: 'Aria – Support Agent (Copy)',
});
Stats
const stats = await client.agents.stats('agt_01HXK8Z3MNPQRS', {
dateFrom: '2025-06-01',
dateTo: '2025-06-30',
});
console.log(`Conversations: ${stats.totalConversations}`);
console.log(`Avg duration: ${stats.avgDurationSeconds}s`);
Conversations
List (async iterator)
for await (const conv of client.conversations.list({
agentId: 'agt_01HXK8Z3MNPQRS',
channel: 'phone',
status: 'completed',
dateFrom: '2025-06-01',
dateTo: '2025-06-30',
})) {
console.log(`${conv.id}: ${conv.durationSeconds}s`);
}
Transcript
const transcript = await client.conversations.transcript('conv_01HXDEF456GHI');
for (const turn of transcript.turns) {
const icon = turn.speaker === 'agent' ? '🤖' : '👤';
console.log(`${icon} [${turn.startTime.toFixed(1)}s] ${turn.text}`);
}
Analysis
const analysis = await client.conversations.analysis('conv_01HXDEF456GHI');
console.log(analysis.summary);
console.log(`Sentiment: ${analysis.sentiment} (${analysis.sentimentScore})`);
Recording URL
const recording = await client.conversations.recording('conv_01HXDEF456GHI');
console.log(recording.url); // pre-signed URL valid 1 hour
Telephony
// Search available numbers
const available = await client.telephony.numbers.search({
country: 'US',
areaCode: '415',
capabilities: ['voice', 'sms'],
});
// Provision
const number = await client.telephony.numbers.provision({
phoneNumber: available[0].phoneNumber,
provider: 'twilio',
friendlyName: 'Main Support Line',
});
// Assign
await client.telephony.numbers.assign(number.id, 'agt_01HXK8Z3MNPQRS');
// List
for await (const num of client.telephony.numbers.list()) {
console.log(`${num.phoneNumber} → ${num.assignedAgentName ?? 'unassigned'}`);
}
// Release
await client.telephony.numbers.release(number.id);
Knowledge Base
// Upload
import { readFileSync } from 'fs';
const fileBuffer = readFileSync('./product-catalog.pdf');
const file = new File([fileBuffer], 'product-catalog.pdf', { type: 'application/pdf' });
const doc = await client.knowledgeBase.uploadDocument({
file,
name: 'Product Catalog Q2 2025',
agentIds: ['agt_01HXK8Z3MNPQRS'],
});
// Poll for completion
let status = await client.knowledgeBase.status(doc.id);
while (status.status === 'processing') {
await new Promise(r => setTimeout(r, 2000));
status = await client.knowledgeBase.status(doc.id);
}
console.log(`Indexed ${status.chunkCount} chunks`);
// Semantic search
const results = await client.knowledgeBase.search({
query: 'What is the return policy?',
documentIds: [doc.id],
topK: 5,
minScore: 0.7,
});
for (const match of results.matches) {
console.log(`${match.score.toFixed(3)}: ${match.excerpt.slice(0, 80)}...`);
}
Outbound Calls
// Immediate call
const call = await client.outboundCalls.create({
agentId: 'agt_01HXK8Z3MNPQRS',
toNumber: '+14155550199',
metadata: { customerId: 'cust_12345' },
overrideFirstMessage: 'Hi Jane, calling from Acme about your appointment.',
});
// Scheduled call
const scheduled = await client.outboundCalls.create({
agentId: 'agt_01HXK8Z3MNPQRS',
toNumber: '+14155550199',
scheduledFor: '2025-06-17T09:00:00Z',
maxRetries: 2,
retryDelayMinutes: 30,
});
// Cancel
await client.outboundCalls.cancel(scheduled.id);
// List
for await (const c of client.outboundCalls.list({ status: 'completed' })) {
console.log(`${c.toNumber}: ${c.status} (${c.durationSeconds}s)`);
}
Webhooks
// Create
const webhook = await client.webhooks.create({
agentId: 'agt_01HXK8Z3MNPQRS',
url: 'https://your-server.com/webhooks/voisnap',
events: ['SessionStarted', 'SessionEnded', 'AnalysisCompleted'],
secret: 'whsec_...',
});
// Verify signature (in your Express handler)
import { verifyWebhookSignature } from '@voisnap/sdk/webhooks';
app.post('/webhooks/voisnap', express.raw({ type: 'application/json' }), (req, res) => {
const event = verifyWebhookSignature({
payload: req.body,
signature: req.headers['x-webhook-signature'] as string,
timestamp: req.headers['x-webhook-timestamp'] as string,
secret: 'whsec_...',
});
if (!event) return res.status(401).send('Invalid signature');
switch (event.type) {
case 'SessionEnded':
console.log('Call ended:', event.data.conversationId);
break;
case 'AnalysisCompleted':
console.log('Analysis ready:', event.data.summary);
break;
}
res.status(200).send('OK');
});
Error handling
import {
VoisnapError,
AuthenticationError,
NotFoundError,
RateLimitError,
ValidationError,
} from '@voisnap/sdk';
try {
const agent = await client.agents.get('agt_does_not_exist');
} catch (err) {
if (err instanceof NotFoundError) {
console.error('Not found:', err.detail);
} else if (err instanceof AuthenticationError) {
console.error('Auth failed:', err.message);
} else if (err instanceof RateLimitError) {
console.error(`Rate limited. Retry after ${err.retryAfter}s`);
} else if (err instanceof ValidationError) {
for (const e of err.errors) {
console.error(` ${e.field}: ${e.message}`);
}
} else if (err instanceof VoisnapError) {
console.error(`API error ${err.status}: ${err.detail} (trace: ${err.traceId})`);
}
}
Configure retries
const client = new VoisnapClient({
apiKey: 'vsnp_live_...',
maxRetries: 3, // default: 3
timeout: 30_000, // ms, default: 30000
});
Edge runtime compatibility
The SDK uses the Fetch API and is compatible with edge runtimes. No Node.js-specific APIs are used:
// Cloudflare Workers
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const client = new VoisnapClient({ apiKey: env.VOISNAP_API_KEY });
const agent = await client.agents.get(env.AGENT_ID);
return new Response(JSON.stringify({ agentName: agent.name }));
},
};