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
client = VaaniClient(api_key="YOUR_API_KEY")
# Trigger an outbound call
result = client.trigger_call(
agent_id="8cf3373e-eb6f-4b4c-9f3c-324a56a91147",
contact_number="+919876543210",
name="Nishank",
)
print(result.call_id) # "outbound-1776774443-863aa698"
client.close()
Using the client as a context manager (recommended — ensures the HTTP connection is closed):
with VaaniClient(api_key="YOUR_API_KEY") as client:
history = client.get_call_history(page=1, page_size=10)
for call in history.data:
print(call.call_id)
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(...)
Create an outbound call dispatch.
| Parameter | Type | Required | Description |
|---|---|---|---|
agent_id |
str | Yes | Agent UUID from the Agent Config page on app.vaanivoice.ai |
contact_number |
str | Yes | Phone number in E.164 format (e.g. +919876543210) |
name |
str | Yes | Customer name |
voice |
str | No | Override the agent's default voice for this call |
metadata |
dict | No | Template variables configured in the agent's prompt, injected at call time |
outbound_number |
str | No | Override the caller ID (E.164 format). Must be a number configured in your Telephony settings |
result = client.trigger_call(
agent_id="8cf3373e-eb6f-4b4c-9f3c-324a56a91147",
contact_number="+919876543210",
name="Nishank",
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
Success response shape:
{
"success": true,
"message": "Call initiated successfully",
"output": {
"agent_name": "my-sales-agent",
"call_id": "outbound-1776774443-863aa698"
},
"error": null
}
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)
# Pagination info
print(history.pagination.total) # e.g. 1028
print(history.pagination.total_pages) # e.g. 21
# Individual calls
for call in history.data:
print(call.call_id, call.raw.get("call_status"), call.raw.get("duration_ms"))
Each call record includes call_id, call_type, call_status, agent_name, from_number, to_number, Start_time, End_time, duration_ms, call_cost, call_summary, recording_api, call_transcription, and more.
client.get_transcript(call_id)
Retrieve the full conversation transcript for a completed call, with speaker labels (AGENT: / USER:).
transcript = client.get_transcript("outbound-1776774443-863aa698")
print(transcript.transcript)
Returns "Transcript not found in Azure Blob Storage" if the call is still in progress or the transcript hasn't been generated yet.
client.get_call_details(call_id)
Get detailed call information including transcript, extracted entities, conversation 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"))
Response includes transcription, entity (extracted entities like callback requests), conversation_eval, summary, and call_eval_tag.
client.stream_audio(call_id)
Download the audio recording for a call. Returns audio/ogg or audio/mpeg binary data.
audio = client.stream_audio("outbound-1776774443-863aa698")
print(audio.content_type) # e.g. "audio/ogg"
with open("recording.ogg", "wb") as f:
f.write(audio.content)
For large files, stream in chunks to avoid loading everything into memory:
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 associated with your client.
| Parameter | Type | Required | Description |
|---|---|---|---|
agent_display_name |
str | Yes | Display name for the new agent |
config |
dict | No | Optional initial agent configuration (persona, etc.) |
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"
client.webrtc_token(...)
Generate a WebRTC token for voice chat with an agent via LiveKit.
| Parameter | Type | Default | Description |
|---|---|---|---|
agent_id |
str | None | Agent UUID (optional if agent_name provided) |
agent_name |
str | None | Agent name (optional if agent_id provided) |
voice_gender |
str | "female" | Voice gender ('male' or 'female') |
primary_language |
str | "hi" | Primary language code (e.g. 'en', 'hi') |
secondary_language |
str | "en" | Secondary language code |
welcome_message |
str | None | Custom welcome message (optional) |
welcome_interruptible |
bool | True | Whether welcome message can be interrupted |
bg_noise_enabled |
bool | False | Enable background noise |
bg_noise_volume |
int | 60 | Background noise volume (0-100) |
voice_speed |
float | 1.0 | Voice speed multiplier (0.6-1.4) |
metadata |
dict | None | Arbitrary key-value pairs (optional) |
result = client.webrtc_token(
agent_id="33ac5907-0e44-43c4-934e-08e335cca6ee",
voice_gender="female",
primary_language="en",
welcome_message="Hi! How can I help you today?",
)
print(result.token) # "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
print(result.room_url) # "wss://livekit.vaanivoice.ai"
client.update_agent_persona(agent_id, persona)
Partially update the persona section of an agent's configuration. Deep-merges the provided payload with the existing persona config.
| Parameter | Type | Required | Description |
|---|---|---|---|
agent_id |
str | Yes | Agent UUID |
persona |
dict | Yes | Persona config dict (identity, senses_capabilities, actions, memories, etc.) |
result = client.update_agent_persona(
agent_id="33ac5907-0e44-43c4-934e-08e335cca6ee",
persona={
"identity": {
"system_prompt": "You are a helpful customer service agent.",
"greeting_message": {
"agent_message": "Hi! How can I help you today?",
"interruptible": True,
}
},
"senses_capabilities": {
"language": "English",
"brain": {
"llm": {
"primary": {
"provider": "google",
"model": "gemini-2.5-flash",
"parameters": {
"temperature": 0.7,
"max_tokens": 1000
}
}
}
}
}
},
)
print(result.agent_display_name) # Updated agent name
print(result.raw["persona"]) # Full merged persona config
client.update_agent_training(agent_id, training)
Partially update the training section (knowledge base, FAQ, guardrails) of an agent's configuration.
| Parameter | Type | Required | Description |
|---|---|---|---|
agent_id |
str | Yes | Agent UUID |
training |
dict | Yes | Training config dict (knowledge, know_how) |
result = client.update_agent_training(
agent_id="33ac5907-0e44-43c4-934e-08e335cca6ee",
training={
"know_how": {
"faq": {
"What are your hours?": "We are open 9 AM to 5 PM.",
"How do I reset my password?": "Click 'Forgot Password' on the login page."
},
"guardrails": {
"no_personal_info": "Never ask for credit card numbers or passwords."
}
}
},
)
print(result.agent_display_name)
client.update_agent_experience(agent_id, experience)
Partially update the experience section (conversational settings, idle/end-call behavior) of an agent's configuration.
| Parameter | Type | Required | Description |
|---|---|---|---|
agent_id |
str | Yes | Agent UUID |
experience |
dict | Yes | Experience config dict (conversational_experience, settings) |
result = client.update_agent_experience(
agent_id="33ac5907-0e44-43c4-934e-08e335cca6ee",
experience={
"conversational_experience": {
"bg_noise": {
"enabled": True,
"volume": 0.3,
"sound": "https://example.com/office-ambience.mp3"
},
"filler_words": {
"filler_words_frequency": 0.5,
"filler_words_list": ["umm", "uhh", "ok"]
}
},
"settings": {
"call_settings": {
"max_call_duration": 30
},
"idle_conversation_settings": {
"idle_call_hangup_timeout": 20,
"idle_call_warning_message": "Are you still there?"
}
}
},
)
print(result.agent_display_name)
client.update_agent_analysis(agent_id, analysis)
Partially update the analysis section (dispositions, evaluations, data extraction) of an agent's configuration.
| Parameter | Type | Required | Description |
|---|---|---|---|
agent_id |
str | Yes | Agent UUID |
analysis |
dict | Yes | Analysis config dict (evaluations, extraction) |
result = client.update_agent_analysis(
agent_id="33ac5907-0e44-43c4-934e-08e335cca6ee",
analysis={
"evaluations": {
"dispositions": {
"enabled": True,
"prompt_based": [
{
"name": "purchase_intent",
"type": "bool",
"prompt": "Did the user express intent to purchase?",
"list_of_tags": {
"Yes": "User is interested",
"No": "User declined"
}
}
]
},
"conversation_evaluation": {
"enabled": True
}
},
"extraction": {
"data_collection": {
"enabled": True,
"data_points": [
{
"name": "customer_email",
"prompt": "Extract the customer's email address",
"nullable": True
}
]
}
}
},
)
print(result.agent_display_name)
client.update_agent_deployment(agent_id, deployment)
Partially update the deployment section (phone call types, inbound/outbound numbers) of an agent's configuration.
| Parameter | Type | Required | Description |
|---|---|---|---|
agent_id |
str | Yes | Agent UUID |
deployment |
dict | Yes | Deployment config dict (phone settings) |
result = client.update_agent_deployment(
agent_id="33ac5907-0e44-43c4-934e-08e335cca6ee",
deployment={
"deployment": {
"phone": {
"call_type": {
"Inbound": "",
"Outbound": ["+919876543210", "+919876543211"]
}
}
}
},
)
print(result.agent_display_name)
print(result.raw["deployment_config"]) # Full merged deployment config
WebRTC Sessions
The client.sessions namespace provides the full session-based WebRTC flow, which is the recommended approach for embedding voice chat into your own UI.
WebRTC Flow
- Create a session with
client.sessions.create(...)— returns asession_tokenand embeddablesession_url. - Call
client.sessions.connect(session_token)when the user is ready to join — returns LiveKit credentials. - Pass
creds.lk_urlandcreds.lk_tokento the LiveKit client SDK in your browser or mobile app. - Optionally watch real-time events with
client.sessions.ws_url(session_token). - End the session with
client.sessions.disconnect(session_token).
from vaani_sdk import VaaniClient
with VaaniClient(api_key="YOUR_API_KEY") as client:
# 1. Create a session
session = client.sessions.create(
agent_id="33ac5907-0e44-43c4-934e-08e335cca6ee",
ui_type="widget",
grace_period=60,
session_ttl=1800,
initial_message="User is asking about order #1234",
metadata={
"user_id": "user_123",
"ticket_id": "T-1234",
},
)
print(session.session_token) # JWT session token
print(session.session_url) # embeddable/shareable URL
print(session.expires_at) # expiry datetime
# 2. Exchange token for LiveKit credentials
creds = client.sessions.connect(session.session_token)
print(creds.lk_url) # "wss://livekit.vaanivoice.ai"
print(creds.lk_token) # LiveKit participant JWT
print(creds.room_name) # LiveKit room name
# 3. Check session status
status = client.sessions.get(session.session_token)
print(status.status) # "created" | "agent_ready" | "active" | "reconnecting" | "ended"
# 4. End the session (with grace period for reconnection)
client.sessions.disconnect(session.session_token)
# Or end immediately with no grace period
client.sessions.disconnect(session.session_token, explicit_end=True)
Session Events via WebSocket
Use client.sessions.ws_url(token) to build a WebSocket URL and listen to server-side push events:
import asyncio
import json
import websockets
from vaani_sdk import VaaniClient
client = VaaniClient(api_key="YOUR_API_KEY")
async def listen(session_token: str) -> None:
url = client.sessions.ws_url(session_token)
async with websockets.connect(url) as ws:
async for message in ws:
event = json.loads(message)
if event["event"] == "agent_ready":
print("Agent has joined the room")
elif event["event"] == "agent_timeout":
print("Agent failed to join:", event.get("reason"))
elif event["event"] == "session_ended":
print("Session ended:", event.get("reason"))
asyncio.run(listen("session-token-here"))
Sessions Reference
| Method | Description | Returns |
|---|---|---|
client.sessions.create(agent_id, ...) |
Create a session and return a token + embeddable URL | WebRTCSession |
client.sessions.connect(token) |
Exchange session token for LiveKit credentials | WebRTCSessionConnect |
client.sessions.get(token) |
Fetch current session state | WebRTCSessionStatus |
client.sessions.disconnect(token, explicit_end=False) |
Mark disconnect or end the session | WebRTCSessionStatus |
client.sessions.ws_url(token) |
Build WebSocket URL for real-time session events | str |
sessions.create() parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
agent_id |
str | required | Agent UUID or name |
ui_type |
str | "fullpage" |
Display mode: "fullpage" or "widget" |
grace_period |
int | None | Reconnection window in seconds (0–3600) |
session_ttl |
int | None | Session lifetime in seconds (60–86400) |
initial_message |
str | None | Message injected into agent context at session start |
metadata |
dict | None | Arbitrary key-value data forwarded to the agent |
Resource Namespaces
client.calls
Manage calls via the resource namespace (an alternative to the flat trigger_call, get_transcript, etc. methods):
with VaaniClient(api_key="YOUR_API_KEY") as client:
# Trigger an outbound call
call = client.calls.trigger(
agent_id="33ac5907-0e44-43c4-934e-08e335cca6ee",
contact_number="+919876543210",
name="Rahul",
metadata={"ticket_id": "T-1234"},
)
print(call.call_id) # "outbound-1776774443-863aa698"
print(call.status) # "in_progress"
# Get a specific call
call = client.calls.get(call.call_id)
# Get call transcript
transcript = client.calls.get_transcript(call.call_id)
# List calls (with optional agent filter and pagination)
calls = client.calls.list(agent_id="33ac5907-0e44-43c4-934e-08e335cca6ee", page=1, page_size=50)
for c in calls:
print(c.call_id, c.status)
client.agents
List and inspect agents via the resource namespace:
with VaaniClient(api_key="YOUR_API_KEY") as client:
# List all agents
agents = client.agents.list()
for agent in agents:
print(agent.id, agent.agent_name)
# Get a specific agent
agent = client.agents.get("33ac5907-0e44-43c4-934e-08e335cca6ee")
print(agent.agent_name)
print(agent.agent_language)
print(agent.created_at)
Async Usage
Every method on VaaniClient has an exact async equivalent on AsyncVaaniClient, including all resource namespaces.
import asyncio
from vaani_sdk import AsyncVaaniClient
async def main():
async with AsyncVaaniClient(api_key="YOUR_API_KEY") as client:
# Flat methods
result = await client.trigger_call(
agent_id="8cf3373e-eb6f-4b4c-9f3c-324a56a91147",
contact_number="+919876543210",
name="Nishank",
)
print(result.call_id)
history = await client.get_call_history(page=1, page_size=5)
for call in history.data:
print(call.call_id)
transcript = await client.get_transcript(history.data[0].call_id)
print(transcript.transcript)
details = await client.get_call_details(history.data[0].call_id)
print(details.raw)
# Stream audio asynchronously
with open("recording.ogg", "wb") as f:
async for chunk in client.stream_audio_iter(history.data[0].call_id):
f.write(chunk)
# Resource namespaces
session = await client.sessions.create(agent_id="8cf3373e-eb6f-4b4c-9f3c-324a56a91147")
creds = await client.sessions.connect(session.session_token)
print(creds.lk_url, creds.lk_token)
calls = await client.calls.list(page=1, page_size=10)
agents = await client.agents.list()
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 for this 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,
AuthenticationError,
ForbiddenError,
InsufficientBalanceError,
NotFoundError,
SessionExpiredError,
VaaniError,
)
with VaaniClient(api_key="YOUR_API_KEY") as client:
try:
session = client.sessions.create(agent_id="my-agent")
creds = client.sessions.connect(session.session_token)
except AuthenticationError:
print("Bad API key — check X-API-Key header value")
except ForbiddenError:
print("Agent not owned by this API key")
except InsufficientBalanceError:
print("Wallet balance is too low")
except SessionExpiredError:
print("Session has already ended")
except NotFoundError:
print("Agent not found")
except VaaniError as exc:
print(f"API error {exc.status_code}: {exc.message}")
Development
# Install with dev extras
pip install -e ".[dev]"
# Run tests
pytest 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.2.0.tar.gz.
File metadata
- Download URL: vaani_sdk-0.2.0.tar.gz
- Upload date:
- Size: 48.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
655846bf0215fc3eb5fbe61a0456434f5eb8dcc40682872e065429a53b96a9bc
|
|
| MD5 |
54f8a88b5fca09e83d813a4c80731081
|
|
| BLAKE2b-256 |
92d40c0a9af1adbf9cbb0737c14a18cfcaf4c8419f39536c7af0eaa0cb1a0e77
|
File details
Details for the file vaani_sdk-0.2.0-py3-none-any.whl.
File metadata
- Download URL: vaani_sdk-0.2.0-py3-none-any.whl
- Upload date:
- Size: 22.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 |
b156a7e72ac0cdcb5a70e9a456d8b5b3747fd6c15791a60e6499a0641faed38d
|
|
| MD5 |
aab983089a63b5844d78d2c93728282e
|
|
| BLAKE2b-256 |
1d3384b9f3264c81a56303a42d48ce3d2fb6017ceb6cb16036a3666959dcff40
|