Python SDK for the Vaani External API
Project description
vaani-sdk
Python SDK for the Vaani API. Authenticate once with your API key and call all available endpoints from clean, typed Python methods — both synchronous and asynchronous.
Installation
pip install vaani-sdk
Or install directly from source:
git clone https://github.com/your-org/vaani-sdk
cd vaani-sdk
pip install -e .
Quick Start
from vaani_sdk import VaaniClient
with VaaniClient(api_key="YOUR_API_KEY") as client:
# Telephony call
result = client.trigger_call(
agent_id="d62cc9bd-2f51-4581-9f38-6c3b7d58a988",
contact_number="+919876543210",
name="Rahul",
)
print(result.call_id) # "outbound-1776774443-863aa698"
# WebRTC session (same endpoint, different medium)
result = client.trigger_call(
agent_id="d62cc9bd-2f51-4581-9f38-6c3b7d58a988",
medium="webrtc",
primary_language="en",
)
print(result.token) # LiveKit participant JWT
print(result.connection_url) # wss://livekit.vaaniresearch.com
Configuration
| Parameter | Description | Default |
|---|---|---|
api_key |
Your Vaani API key (X-API-Key) |
(required) |
base_url |
Base URL of the Vaani API | https://api.vaanivoice.ai |
timeout |
Request timeout in seconds | 120.0 |
client = VaaniClient(
api_key="YOUR_API_KEY",
base_url="https://api.vaanivoice.ai",
timeout=60.0,
)
Getting your API key
- Log in to app.vaanivoice.ai
- Navigate to Settings > API Keys
- Click Generate API Key, give it a descriptive name, and copy the key immediately
Your key is shown only once at creation time. Store it securely in an environment variable or secrets manager — never commit it to version control.
import os
from vaani_sdk import VaaniClient
client = VaaniClient(api_key=os.getenv("VAANI_API_KEY"))
API Reference
client.health()
Check the health of the Vaani API.
resp = client.health()
print(resp.status) # "healthy"
print(resp.service) # "vaani-external-api"
client.trigger_call(...)
Unified endpoint for telephony outbound calls and WebRTC voice sessions.
Select the mode with the medium parameter.
Telephony
| Parameter | Type | Required | Description |
|---|---|---|---|
agent_id |
str | Yes | Agent UUID from app.vaanivoice.ai |
medium |
str | No | "telephony" (default) |
contact_number |
str | Yes | Phone number in E.164 format (e.g. +919876543210) |
name |
str | Yes | Customer display name |
voice |
str | No | Override the agent's default voice for this call |
metadata |
dict | No | Template variables injected into the agent's prompt at call time |
outbound_number |
str | No | Override the caller ID (E.164). Must be configured in Telephony settings |
sip_trunk_id |
str | No | SIP trunk identifier |
test_mode |
bool | No | When True, simulates the call without placing it |
dnd_check_skipped |
bool | No | Skip Do-Not-Disturb registry check |
modify_agent |
ModifyAgentConfig | No | Inline agent config overrides for this call |
result = client.trigger_call(
agent_id="d62cc9bd-2f51-4581-9f38-6c3b7d58a988",
contact_number="+919876543210",
name="Rahul Sharma",
metadata={
"customer_name": "Rahul Sharma",
"property_name": "Prateek Laurel",
},
outbound_number="+919873446283",
)
print(result.call_id) # "outbound-1776774443-863aa698"
print(result.raw) # full API response dict
Telephony response shape:
{
"success": true,
"message": "Call initiated successfully",
"output": {
"agent_name": "my-sales-agent",
"call_id": "outbound-1776774443-863aa698",
"live_captions_url": "wss://api.vaanivoice.ai/api/live-transcripts/ws/outbound-..."
}
}
WebRTC
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
agent_id |
str | Yes | Agent UUID | |
medium |
str | Yes | "webrtc" |
|
voice_gender |
str | No | "female" |
"male" or "female" |
primary_language |
str | No | "hi" |
Primary language code (e.g. "en", "hi") |
secondary_language |
str | No | "en" |
Secondary language code |
welcome_message |
str | No | None | Custom opening message |
welcome_interruptible |
bool | No | True |
Can the user interrupt the welcome message |
bg_noise_enabled |
bool | No | False |
Enable background noise |
bg_noise_volume |
int | No | 60 |
Background noise volume (0–100) |
voice_speed |
float | No | 1.0 |
Voice speed multiplier (0.6–1.4) |
metadata |
dict | No | {} |
Arbitrary key-value pairs |
modify_agent |
ModifyAgentConfig | No | None | Inline agent overrides |
result = client.trigger_call(
agent_id="d62cc9bd-2f51-4581-9f38-6c3b7d58a988",
medium="webrtc",
primary_language="en",
voice_gender="female",
welcome_message="Hi! How can I help you today?",
)
print(result.token) # LiveKit participant JWT
print(result.room_name) # "room_<agent_id>_<hash>"
print(result.connection_url) # "wss://livekit.vaaniresearch.com"
print(result.live_captions_url)# WebSocket URL for live transcription
WebRTC response shape:
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"room_name": "room_d62cc9bd-2f51-4581-9f38-6c3b7d58a988_abc123",
"agent_name": "my-agent",
"connection_url": "wss://livekit.vaaniresearch.com",
"live_captions_url": "ws://api.vaanivoice.ai/api/live-transcripts/ws/room_..."
}
ModifyAgentConfig
Inline agent configuration overrides applied for the duration of this call only. Works for both mediums.
from vaani_sdk import VaaniClient
from vaani_sdk.models import ModifyAgentConfig
result = client.trigger_call(
agent_id="d62cc9bd-2f51-4581-9f38-6c3b7d58a988",
contact_number="+919876543210",
name="Rahul",
modify_agent=ModifyAgentConfig(
persona={
"identity": {
"system_prompt": "You are a concise support agent. Keep answers under 2 sentences."
}
},
training={
"know_how": {
"faq": {"What are your hours?": "9 AM to 5 PM."}
}
},
),
)
| Field | Type | Description |
|---|---|---|
persona |
dict | Persona section override |
training |
dict | Training section override |
experience |
dict | Experience section override |
analysis |
dict | Analysis section override |
client.get_call_history(page, page_size)
Retrieve paginated call history for the authenticated user's workspace.
| Parameter | Type | Default | Description |
|---|---|---|---|
page |
int | 1 | Page number (1-indexed) |
page_size |
int | 50 | Records per page (max 200) |
history = client.get_call_history(page=1, page_size=20)
print(history.pagination.total) # e.g. 1028
print(history.pagination.total_pages) # e.g. 21
for call in history.data:
print(call.call_id, call.raw.get("call_status"), call.raw.get("duration_ms"))
client.get_transcript(call_id)
Retrieve the full conversation transcript for a completed call.
transcript = client.get_transcript("outbound-1776774443-863aa698")
print(transcript.transcript)
client.get_call_details(call_id)
Get detailed call information including transcript, extracted entities, evaluation, and AI-generated summary.
details = client.get_call_details("outbound-1776774443-863aa698")
print(details.raw.get("summary"))
print(details.raw.get("entity"))
print(details.raw.get("call_eval_tag"))
client.stream_audio(call_id)
Download the audio recording for a call (audio/ogg or audio/mpeg).
audio = client.stream_audio("outbound-1776774443-863aa698")
with open("recording.ogg", "wb") as f:
f.write(audio.content)
# Stream in chunks for large files
with open("recording.ogg", "wb") as f:
for chunk in client.stream_audio_iter("outbound-1776774443-863aa698"):
f.write(chunk)
client.create_agent(agent_display_name, config)
Create a new agent.
result = client.create_agent(
agent_display_name="my-support-bot",
config={
"persona": {
"identity": {
"system_prompt": "You are a helpful support agent."
}
}
},
)
print(result.agent_id) # "33ac5907-0e44-43c4-934e-08e335cca6ee"
print(result.agent_name) # "vaani123my-support-bot"
Agent config update methods
Partially update any section of an agent's configuration:
# Persona (identity, senses, actions, memories)
client.update_agent_persona(agent_id, persona={...})
# Training (knowledge base, FAQ, guardrails)
client.update_agent_training(agent_id, training={...})
# Experience (conversational settings, idle/end-call behavior)
client.update_agent_experience(agent_id, experience={...})
# Analysis (dispositions, evaluations, data extraction)
client.update_agent_analysis(agent_id, analysis={...})
# Deployment (phone call types, inbound/outbound numbers)
client.update_agent_deployment(agent_id, deployment={...})
Each returns AgentConfigResponse with agent_id, agent_display_name, and raw (full merged config).
WebRTC Sessions
The client.sessions namespace provides the full session-based WebRTC flow for embedding voice chat in your own UI.
Flow
client.sessions.create(...)— returns asession_tokenand embeddablesession_urlclient.sessions.connect(session_token)— exchange for LiveKit credentials- Pass
creds.lk_url+creds.lk_tokento the LiveKit client SDK in your browser/app - Optionally watch real-time events via
client.sessions.ws_url(session_token) client.sessions.disconnect(session_token)— end the session
with VaaniClient(api_key="YOUR_API_KEY") as client:
session = client.sessions.create(
agent_id="d62cc9bd-2f51-4581-9f38-6c3b7d58a988",
ui_type="widget",
grace_period=60,
session_ttl=1800,
metadata={"user_id": "user_123"},
)
print(session.session_token)
print(session.session_url)
creds = client.sessions.connect(session.session_token)
print(creds.lk_url) # "wss://livekit.vaaniresearch.com"
print(creds.lk_token) # LiveKit participant JWT
print(creds.room_name)
client.sessions.disconnect(session.session_token, explicit_end=True)
Sessions reference
| Method | Description | Returns |
|---|---|---|
sessions.create(agent_id, ...) |
Create a session token + embeddable URL | WebRTCSession |
sessions.connect(token) |
Exchange token for LiveKit credentials | WebRTCSessionConnect |
sessions.get(token) |
Fetch current session state | WebRTCSessionStatus |
sessions.disconnect(token, explicit_end=False) |
Signal disconnect or end session | WebRTCSessionStatus |
sessions.ws_url(token) |
Build WebSocket URL for real-time events | str |
Resource Namespaces
client.calls
with VaaniClient(api_key="YOUR_API_KEY") as client:
# Trigger a telephony call
resp = client.calls.trigger(
agent_id="d62cc9bd-2f51-4581-9f38-6c3b7d58a988",
contact_number="+919876543210",
name="Rahul",
medium="telephony",
dnd_check_skipped=True,
)
print(resp.call_id)
# Trigger a WebRTC session
resp = client.calls.trigger(
agent_id="d62cc9bd-2f51-4581-9f38-6c3b7d58a988",
contact_number="+919876543210",
medium="webrtc",
)
print(resp.token)
# Get call details, transcript, history
details = client.calls.get_details(resp.call_id)
transcript = client.calls.get_transcript(resp.call_id)
history = client.calls.get_history(page=1, page_size=50)
client.campaigns
Manage outbound campaigns:
with VaaniClient(api_key="YOUR_API_KEY") as client:
campaign = client.campaigns.create(
name="Q3 Outreach",
agent_id="d62cc9bd-2f51-4581-9f38-6c3b7d58a988",
csv_content=open("contacts.csv", "rb").read(),
)
client.campaigns.start(campaign.id)
status = client.campaigns.get_status(campaign.id)
print(status.status) # "running"
client.campaigns.pause(campaign.id)
client.campaigns.resume(campaign.id)
client.campaigns.stop(campaign.id)
client.agents
with VaaniClient(api_key="YOUR_API_KEY") as client:
agents = client.agents.list()
for agent in agents:
print(agent.id, agent.agent_name)
agent = client.agents.get("d62cc9bd-2f51-4581-9f38-6c3b7d58a988")
print(agent.agent_language)
Async Usage
Every method has an exact async counterpart on AsyncVaaniClient:
import asyncio
from vaani_sdk import AsyncVaaniClient
async def main():
async with AsyncVaaniClient(api_key="YOUR_API_KEY") as client:
# Telephony
result = await client.trigger_call(
agent_id="d62cc9bd-2f51-4581-9f38-6c3b7d58a988",
contact_number="+919876543210",
name="Rahul",
)
print(result.call_id)
# WebRTC
result = await client.trigger_call(
agent_id="d62cc9bd-2f51-4581-9f38-6c3b7d58a988",
medium="webrtc",
primary_language="en",
)
print(result.token)
history = await client.get_call_history(page=1, page_size=5)
session = await client.sessions.create(
agent_id="d62cc9bd-2f51-4581-9f38-6c3b7d58a988"
)
creds = await client.sessions.connect(session.session_token)
asyncio.run(main())
Error Handling
All exceptions inherit from VaaniError and carry a status_code attribute.
| Exception | HTTP status | Cause |
|---|---|---|
AuthenticationError |
401 | Invalid or missing API key |
ForbiddenError |
403 | Operation not allowed (e.g. DND block, wrong key) |
NotFoundError |
404 | Resource does not exist |
SessionExpiredError |
410 | WebRTC session has ended or expired |
InsufficientBalanceError |
402 | Wallet balance too low |
ValidationError |
422 | Request parameters failed validation |
RateLimitError |
429 | Too many requests |
ServerError |
5xx | Vaani server-side error |
TimeoutError |
— | Request timed out |
ConnectionError |
— | Could not reach the API |
from vaani_sdk import VaaniClient, ForbiddenError, VaaniError
with VaaniClient(api_key="YOUR_API_KEY") as client:
try:
result = client.trigger_call(
agent_id="my-agent",
contact_number="+919876543210",
name="Test",
)
except ForbiddenError as exc:
# e.g. "Call blocked: destination number is in DND registry"
# Use dnd_check_skipped=True to bypass DND in test environments
print(f"Forbidden: {exc}")
except VaaniError as exc:
print(f"API error {exc.status_code}: {exc}")
Development
Setup
# Install with dev extras (uses uv)
uv sync --dev
# Or with pip
pip install -e ".[dev]"
Running tests
# Unit tests (no server required — all mocked)
uv run pytest tests/test_client.py tests/test_resources.py -v
# Integration tests (requires local API stack)
uv run pytest tests/integration/ -v -s
Integration test setup
The integration tests target a locally-running vaani-external-api (port 8001) which proxies to vaani-backend-new (port 8500).
# 1. Start vaani-backend-new
cd vaani-backend-new && docker compose -f docker-compose.dev.yaml up -d
# 2. Start vaani-external-api
cd external/vaani-external-api && docker compose up -d
# 3. Run integration tests
cd external/vaani-sdk
VAANI_API_KEY=vaani_... VAANI_AGENT_ID=<uuid> uv run pytest tests/integration/ -v -s
Environment variables for integration tests:
| Variable | Default | Description |
|---|---|---|
VAANI_API_KEY |
vaani_c1fc7e33c05632830ffe16da5e314b0d |
API key |
VAANI_BASE_URL |
http://localhost:8001 |
External API base URL |
VAANI_AGENT_ID |
d62cc9bd-2f51-4581-9f38-6c3b7d58a988 |
Agent UUID for tests |
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file vaani_sdk-0.3.0.tar.gz.
File metadata
- Download URL: vaani_sdk-0.3.0.tar.gz
- Upload date:
- Size: 84.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7350238dc9d08ecc497a9fe783f25cd51abed702d4f0e5d2f86dedf86d9e6e25
|
|
| MD5 |
9af561730d927efedc27b5a8265e6409
|
|
| BLAKE2b-256 |
8cc8f5b4932ef7b00d80490defa683e7d0bc6efd125211a2d8da1cd54a895773
|
File details
Details for the file vaani_sdk-0.3.0-py3-none-any.whl.
File metadata
- Download URL: vaani_sdk-0.3.0-py3-none-any.whl
- Upload date:
- Size: 24.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
051960d5b31c710e25990fca6dd5aa25b7682c8e818e43da398670a24483a275
|
|
| MD5 |
a75e505c5402119ae2f9431566a97508
|
|
| BLAKE2b-256 |
16931d6b4c25da406669a1f6a87a844b921b5871d887160c20ff32a335c567da
|