Voisnap Docs
SDKs

Python SDK

Full reference for the official Voisnap Python SDK — installation, authentication, all resource methods, async support, and error handling.

Python SDK

The official Voisnap Python SDK provides a Pythonic interface to the entire Voisnap API with auto-pagination, async support, and typed dataclasses.

Installation

pip install voisnap

Requires Python 3.8+.


Initialization

API key authentication

import voisnap
 
client = voisnap.VoisnapClient(api_key="vsnp_live_...")

JWT authentication

client = voisnap.VoisnapClient(access_token="eyJhbGci...")

Custom base URL (sandbox)

client = voisnap.VoisnapClient(
    api_key="vsnp_sb_...",
    base_url="https://sandbox.api.voisnap.ai"
)

Environment variable

Set VOISNAP_API_KEY in your environment and the client picks it up automatically:

import os
os.environ["VOISNAP_API_KEY"] = "vsnp_live_..."
 
client = voisnap.VoisnapClient()  # uses VOISNAP_API_KEY

Agents

Create an agent

agent = client.agents.create(
    name="Aria – Support Agent",
    persona={"name": "Aria", "personality": "friendly, professional"},
    voice={
        "provider": "elevenlabs",
        "voice_id": "EXAVITQu4vr4xnSDxMaL",
        "stability": 0.5,
        "similarity_boost": 0.75,
    },
    llm={"provider": "openai", "model": "gpt-4o", "temperature": 0.7, "max_tokens": 300},
    transcription={"provider": "deepgram", "model": "nova-2", "language": "en-US"},
    system_prompt_template="You are Aria, a friendly support agent...",
    first_message="Hello! How can I help you today?",
    first_message_mode="assistant_speaks_first",
    end_call_phrases=["goodbye", "thank you, bye"],
    max_duration_seconds=600,
    recording={"enabled": True, "format": "mp3", "storage_retention_days": 90},
)
print(f"Created agent: {agent.id}")

List agents (auto-paginated)

The list() method returns a lazy iterator that automatically fetches subsequent pages:

# Iterate all active agents
for agent in client.agents.list(status="active"):
    print(f"{agent.name}{agent.status}")
 
# Collect all to a list
all_agents = list(client.agents.list())
 
# With filters
support_agents = list(client.agents.list(
    status="active",
    search="support",
    sort_by="created_at",
    sort_order="desc"
))

Get a single agent

agent = client.agents.get("agt_01HXK8Z3MNPQRS")
print(agent.system_prompt_template)

Update an agent

updated = client.agents.update(
    "agt_01HXK8Z3MNPQRS",
    system_prompt_template="Updated prompt text...",
    llm={"temperature": 0.5},
    max_duration_seconds=900,
)

Delete an agent

client.agents.delete("agt_01HXK8Z3MNPQRS")

Activate and deactivate

client.agents.activate("agt_01HXK8Z3MNPQRS")
client.agents.deactivate("agt_01HXK8Z3MNPQRS")

Publish a version

client.agents.publish("agt_01HXK8Z3MNPQRS", notes="Improved billing prompt")

Get agent stats

stats = client.agents.stats(
    "agt_01HXK8Z3MNPQRS",
    date_from="2025-06-01",
    date_to="2025-06-30"
)
print(f"Conversations: {stats.total_conversations}")
print(f"Avg duration: {stats.avg_duration_seconds}s")
print(f"Resolution rate: {stats.outcome_breakdown.resolved / stats.total_conversations:.1%}")

Conversations

List conversations (auto-paginated)

for conv in client.conversations.list(
    agent_id="agt_01HXK8Z3MNPQRS",
    channel="phone",
    status="completed",
    date_from="2025-06-01",
    date_to="2025-06-30",
):
    print(f"{conv.id}: {conv.duration_seconds}s, sentiment: {conv.analysis.sentiment}")

Get a conversation

conv = client.conversations.get("conv_01HXDEF456GHI")

Get transcript

transcript = client.conversations.transcript("conv_01HXDEF456GHI")
for turn in transcript.turns:
    role = "🤖" if turn.speaker == "agent" else "👤"
    print(f"{role} [{turn.start_time:.1f}s] {turn.text}")

Get analysis

analysis = client.conversations.analysis("conv_01HXDEF456GHI")
print(f"Sentiment: {analysis.sentiment} ({analysis.sentiment_score:.2f})")
print(f"Intent: {analysis.intent}")
print(f"Summary: {analysis.summary}")

