VaatAI Developer API
Place phone calls that run your voice agents, read their transcripts and recordings, seed each call with your own variables, and get signed webhooks as calls progress — all over a simple, versioned REST API.
All requests are HTTPS and authenticated with an API key sent as a bearer token. Responses are JSON. Jump to the live tester to run any endpoint with your own key.
Authentication
Every request must carry your API key in the Authorization header:
Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxx
Mint keys — and choose exactly what each key can do — in the dashboard under Settings → Developer API. The raw key is shown once at creation; store it securely. A key belongs to one workspace and can only ever see that workspace's data.
sk_live_ key in browser or mobile
client code — call the API from your server. Revoke a leaked key immediately in the dashboard.Scopes
Each key is granted a set of scopes. A request that needs a scope the key doesn't hold returns
403. Grant the minimum a given integration needs.
| Scope | Grants |
|---|---|
calls:read | List/read calls, transcripts and recordings |
calls:write | Place calls and hang them up |
agents:read | List the agents a call can run |
numbers:read | List the phone numbers you can call from |
webhooks:write | Create, list and delete webhook endpoints |
Quickstart
Place a call in one request. The agent runs when the callee answers.
# Place an outbound call curl https://voxa.datavonix.com/api/public/v1/calls \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "agent_id": "<your-agent-id>", "to": "+14155550123", "variables": { "customer_name": "Asha" } }'
# → 202 Accepted { "id": "CA9f2b…", // use this to track the call "status": "dialing", "to": "+14155550123", "variables": { "customer_name": "Asha" } }
Then poll GET /calls/{id} or subscribe to
webhooks to follow it to completion.
▶ Try it live
Paste an API key and run real requests against the live API, right here. Nothing is sent anywhere except the API itself; your key stays in this browser.
Place a call
Starts an outbound call that runs agent_id when answered. Returns 202
immediately; the call runs in the background. Track it via GET /calls/{id}
or webhooks.
| Field | Type | Notes |
|---|---|---|
agent_id | string | Required. The agent to run — see GET /agents. |
to | string | Required. Destination in E.164, e.g. +14155550123. |
from | string | One of your numbers. Defaults to your first number for the provider. |
provider | string | twilio (default) or plivo. |
variables | object | Predefined agent variables — see below. |
metadata | object | Opaque; echoed back on webhooks for your own correlation. |
The returned id (the carrier call id) is what you use everywhere else in the API.
Predefined agent variables
Pass variables to seed values the agent can use during the call. They become available:
- in prompts and messages as
{global.customer_name} - in custom-code nodes via
global_variables['customer_name']andoutbound_customer_data
{
"agent_id": "…", "to": "+14155550123",
"variables": {
"customer_name": "Asha",
"appointment_time": "3 PM",
"clinic": "City General Hospital"
}
}
{global.<key>}),
up to 50 per call. Values are strings the agent reads at answer time.List calls
Newest first. Query params: agent_id, status (active|completed),
limit (1–200), offset. Returns { data, limit, offset, count }.
Get a call
Full detail including the transcript. Accepts the carrier id or the internal UUID.
{
"id": "CA9f2b…", "status": "completed", "provider": "plivo",
"direction": "outbound", "from": "…", "to": "…",
"agent_id": "…", "agent_name": "…",
"started_at": "…", "ended_at": "…", "duration_seconds": 13,
"message_count": 2, "has_recording": true,
"transcript": [ { "role": "agent", "text": "…", "at": "…" } ]
}
Get transcript
Just the turn-by-turn transcript: { id, message_count, transcript }.
Get recording
The stereo WAV tape (left = caller, right = agent), streamed back or redirected to a
time-limited URL depending on server config. 404 if the call has no recording.
Hang up a call
Ends a live call now. Safe no-op (200) if the call already ended.
List agents
The agents in your workspace a call can run: [{ id, name, type, created_at }].
List numbers
Phone numbers you can place calls from: [{ id, phone_number, provider, status, agent_id }].
Webhooks
Register endpoints to receive call-lifecycle events. Manage them in the dashboard
(Settings → Developer API) or via the API with the webhooks:write scope.
Events we deliver:
| Event | Fires when |
|---|---|
call.initiated | the API accepted your place-call request (dialing started) |
call.answered | the call connected and the agent went live |
call.completed | the call ended normally (includes transcript) |
call.failed | the call could not be placed / did not connect |
Each delivery is a JSON envelope:
{
"id": "<delivery-uuid>",
"event": "call.completed",
"created_at": "2026-08-21T13:38:09Z",
"data": { /* the call object, as in GET /calls/{id} */ }
}
Verifying signatures
Every delivery is signed so you can trust it came from us. Compute an HMAC-SHA256 of the raw request body keyed by your endpoint's secret and compare to the header:
// Node.js (Express) const crypto = require('crypto'); function verify(req, secret){ const sig = req.headers['x-voxa-signature']; const mac = 'sha256=' + crypto .createHmac('sha256', secret) .update(req.rawBody) .digest('hex'); return crypto.timingSafeEqual( Buffer.from(sig), Buffer.from(mac)); }
# Python (Flask) import hmac, hashlib def verify(request, secret): sig = request.headers.get('X-Voxa-Signature','') mac = 'sha256=' + hmac.new( secret.encode(), request.get_data(), hashlib.sha256).hexdigest() return hmac.compare_digest(sig, mac)
Errors
Standard HTTP status codes with a JSON { "detail": "…" } body.
| Code | Meaning |
|---|---|
401 | Missing or invalid API key |
402 | Workspace out of credits |
403 | Key lacks the required scope |
404 | Call / agent / number not found in your workspace |
409 | Not placeable (e.g. number on your Do-Not-Call list) |
422 | Invalid request body |
429 | Rate limit exceeded |
Rate limits
Up to 120 requests per minute per key. Exceeding it returns 429 — back off and retry.