Audatec Voice AI
A programmable outbound call platform that lets your application trigger AI-powered phone conversations at scale. One API call — your agent handles the rest.
How it works
Every call flows through three components:
- Agents — an AI persona with a script, voice, and expected input fields (e.g.
customer_name,amount_due) - SIP Trunks — carrier lines with concurrency limits assigned to your org
- Calls — a request that combines a phone number, an agent, a trunk, and per-call metadata
Base URL
https://api.audatec.in/integration/v1
Authentication
Every request to the API must include an API key in the Authorization header.
API Key Format
Using your key
Include your key in the Authorization header on every request:
Authorization: Bearer audtk_your_key_here
Getting a key
Generate API keys from the Audatec Dashboard:
- Log in to studio.audatec.in
- Navigate to Settings → Integration
- Click New API Key, give it a name, and select a role
- Copy the key immediately — it is shown only once
Key roles
Each key carries a role that controls what it can do:
Keys are org-scoped — a key authenticates as the organisation, not an individual user. All agents and trunks belonging to your org are accessible with a valid key.
Quick Start
Place your first AI call in three steps.
id and required input_schema.fields.curl https://api.audatec.in/integration/v1/agents \
-H "Authorization: Bearer $API_KEY"
id of an active one.curl https://api.audatec.in/integration/v1/sip-trunks \
-H "Authorization: Bearer $API_KEY"
curl -X POST https://api.audatec.in/integration/v1/calls \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"phone_number": "+919876543210",
"agent_id": "830f767a-397e-4b39-82ff-235cd344e2f9",
"sip_trunk_id": "d5f3a1c0-8b2e-4f9a-b7d1-1e2c3a4b5c6d",
"metadata": {
"customer_name": "Rahul Sharma",
"amount_due": "7500",
"due_date": "2026-06-20"
}
}'
call_id. Use it to poll /calls/{call_id}/status or set a callback_url to receive the result automatically.
List Agents
Returns all active AI agents available to your organisation, including the metadata fields each agent requires.
Response — 200 OK
{
"agents": [
{
"id": "830f767a-397e-4b39-82ff-235cd344e2f9",
"name": "EMI Reminder Agent",
"agent_code": "emi-reminder-v2",
"status": "active",
"input_schema": {
"fields": ["customer_name", "amount_due", "due_date"],
"sample_context": {
"customer_name": "Rahul Sharma",
"amount_due": "7500",
"due_date": "2026-06-20"
}
}
}
]
}
Response fields
| Field | Type | Description |
|---|---|---|
id | string | Unique agent UUID. Pass this as agent_id when triggering a call. |
name | string | Human-readable display name. |
agent_code | string | Internal identifier used to dispatch the agent on the LiveKit server. |
status | string | active agents are available. Only active agents can be used to trigger calls. |
input_schema.fields | string[] | Keys that must be present in metadata when triggering a call with this agent. |
input_schema.sample_context | object | Example values showing the expected format for each field. |
List SIP Trunks
Returns all active SIP trunks (carrier lines) allocated to your organisation, with their concurrency and rate limits.
Response — 200 OK
{
"sip_trunks": [
{
"id": "d5f3a1c0-8b2e-4f9a-b7d1-1e2c3a4b5c6d",
"name": "India Prod Trunk 1",
"trunk_phone": "+918069XXXXXX",
"max_cps": 5,
"max_channels": 100,
"status": "active"
}
]
}
Response fields
| Field | Type | Description |
|---|---|---|
id | string | Unique trunk UUID. Pass this as sip_trunk_id when triggering a call. |
name | string | Display name. |
trunk_phone | string | The caller ID shown to the recipient. |
max_cps | number | Maximum calls per second this trunk accepts. Exceed it and you receive 429. |
max_channels | number | Maximum simultaneous active calls. Exceed it and you receive 429. |
status | string | Only active trunks can be used. |
Trigger a Call
Dispatch a single outbound AI call. The call is queued immediately and your agent starts the conversation when the recipient answers.
Request headers
| Header | Required | Description |
|---|---|---|
Authorization | required | Bearer audtk_... |
Content-Type | required | application/json |
Request body
| Parameter | Type | Description |
|---|---|---|
phone_numberrequired |
string | The number to call. Must be in E.164 format — +919876543210 for India, +14155552671 for the US. |
agent_idrequired |
string (UUID) | ID of the agent that will handle the call. Obtain from List Agents. |
sip_trunk_idrequired |
string (UUID) | ID of the trunk to place the call through. Obtain from List SIP Trunks. |
metadataconditional |
object | Per-call variables injected into the agent's conversation (e.g. customer name, loan amount). Keys must match all entries in the agent's input_schema.fields. Required if the agent has any fields defined. |
callback_urloptional |
string (URL) | Your HTTPS endpoint. Audatec will POST the call result here when the call reaches a terminal state. See Call Notifications. |
Example request
{
"phone_number": "+919876543210",
"agent_id": "830f767a-397e-4b39-82ff-235cd344e2f9",
"sip_trunk_id": "d5f3a1c0-8b2e-4f9a-b7d1-1e2c3a4b5c6d",
"metadata": {
"customer_name": "Rahul Sharma",
"amount_due": "7500",
"due_date": "2026-06-20"
},
"callback_url": "https://your-server.com/hooks/call-done"
}
Responses
{
"call_id": "31106b7c-9d02-4723-8b07-5bb8d90240cb",
"status": "triggered",
"poll_url": "/integration/v1/calls/31106b7c-9d02-4723-8b07-5bb8d90240cb/status"
}
Retry-After header{
"error": "Trunk concurrency (max_channels) exhausted",
"call_id": "31106b7c-9d02-4723-8b07-5bb8d90240cb",
"status": "rejected"
}
Retry-After response header for the number of seconds to wait before retrying. Channels free up as live calls complete.
Get Call Status
Returns the current state and outcome of a call. Poll this endpoint until is_terminal is true.
Path parameters
| Parameter | Description |
|---|---|
call_idrequired | The UUID returned in the call_id field when you triggered the call. |
Response — 200 OK
{
"id": "31106b7c-9d02-4723-8b07-5bb8d90240cb",
"phone_number": "+919876543210",
"call_status": "Completed",
"is_terminal": true,
"stalled": false,
"call_outcome": {
"disposition": "interested",
"summary": "Customer confirmed payment for June 20.",
"sentiment": "positive"
},
"duration": 97,
"start_timestamp": "2026-06-14T10:32:05.000Z",
"end_timestamp": "2026-06-14T10:33:42.000Z",
"transcript_url": null,
"recording_url": null,
"last_updated": "2026-06-14T10:33:42.000Z"
}
Response fields
| Field | Type | Description |
|---|---|---|
call_status | string | Current status. See Call Status Values for the full table. |
is_terminal | boolean | Stop polling when this is true. No further status changes will occur. |
stalled | boolean | true if the call was answered but has not been updated in over 10 minutes — likely a stuck session. |
call_outcome | object | null | AI-determined result (disposition, summary, sentiment). Shape depends on agent configuration. null if the call did not connect. |
duration | number | null | Call duration in seconds. null for unanswered calls. |
start_timestamp | string | null | ISO 8601 timestamp of when the recipient answered. |
end_timestamp | string | null | ISO 8601 timestamp of when the call ended. |
transcript_url | string | null | Link to call transcript, if enabled for your account. |
recording_url | string | null | Link to call recording, if enabled for your account. |
Call Notifications
Receive the call result instantly without polling by providing a callback_url when triggering the call. Audatec sends one POST to your endpoint when the call reaches a terminal state.
Notification payload
{
"event": "call.completed",
"call_id": "31106b7c-9d02-4723-8b07-5bb8d90240cb",
"call_status": "Completed",
"call_outcome": {
"disposition": "interested",
"summary": "Customer confirmed payment for June 20.",
"sentiment": "positive"
},
"duration": 97,
"transcript_url": null,
"recording_url": null,
"metadata": {
"customer_name": "Rahul Sharma",
"amount_due": "7500",
"due_date": "2026-06-20"
},
"occurred_at": "2026-06-14T10:33:42.000Z"
}
{
"event": "call.failed",
"call_id": "91a2b3c4-d5e6-7f8a-9b0c-1d2e3f4a5b6c",
"call_status": "SIP Call Failed",
"call_outcome": null,
"duration": null,
"transcript_url": null,
"recording_url": null,
"metadata": null,
"occurred_at": "2026-06-14T11:05:10.000Z"
}
Event types
The event field will be one of:
Signature verification
Every notification includes an X-Audatec-Signature header — an HMAC-SHA256 of the request body signed with your account's webhook secret. Verify it before processing:
const crypto = require('crypto');
function verifySignature(rawBody, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
Endpoint requirements
- Must return HTTP
2xxwithin 30 seconds - If processing takes longer, respond
200immediately and handle the payload asynchronously - Non-2xx responses and timeouts are retried
callback_url vs Polling
Two ways to receive call results. callback_url is strongly recommended for any production system.
callback_url Recommended
Pass a callback_url when triggering the call. Audatec POSTs the result to your endpoint the moment the call reaches a terminal state — no repeated requests, no delay, no wasted API quota.
- Zero server load — one inbound POST replaces dozens of status polls per call
- Instant — notification arrives within seconds of the call ending
- Scales linearly — 1000 concurrent calls still means exactly 1000 callbacks, not 1000 × N polls
- Verified with
X-Audatec-Signature— HMAC-SHA256 so you can reject spoofed requests
200 immediately and process the payload asynchronously. Audatec retries on non-2xx or timeout — so a fast ack prevents duplicate processing.
Polling
If you can't expose a public endpoint (local development, scripts, one-off jobs), poll GET /calls/{call_id}/status until is_terminal is true.
- No inbound server required
- Keep the interval at 4–5 seconds minimum — tighter loops waste quota without benefit
- Stop immediately once
is_terminal: true— further polls are no-ops - Not recommended at scale: 100 concurrent calls at 4 s intervals = 25 req/s of pure overhead
async function waitForCall(callId, apiKey) {
const url = `https://api.audatec.in/integration/v1/calls/${callId}/status`;
while (true) {
const res = await fetch(url, {
headers: { Authorization: `Bearer ${apiKey}` }
});
const data = await res.json();
if (data.is_terminal) return data;
await new Promise(r => setTimeout(r, 4000)); // poll every 4s
}
}
Error Handling
All errors return JSON with an error field describing what went wrong.
{ "error": "metadata missing required keys: amount_due, due_date" }
Common errors
| Error message | Cause | Fix |
|---|---|---|
phone_number is required | Missing or empty field | Include phone_number in E.164 format, e.g. +919876543210 |
metadata missing required keys: X | Agent's required fields not all present | Check input_schema.fields from GET /agents and include all keys |
Agent is not active | Agent has been deactivated | Use GET /agents to find an active agent |
SIP trunk is not active | Trunk is inactive | Use GET /sip-trunks to find an active trunk |
callback_url must be a valid http or https URL | Malformed URL | Ensure URL starts with https:// or http:// |
Invalid or inactive API key | Key revoked or wrong | Generate a new key from Settings → Integration |
Retry strategy
Different status codes call for different retry behaviour:
- 400 — Do not retry. Fix the request payload.
- 401 — Do not retry. Check your API key.
- 429 — Retry after the
Retry-Afterheader value (seconds). - 502 / 503 — Retry with exponential backoff (1s, 2s, 4s…).
Call Status Values
All possible values for the call_status field.
| Status | Terminal? | Meaning |
|---|---|---|
Initiating |
● In progress | Call accepted and queued for dispatch |
Ringing |
● In progress | Phone is ringing at the recipient's end |
Answered |
● In progress | Recipient picked up — AI conversation underway |
Completed |
✓ Terminal | Call ended normally. call_outcome is populated. |
Decline |
✓ Terminal | Recipient declined the call or line was busy |
Rejected — Capacity |
✓ Terminal | No available channels on the trunk at dispatch time |
Trigger Failed |
✓ Terminal | Audatec could not initiate the call to the carrier |
SIP Call Failed |
✓ Terminal | Carrier-level failure (no answer, network issue, SIP error) |
is_terminal is true, no further status changes will occur. The call_status field is the final state.
Error Codes
HTTP status codes returned by the API.
| Status | Name | When it occurs |
|---|---|---|
| 201 | Created | Call accepted and queued successfully |
| 400 | Bad Request | Invalid request — missing field, wrong format, metadata mismatch. The error field explains exactly what is wrong. |
| 401 | Unauthorized | API key is missing, invalid, or has been revoked |
| 404 | Not Found | The agent_id, sip_trunk_id, or call_id does not exist or does not belong to your org |
| 429 | Too Many Requests | Trunk at full capacity. Wait the number of seconds in the Retry-After response header. |
| 502 | Bad Gateway | The Audatec dialer is temporarily unavailable. Retry with exponential backoff. |
| 503 | Service Unavailable | Authentication service temporarily unavailable. Retry after a short delay. |