Add tags

client.conversations.add_tags("conv_01HXDEF456GHI", ["billing", "vip"])

Set outcome

client.conversations.set_outcome(
    "conv_01HXDEF456GHI",
    outcome="resolved",
    notes="Billing question resolved."
)

Telephony

Search available numbers

numbers = client.telephony.numbers.search(
    country="US",
    area_code="415",
    capabilities=["voice", "sms"]
)
for n in numbers:
    print(f"{n.phone_number} — ${n.monthly_cost_usd}/mo")

Provision a number

number = client.telephony.numbers.provision(
    phone_number="+14155550100",
    provider="twilio",
    friendly_name="Main Support Line"
)

Assign to agent

client.telephony.numbers.assign(
    number_id=number.id,
    agent_id="agt_01HXK8Z3MNPQRS"
)

List provisioned numbers

for num in client.telephony.numbers.list():
    print(f"{num.phone_number}{num.assigned_agent_name or 'unassigned'}")

Knowledge Base

Upload a document

with open("product-catalog.pdf", "rb") as f:
    doc = client.knowledge_base.upload_document(
        file=f,
        name="Product Catalog Q2 2025",
        agent_ids=["agt_01HXK8Z3MNPQRS"],
        metadata={"department": "product"}
    )
 
# Wait for indexing
import time
while doc.status == "processing":
    time.sleep(3)
    doc = client.knowledge_base.get(doc.id)
 
print(f"Indexed {doc.chunk_count} chunks")
results = client.knowledge_base.search(
    query="What is the return policy?",
    document_ids=["kb_01HXABC123DEF"],
    top_k=5,
    min_score=0.7
)
for match in results.matches:
    print(f"Score: {match.score:.3f} | {match.excerpt[:100]}...")

Outbound Calls

Create an outbound call

# Immediate
call = client.outbound_calls.create(
    agent_id="agt_01HXK8Z3MNPQRS",
    to_number="+14155550199",
    metadata={"customer_id": "cust_12345"},
)
 
# Scheduled
call = client.outbound_calls.create(
    agent_id="agt_01HXK8Z3MNPQRS",
    to_number="+14155550199",
    scheduled_for="2025-06-17T09:00:00Z",
    max_retries=2,
    retry_delay_minutes=30,
)

Cancel a call

client.outbound_calls.cancel("obc_01HXMN8ZABC123")

List outbound calls

for call in client.outbound_calls.list(status="completed"):
    print(f"{call.to_number}: {call.status}")

Async support

Every synchronous method has an async equivalent via AsyncVoisnapClient:

import asyncio
import voisnap
 
async def main():
    client = voisnap.AsyncVoisnapClient(api_key="vsnp_live_...")
 
    # Concurrent requests
    agent, conversations = await asyncio.gather(
        client.agents.get("agt_01HXK8Z3MNPQRS"),
        client.conversations.list(agent_id="agt_01HXK8Z3MNPQRS").__anext__(),
    )
 
    # Async iteration
    async for conv in client.conversations.list(status="completed"):
        print(conv.id)
 
    await client.close()
 
asyncio.run(main())

Error handling

from voisnap.exceptions import (
    VoisnapError,
    AuthenticationError,
    PermissionError,
    NotFoundError,
    RateLimitError,
    ValidationError,
    ServerError,
)
 
try:
    agent = client.agents.get("agt_does_not_exist")
except NotFoundError as e:
    print(f"Not found: {e.detail}")
except AuthenticationError as e:
    print(f"Auth failed: {e.message}")
except RateLimitError as e:
    print(f"Rate limited. Retry after {e.retry_after}s")
except ValidationError as e:
    for err in e.errors:
        print(f"  {err.field}: {err.message}")
except VoisnapError as e:
    print(f"API error {e.status}: {e.detail} (trace: {e.trace_id})")

The SDK automatically retries RateLimitError (429) and transient ServerError (503) with exponential backoff. You can configure retry behavior:

client = voisnap.VoisnapClient(
    api_key="vsnp_live_...",
    max_retries=3,          # default: 3
    retry_on=[429, 503],    # default
    timeout=30,             # seconds, default: 30
)

Pagination utilities

# Get a single page
page = client.agents.list_page(page=2, page_size=50)
print(f"Page {page.page} of {page.total_pages}, {page.total} total")
for agent in page.data:
    print(agent.name)
 
# Collect all items across all pages
all_agents = client.agents.list_all()  # fetches all pages sequentially