Metadata-Version: 2.4
Name: vaani-sdk
Version: 0.1.0
Summary: Python SDK for the Vaani External API
License: MIT
Keywords: ai,calls,sdk,vaani,voice
Requires-Python: >=3.9
Requires-Dist: httpx>=0.24.0
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: respx>=0.20; extra == 'dev'
Description-Content-Type: text/markdown

# vaani-sdk

Python SDK for the [Vaani](https://vaanivoice.ai) API. Authenticate once with your API key and call all available endpoints from clean, typed Python methods — both synchronous and asynchronous.

## Installation

```bash
pip install vaani-sdk
```

Or install directly from source:

```bash
git clone https://github.com/your-org/vaani-sdk
cd vaani-sdk
pip install -e .
```

## Quick Start

```python
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):

```python
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`                     |

```python
client = VaaniClient(
    api_key="YOUR_API_KEY",
    base_url="https://api.vaanivoice.ai",
    timeout=60.0,
)
```

### Getting your API key

1. Log in to **[app.vaanivoice.ai](https://app.vaanivoice.ai)**
2. Navigate to **Settings > API Keys**
3. 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.

```python
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.

```python
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](https://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 |

```python
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:

```json
{
  "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) |

```python
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:`).

```python
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.

```python
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.

```python
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:

```python
with open("recording.ogg", "wb") as f:
    for chunk in client.stream_audio_iter("outbound-1776774443-863aa698"):
        f.write(chunk)
```

---

## Async Usage

Every method on `VaaniClient` has an exact async equivalent on `AsyncVaaniClient`.

```python
import asyncio
from vaani_sdk import AsyncVaaniClient

async def main():
    async with AsyncVaaniClient(api_key="YOUR_API_KEY") as client:
        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)

asyncio.run(main())
```

---

## Error Handling

All exceptions inherit from `VaaniError` and carry a `status_code` attribute.

| Exception             | HTTP status | Cause                      |
| --------------------- | ----------- | -------------------------- |
| `AuthenticationError` | 401 / 403   | Invalid or missing API key |
| `NotFoundError`       | 404         | Resource does not exist    |
| `RateLimitError`      | 429         | Too many requests          |
| `ServerError`         | 5xx         | Vaani server-side error    |
| `TimeoutError`        | ---         | Request timed out          |
| `ConnectionError`     | ---         | Could not reach the API    |

```python
from vaani_sdk import VaaniClient, AuthenticationError, NotFoundError, VaaniError

with VaaniClient(api_key="YOUR_API_KEY") as client:
    try:
        transcript = client.get_transcript("non-existent-id")
    except AuthenticationError:
        print("Bad API key — check X-API-Key header value")
    except NotFoundError:
        print("Call not found or transcript not yet generated")
    except VaaniError as exc:
        print(f"API error {exc.status_code}: {exc.message}")
```

---

## Development

```bash
# Install with dev extras
pip install -e ".[dev]"

# Run tests
pytest tests/
```
