npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@veroai/voice

v0.1.1

Published

VeroAI Voice SDK - Build voice applications with webhooks, real-time call control, and WebRTC

Downloads

214

Readme

@veroai/voice

VeroAI Voice SDK - Build voice applications with webhooks and real-time call control.

Installation

npm install @veroai/voice

Quick Start

import { VoiceResponse, parseIncomingCall } from '@veroai/voice';

// Handle incoming call webhook
export async function POST(req: Request) {
  const body = await req.json();
  const call = parseIncomingCall(body);

  console.log(`Incoming call from ${call.from} to ${call.to}`);

  const response = new VoiceResponse()
    .say({ text: 'Welcome to Acme Corp!' })
    .gather({
      input: ['dtmf', 'speech'],
      numDigits: 1,
      timeout: 5,
      say: { text: 'Press 1 for sales, or 2 for support.' },
      actionHook: '/api/voice/menu'
    })
    .say({ text: "We didn't receive any input. Goodbye!" })
    .hangup();

  return Response.json(response.toJSON());
}

Voice Response Builder

The VoiceResponse class provides a fluent API for building call flows:

Speaking Text

// Simple
response.say('Hello, world!');

// With options
response.say({
  text: 'Welcome!',
  synthesizer: {
    vendor: 'elevenlabs',
    voice: 'rachel',
    language: 'en-US'
  },
  loop: 2
});

Playing Audio

response.play('https://example.com/welcome.mp3');

response.play({
  url: 'https://example.com/music.mp3',
  loop: 3,
  timeoutSecs: 30
});

Gathering Input

// Collect DTMF digits
response.gather({
  input: ['dtmf'],
  numDigits: 4,
  timeout: 10,
  say: { text: 'Please enter your PIN.' },
  actionHook: '/api/voice/verify-pin'
});

// Collect speech
response.gather({
  input: ['speech'],
  timeout: 5,
  say: { text: 'How can I help you today?' },
  recognizer: {
    vendor: 'deepgram',
    language: 'en-US',
    hints: ['sales', 'support', 'billing']
  },
  actionHook: '/api/voice/intent'
});

// Collect either
response.gather({
  input: ['dtmf', 'speech'],
  numDigits: 1,
  say: { text: 'Press 1 or say "sales" for sales.' },
  actionHook: '/api/voice/route'
});

Dialing

// Dial a phone number
response.dial({
  target: [{ type: 'phone', number: '+15551234567' }],
  callerId: '+15559876543',
  timeout: 30
});

// Dial a SIP endpoint
response.dial({
  target: [{ type: 'sip', sipUri: 'sip:[email protected]' }],
  timeout: 20
});

// Dial multiple targets (first to answer wins)
response.dial({
  target: [
    { type: 'phone', number: '+15551111111' },
    { type: 'phone', number: '+15552222222' }
  ],
  timeout: 30,
  dialMusic: 'https://example.com/hold-music.mp3'
});

Conference Calls

response.conference({
  name: 'team-standup',
  beep: true,
  maxParticipants: 10,
  statusHook: '/api/voice/conference-events'
});

Recording

// Start recording
response.record({
  action: 'start',
  stereo: true,
  recordingStatusHook: '/api/voice/recording-ready'
});

// Stop recording
response.record({ action: 'stop' });

Transcription

response.transcribe({
  enable: true,
  transcriptionHook: '/api/voice/transcription',
  recognizer: {
    vendor: 'deepgram',
    language: 'en-US'
  }
});

Other Verbs

// Pause
response.pause(2); // 2 seconds
response.pause({ length: 5 });

// Send DTMF
response.dtmf('1234#');

// Redirect to another webhook
response.redirect('/api/voice/other-handler');

// Hang up
response.hangup();

Webhook Parsers

Parse incoming webhook payloads with type safety:

import {
  parseIncomingCall,
  parseCallStatus,
  parseGatherResult,
  parseTranscription
} from '@veroai/voice';

// Incoming call
const call = parseIncomingCall(body);
console.log(call.from, call.to, call.callId);

