API Reference
Programmatic call uploads and data retrieval via REST API
API Reference
Overview
The TotalView AI API allows you to programmatically upload call recordings and retrieve call data. This is useful for:
- Automating call ingestion from your telephony system
- Integrating with CRM or other business systems
- Building custom workflows
Base URL: https://app.totalview.ai/api/v1
Authentication
All API requests require authentication via an API key.
Getting an API Key
API keys are campaign-specific:
- Navigate to your campaign
- Go to Settings
- Find the API Key section
- Click Generate API Key
- Copy the key immediately
Warning: The API key is shown only once. Store it securely. If lost, generate a new key (which invalidates the old one).
[SCREENSHOT: API key section in campaign settings]
Using the API Key
Include the key in the X-API-Key header:
curl -X POST https://app.totalview.ai/api/v1/calls/upload \
-H "X-API-Key: your-api-key-here" \
-F "file=@recording.mp3"Endpoints
Upload Call
Upload a new call recording for processing.
Endpoint: POST /calls/upload
Content-Type: multipart/form-data
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
file |
File | Yes | Audio file (MP3, WAV, M4A, MP4) |
agent_name |
String | No | Agent display name |
agent_code |
String | No | Agent identifier for auto-linking |
call_type |
String | No | INBOUND or OUTBOUND |
call_date |
String | No | ISO 8601 date (e.g., 2026-01-15) |
customer_id |
String | No | Your customer reference |
disposition |
String | No | Call outcome |
client_reference |
String | No | External system ID (for deduplication) |
Example Request
curl -X POST https://app.totalview.ai/api/v1/calls/upload \
-H "X-API-Key: your-api-key" \
-F "file=@/path/to/recording.mp3" \
-F "agent_code=JS001" \
-F "agent_name=John Smith" \
-F "call_type=OUTBOUND" \
-F "call_date=2026-01-15" \
-F "customer_id=CUST-12345" \
-F "disposition=Sale Completed" \
-F "client_reference=CRM-98765"Success Response
Status: 201 Created
{
"success": true,
"data": {
"call_id": "cmj7abc123def456",
"file_name": "recording.mp3",
"status": "PENDING",
"campaign_id": "cmp_xyz789",
"created_at": "2026-01-15T10:30:00Z"
}
}Error Responses
401 Unauthorized
{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid or missing API key"
}
}403 Forbidden
{
"success": false,
"error": {
"code": "FORBIDDEN",
"message": "Campaign is archived"
}
}409 Conflict (Duplicate)
{
"success": false,
"error": {
"code": "DUPLICATE",
"message": "Call with this client_reference already exists",
"existing_call_id": "cmj7existing123"
}
}413 Payload Too Large
{
"success": false,
"error": {
"code": "FILE_TOO_LARGE",
"message": "File exceeds maximum size of 500MB"
}
}415 Unsupported Media Type
{
"success": false,
"error": {
"code": "UNSUPPORTED_FORMAT",
"message": "File format not supported. Use MP3, WAV, M4A, or MP4"
}
}429 Too Many Requests
{
"success": false,
"error": {
"code": "RATE_LIMITED",
"message": "Too many requests. Retry after 60 seconds"
},
"retry_after": 60
}Get Call IDs
Retrieve call IDs for a campaign (for integration purposes).
Endpoint: GET /campaigns/{campaign_id}/calls/ids
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
status |
String | No | Filter by status (COMPLETED, PENDING, etc.) |
from_date |
String | No | Start date (ISO 8601) |
to_date |
String | No | End date (ISO 8601) |
limit |
Number | No | Max results (default 100, max 1000) |
offset |
Number | No | Pagination offset |
Example Request
curl -X GET "https://app.totalview.ai/api/v1/campaigns/cmp_xyz789/calls/ids?status=COMPLETED&limit=50" \
-H "X-API-Key: your-api-key"Success Response
{
"success": true,
"data": {
"call_ids": [
"cmj7abc123",
"cmj7def456",
"cmj7ghi789"
],
"total": 150,
"limit": 50,
"offset": 0,
"has_more": true
}
}Rate Limits
To ensure fair usage, the API has rate limits:
| Limit | Value |
|---|---|
| Requests per minute | 60 |
| Concurrent uploads | 10 |
| Daily uploads | No hard limit (contact support for high volume) |
Handling Rate Limits
When rate limited:
- Check the
Retry-Afterheader orretry_afterfield - Wait the specified seconds
- Retry the request
Example with exponential backoff:
import time
import requests
def upload_with_retry(file_path, api_key, max_retries=3):
url = "https://app.totalview.ai/api/v1/calls/upload"
headers = {"X-API-Key": api_key}
for attempt in range(max_retries):
with open(file_path, 'rb') as f:
response = requests.post(url, headers=headers, files={"file": f})
if response.status_code == 429:
retry_after = response.json().get('retry_after', 60)
wait_time = retry_after * (2 ** attempt) # Exponential backoff
time.sleep(wait_time)
continue
return response.json()
raise Exception("Max retries exceeded")Processing Flow
After uploading via API:
Upload (201) → PENDING → TRANSCRIBING → ANALYZING → COMPLETED
The API returns immediately with PENDING status. Processing happens asynchronously.
Auto-Processing
By default, uploaded calls are processed automatically.
To disable auto-processing:
- Go to campaign Settings
- Toggle off Auto-Process API Uploads
- Calls will stay in PENDING until manually triggered
Deduplication
Use client_reference to prevent duplicate uploads:
-F "client_reference=CRM-98765"If a call with the same client_reference already exists in the campaign:
- API returns
409 Conflict - No duplicate is created
- Response includes the existing call ID
Best Practice
Always include a unique client_reference from your source system:
- CRM record ID
- Telephony system call ID
- Unique timestamp + agent combination
Webhooks (Coming Soon)
Webhook support for receiving notifications when calls complete processing is planned for a future release.
In the meantime, poll the API or check the UI for call status updates.
Code Examples
Python
import requests
API_KEY = "your-api-key"
BASE_URL = "https://app.totalview.ai/api/v1"
def upload_call(file_path, agent_code=None, call_type=None):
"""Upload a call recording."""
headers = {"X-API-Key": API_KEY}
with open(file_path, 'rb') as f:
files = {"file": f}
data = {}
if agent_code:
data["agent_code"] = agent_code
if call_type:
data["call_type"] = call_type
response = requests.post(
f"{BASE_URL}/calls/upload",
headers=headers,
files=files,
data=data
)
return response.json()
# Example usage
result = upload_call(
"/path/to/call.mp3",
agent_code="JS001",
call_type="OUTBOUND"
)
print(result)Node.js
const FormData = require('form-data');
const fs = require('fs');
const axios = require('axios');
const API_KEY = 'your-api-key';
const BASE_URL = 'https://app.totalview.ai/api/v1';
async function uploadCall(filePath, metadata = {}) {
const form = new FormData();
form.append('file', fs.createReadStream(filePath));
Object.entries(metadata).forEach(([key, value]) => {
if (value) form.append(key, value);
});
const response = await axios.post(`${BASE_URL}/calls/upload`, form, {
headers: {
'X-API-Key': API_KEY,
...form.getHeaders()
}
});
return response.data;
}
// Example usage
uploadCall('./call.mp3', {
agent_code: 'JS001',
call_type: 'OUTBOUND'
}).then(console.log);cURL (Bash Script)
#!/bin/bash
API_KEY="your-api-key"
FILE_PATH="$1"
AGENT_CODE="$2"
curl -X POST "https://app.totalview.ai/api/v1/calls/upload" \
-H "X-API-Key: $API_KEY" \
-F "file=@$FILE_PATH" \
-F "agent_code=$AGENT_CODE" \
-F "call_type=OUTBOUND"Usage: ./upload.sh /path/to/call.mp3 JS001
API Key Management
Key Security
- Store keys in environment variables, not in code
- Use secrets management for production
- Never commit keys to version control
- Rotate keys periodically
Rotating Keys
To rotate an API key:
- Go to campaign Settings → API Key
- Click Regenerate Key
- Copy the new key
- Update your integration
- The old key is immediately invalidated
Key Scope
Each API key is scoped to a single campaign:
- Can only upload to that campaign
- Cannot access other campaigns
- Different campaigns need different keys
Troubleshooting
Common Issues
| Issue | Cause | Solution |
|---|---|---|
| 401 Unauthorized | Missing or invalid key | Check X-API-Key header |
| 403 Forbidden | Campaign archived | Unarchive the campaign |
| 409 Conflict | Duplicate client_reference | Check for existing call |
| 413 Too Large | File over 500MB | Compress or split the file |
| 415 Unsupported | Wrong file format | Use MP3, WAV, M4A, MP4 |
| 429 Rate Limited | Too many requests | Wait and retry with backoff |
Testing Your Integration
- Start with a single test file
- Verify the response
- Check the call appears in the UI
- Confirm processing completes
- Then scale up uploads
FAQ
How do I get the call results via API?
Currently, the API is upload-focused. To get call results:
- Use the web interface
- Use AI Copilot for queries
- Generate reports
A results API is planned for future releases.
Can I update call metadata after upload?
Not via API. Use the web interface to edit call metadata.
What happens if upload is interrupted?
Partial uploads are discarded. The upload is atomic — it either succeeds completely or fails.
Can I delete calls via API?
Not currently. Use the web interface for deletion.
How do I know when a call is processed?
Polling: Check the call status via the UI or a future status endpoint.
The call moves from PENDING → TRANSCRIBING → ANALYZING → COMPLETED.
Is there a sandbox environment?
Contact support for sandbox access for integration testing.
Can I upload to multiple campaigns?
Yes, but you need separate API keys for each campaign. Include the correct key for the target campaign.
Related Documentation
- Uploading Calls - All upload methods
- Analysis & Scoring - Processing pipeline
- Troubleshooting - API error solutions