API v1

Voice API Documentation

Start AI voice sessions, manage configuration, track usage, and receive webhooks — all with one API key. No SDKs required.

Contents

Base URL

https://api.voisero.info

All requests must use HTTPS.

01 Authentication

Every request requires your API key in the Authorization header:

Authorization: Bearer vl_live_your_api_key_here
Security: Never expose your API key in frontend code or public repos. Always call the API from your backend server, then pass the WebSocket URL to your frontend.

02 Configuration

Set your default agent settings. These apply to every new session unless overridden per-request.

GET/v1/config

Get your current configuration.

curl https://api.voisero.info/v1/config \
  -H "Authorization: Bearer YOUR_API_KEY"
Response
{
  "provider": "basic",
  "prompt": "You are a helpful assistant.",
  "language": "ro",
  "maxDuration": 300,
  "webhookUrl": null
}
PUT/v1/config

Update any combination of settings.

FieldTypeDescription
providerstringbasic — low cost & low latency | advanced — superior quality & reasoning
promptstringSystem prompt — personality and instructions for the agent
languagestringLanguage hint (e.g. ro, en, de)
maxDurationintegerMax call duration in seconds (10 – 3600)
curl -X PUT https://api.voisero.info/v1/config \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"provider":"advanced","prompt":"You are a recruitment assistant.","maxDuration":180}'

03 Sessions

A session is a single voice conversation. Only one active session at a time per API key.

POST/v1/sessions

Start a new voice session. Returns a WebSocket URL your frontend connects to.

All fields are optional — defaults come from your config.

FieldTypeDescription
providerstringOverride provider for this session
promptstringOverride prompt for this session
languagestringOverride language for this session
maxDurationintegerOverride max duration for this session
curl -X POST https://api.voisero.info/v1/sessions \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
Response
{
  "sessionId": "sess_1775550000_a1b2c3d4",
  "provider": "basic",
  "connectionType": "wss",
  "joinUrl": "wss://provider.example/session/abc123...",
  "maxDuration": 300,
  "status": "active"
}
One session at a time. Starting a second session while one is active returns 409 with the active session ID. End it first.
GET/v1/sessions/:id

Get session status with live elapsed timer.

curl https://api.voisero.info/v1/sessions/SESSION_ID \
  -H "Authorization: Bearer YOUR_API_KEY"
Response
{
  "sessionId": "sess_1775550000_a1b2c3d4",
  "status": "active",
  "elapsed": { "totalSeconds": 47, "display": "0m 47s" },
  "maxDuration": 300,
  "transcript": []
}
DELETE/v1/sessions/:id

End an active session immediately.

curl -X DELETE https://api.voisero.info/v1/sessions/SESSION_ID \
  -H "Authorization: Bearer YOUR_API_KEY"

04 Connecting to Voice

No SDKs or packages to install. The joinUrl is a standard WebSocket URL that works in any browser.

Zero dependencies. Your frontend only needs the native browser WebSocket and MediaDevices APIs. No npm packages required.

How it works

1. Your backend calls POST /v1/sessions → gets joinUrl (wss://...)
2. Pass joinUrl to your frontend
3. Frontend opens WebSocket connection
4. User speaks → mic audio streams over WebSocket
5. AI responds with audio → plays in browser
6. Session auto-ends at maxDuration, or you call DELETE

Frontend Example (plain JavaScript)

// joinUrl from your backend (never expose API key in frontend)
const joinUrl = "wss://...";

const ws = new WebSocket(joinUrl);

ws.onopen = async () => {
  // Get microphone access
  const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
  const ctx = new AudioContext({ sampleRate: 16000 });
  const source = ctx.createMediaStreamSource(stream);
  const processor = ctx.createScriptProcessor(4096, 1, 1);

  processor.onaudioprocess = (e) => {
    if (ws.readyState === WebSocket.OPEN) {
      const pcm = e.inputBuffer.getChannelData(0);
      const int16 = new Int16Array(pcm.length);
      for (let i = 0; i < pcm.length; i++) {
        int16[i] = Math.max(-32768, Math.min(32767, pcm[i] * 32768));
      }
      ws.send(int16.buffer);
    }
  };

  source.connect(processor);
  processor.connect(ctx.destination);
};

ws.onmessage = async (event) => {
  if (event.data instanceof Blob) {
    // Play AI audio response
    const ctx = new AudioContext();
    const buf = await ctx.decodeAudioData(await event.data.arrayBuffer());
    const src = ctx.createBufferSource();
    src.buffer = buf;
    src.connect(ctx.destination);
    src.start();
  }
};

ws.onclose = () => console.log("Session ended");

Architecture

┌──────────────┐      HTTPS       ┌────────────────┐      HTTPS       ┌─────────────┐
│   Browser    │ ───────────────► │  Your Backend  │ ───────────────► │  Voisero    │
│   (user)     │ ◄─────────────── │  (any language)│ ◄─────────────── │  API        │
│              │   joinUrl        │                │   joinUrl        │             │
└──────┬───────┘                  └────────────────┘                  └─────────────┘
       │
       │ wss:// (direct audio)
       ▼
┌──────────────┐
│  Voice AI    │
│  Provider    │
└──────────────┘

Your backend holds the API key. The browser connects directly to the voice provider — audio never passes through your server.

05 Usage & History

GET/v1/usage

Cumulative usage: total calls, total time, active sessions.

curl https://api.voisero.info/v1/usage \
  -H "Authorization: Bearer YOUR_API_KEY"
Response
{
  "totalCalls": 24,
  "totalTime": { "seconds": 3720, "display": "62m 0s" },
  "activeSessions": 0
}
GET/v1/sessions

List all sessions (newest first) with duration.

Query ParamTypeDescription
limitintegerResults per page (default 20, max 100)
offsetintegerSkip N results for pagination
statusstringFilter: active, ended, timeout
curl "https://api.voisero.info/v1/sessions?limit=5&status=ended" \
  -H "Authorization: Bearer YOUR_API_KEY"
Response
{
  "sessions": [
    {
      "id": "sess_1775550000_a1b2c3d4",
      "provider": "basic",
      "status": "ended",
      "reason": "manual",
      "duration_seconds": 270,
      "elapsed": { "totalSeconds": 270, "display": "4m 30s" }
    }
  ],
  "pagination": { "total": 24, "limit": 5, "offset": 0 }
}

06 Webhooks

Get notified when a session ends.

PUT/v1/webhooks

Register or update your webhook URL.

curl -X PUT https://api.voisero.info/v1/webhooks \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://your-server.com/webhook"}'

Webhook Payload

{
  "event": "session.ended",
  "sessionId": "sess_...",
  "provider": "basic",
  "reason": "manual",
  "duration": 270,
  "transcript": [...],
  "timestamp": "2026-04-07T12:04:30Z"
}

Verifying Signatures

Every webhook includes an X-Signature header — HMAC-SHA256 of the body using your webhookSecret:

const expected = crypto
  .createHmac('sha256', webhookSecret)
  .update(JSON.stringify(body))
  .digest('hex');
const valid = (signature === expected);
DELETE/v1/webhooks

Remove your webhook.

07 Error Reference

StatusMeaningWhat to do
401Invalid or missing API keyCheck your Authorization header
400Bad request / invalid providerCheck request body fields
404Session not foundVerify the session ID belongs to your account
409Session already activeEnd current session first with DELETE
500Server errorRetry or contact support

All errors return JSON: {"error": "description"}