// Call status update
const status = parseCallStatus(body);
console.log(status.status, status.duration);

// Gather result
const gather = parseGatherResult(body);
if (gather.digits) {
  console.log('DTMF:', gather.digits);
} else if (gather.speech) {
  console.log('Speech:', gather.speech.text);
}

// Transcription
const transcript = parseTranscription(body);
console.log(transcript.transcript, transcript.isFinal);

Signature Verification

Verify webhook signatures to ensure requests are authentic:

import { verifySignature, verifySignatureAsync } from '@veroai/voice';

// Node.js
const isValid = verifySignature(
  JSON.stringify(body),
  request.headers['x-veroai-signature'],
  process.env.WEBHOOK_SECRET
);

// Edge runtime (async)
const isValid = await verifySignatureAsync(
  JSON.stringify(body),
  request.headers.get('x-veroai-signature'),
  process.env.WEBHOOK_SECRET
);

TypeScript Types

All types are exported for use in your application:

import type {
  IncomingCallPayload,
  CallStatusPayload,
  GatherResultPayload,
  GatherOptions,
  DialOptions,
  Synthesizer,
  Recognizer
} from '@veroai/voice';

Supported TTS Vendors

  • google - Google Cloud Text-to-Speech
  • aws - Amazon Polly
  • azure - Microsoft Azure Speech
  • elevenlabs - ElevenLabs
  • deepgram - Deepgram Aura
  • wellsaid - WellSaid Labs

Supported STT Vendors

  • google - Google Cloud Speech-to-Text
  • aws - Amazon Transcribe
  • azure - Microsoft Azure Speech
  • deepgram - Deepgram
  • assembly - AssemblyAI

Examples

IVR Menu

import { VoiceResponse, parseIncomingCall, parseGatherResult } from '@veroai/voice';

// /api/voice/incoming
export async function handleIncoming(req: Request) {
  return new VoiceResponse()
    .say({ text: 'Welcome to Acme Corp!' })
    .gather({
      input: ['dtmf'],
      numDigits: 1,
      say: { text: 'Press 1 for sales, 2 for support, or 3 for billing.' },
      actionHook: '/api/voice/menu'
    })
    .say({ text: 'Goodbye!' })
    .hangup()
    .toJSON();
}

// /api/voice/menu
export async function handleMenu(req: Request) {
  const body = await req.json();
  const result = parseGatherResult(body);

  const response = new VoiceResponse();

  switch (result.digits) {
    case '1':
      response
        .say({ text: 'Connecting you to sales.' })
        .dial({ target: [{ type: 'phone', number: '+15551111111' }] });
      break;
    case '2':
      response
        .say({ text: 'Connecting you to support.' })
        .dial({ target: [{ type: 'phone', number: '+15552222222' }] });
      break;
    case '3':
      response
        .say({ text: 'Connecting you to billing.' })
        .dial({ target: [{ type: 'phone', number: '+15553333333' }] });
      break;
    default:
      response
        .say({ text: 'Invalid selection. Please try again.' })
        .redirect('/api/voice/incoming');
  }

  return response.toJSON();
}

Call Forwarding with Voicemail

import { VoiceResponse } from '@veroai/voice';

export async function handleCall(req: Request) {
  return new VoiceResponse()
    .dial({
      target: [{ type: 'phone', number: '+15551234567' }],
      timeout: 20,
      actionHook: '/api/voice/dial-result'
    })
    .toJSON();
}

export async function handleDialResult(req: Request) {
  const body = await req.json();

  // If no answer, go to voicemail
  if (body.dial_status !== 'completed') {
    return new VoiceResponse()
      .say({ text: 'Sorry, no one is available. Please leave a message after the beep.' })
      .record({
        action: 'start',
        recordingStatusHook: '/api/voice/voicemail-saved'
      })
      .pause(60) // Max 60 second message
      .hangup()
      .toJSON();
  }

  return new VoiceResponse().hangup().toJSON();
}

License

MIT