Zernio
Zernio
PlatformsVoice & CallsSetupAI Voice Agents
Integrations
ElevenLabsRetell
Outbound CallsBrowser CallingCall History & Recordings
Dashboard
llms.txtOpenAPI
OverviewPlatformsAPI ReferenceResources
Voice & Calls

AI Voice Agents

Answer a number's calls with an AI voice agent: a Vapi agent over a sip: address, or your own media server over wss://.


When you finish this page inbound calls to a number are answered by an AI voice agent. You need a voice-enabled number and an agent to hand the calls to. An agent is a forward destination like any other, in one of 2 shapes: a hosted platform such as Vapi takes a sip: address, and a server of your own takes a wss:// URL that the call's live, bidirectional audio streams over.

Retell and ElevenLabs are sip: destinations with guides of their own: Retell and ElevenLabs.

Step 1: Point the number at the agent

Call POST /v1/phone-numbers/{id}/voice with forwardTo set to the agent's address. This sample uses a wss:// media server of your own; a sip: address goes in the same field.

import Zernio from '@zernio/node';

const zernio = new Zernio();
const phoneNumberId = '66d4e5f6a7b8c9d0e1f2a3b4';

const { data: voice } = await zernio.voice.enableVoiceOnNumber({
  path: { id: phoneNumberId },
  body: { forwardTo: 'wss://your-agent.example.com/media' }
});
console.log(voice.pstnForwardTo);

Response (200):

{
  "enabled": true,
  "phoneNumber": "+14155550100",
  "pstnForwardTo": "wss://your-agent.example.com/media",
  "recordingEnabled": false,
  "transcriptionEnabled": false,
  "voicemailEnabled": true
}

How the bridge works

  1. Your agent exposes a WebSocket endpoint that streams call audio in both directions, or a SIP address that accepts the call.
  2. On an inbound call, Zernio answers and bridges the audio to that destination; the agent speaks back over the same connection. To the caller it is one continuous call.
  3. There is no second phone leg either way, so you pay only the inbound leg.

If the stream cannot be established (a bad URL, a failed handshake), the already-answered caller falls to voicemail when it is enabled, and the call ends otherwise.

The same wss:// destination works as a per-call forwardTo override on outbound calls, so you can hand one outbound call to an agent without changing the number's default. Turn on recording or transcription on the number when you want Zernio to capture the conversation as well.

Vapi

A Vapi assistant answers over SIP. Create the assistant's SIP username in Vapi, then point the number at sip:{username}@sip.vapi.ai. Zernio authenticates with SIP digest, so nothing else is needed on your side.

curl -X POST "https://zernio.com/api/v1/phone-numbers/66d4e5f6a7b8c9d0e1f2a3b4/voice" \
  -H "Authorization: Bearer $ZERNIO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"forwardTo": "sip:agent-acme@sip.vapi.ai"}'

Response (200):

{
  "enabled": true,
  "phoneNumber": "+14155550100",
  "pstnForwardTo": "sip:agent-acme@sip.vapi.ai",
  "voicemailEnabled": true
}

The prompt, the voice and the tools stay on Vapi's side; Zernio owns the carrier leg and bridges the audio. A sip: agent bills the same way a wss:// one does: there is no PSTN leg on the far side, so you pay only for the inbound call.

Custom agents

Point forwardTo at your own wss:// endpoint to run your own speech-to-text, LLM and text-to-speech pipeline. Zernio does not proxy or re-encode the audio: it starts the stream on the carrier leg, and Telnyx, the carrier behind Zernio voice, opens the WebSocket to your server. Your side implements Telnyx's media streaming over WebSockets, which defines the start, media, stop and error events and carries the audio as base64 RTP payloads. Zernio fixes 3 of that protocol's settings:

SettingValue
stream_trackinbound_track, so you receive the caller's audio
stream_bidirectional_modertp, so media frames you write back on the same socket reach the caller
stream_bidirectional_codecPCMU, G.711 u-law at 8 kHz, in both directions

They are not configurable per number today, so build the agent against PCMU at 8 kHz. This is the same bidirectional media bridge that WhatsApp Calling uses, so an agent you build once serves both channels.

If it fails

A 409 with code: "invalid_resource_state" on the voice call means the number is attached to a SIP trunk; detach it with DELETE /v1/phone-numbers/{id}/sip-trunk first. A call that reaches voicemail or ends right after answering usually means the handshake failed: check the wss:// URL and that the server accepts the connection, then read callErrors on the call record. Every error uses the envelope in error handling.

Related

  • Setup: voicemail, business hours, IVR and the blocklist around the agent.
  • ElevenLabs and Retell: SIP-based agents.
  • Outbound calls: hand an outbound call to the agent.
  • Enable voice on a number: every field of the request.
Was this page helpful?

Setup

Set where a number's inbound calls go and turn on voicemail, business hours, an IVR menu, a caller blocklist, recording and transcription.

Integrations

Put an ElevenLabs or Retell agent on a Zernio number by SIP forwarding or a SIP trunk, while the number, its KYC, SMS and WhatsApp stay with Zernio.

On this page

Step 1: Point the number at the agentHow the bridge worksVapiCustom agentsIf it failsRelated