Vyora API
Trigger AI voice calls and receive real-time events. One endpoint. Works with any backend, Zapier, or Make.
One endpoint
POST /v1/calls to trigger any call instantly
Real-time events
Receive transcripts and analysis via webhook
API key auth
Simple header-based auth, no OAuth complexity
Base URL
https://api.vyora.aiAuthentication
All requests require an X-API-KEY header. Generate your key from Settings → Integrations.
X-API-KEY: vya_live_your_key_here
Keep your API key secret. Never expose it in client-side JavaScript or public repos. If compromised, revoke it immediately from Settings and generate a new one.
Rate limits
60 / minutePlan dependent5 secondsWhen rate limited, the API returns 429 Too Many Requests. Use exponential backoff before retrying.
// Exponential backoff — retry up to 3 times
async function callWithRetry(payload, retries = 3) {
for (let i = 0; i < retries; i++) {
const res = await fetch('https://api.vyora.ai/v1/calls', { ... });
if (res.status !== 429) return res;
await new Promise(r => setTimeout(r, Math.pow(2, i) * 1000));
}
throw new Error('Rate limit exceeded after retries');
}List agents
/v1/agentsReturns all active agents in your workspace. Use the id or name when triggering calls. Agent IDs are also shown in your dashboard under Agents → copy icon.
limitintegeroffsetintegerRequest
curl https://api.vyora.ai/v1/agents \ -H "X-API-KEY: vya_live_your_key_here"
Paginated request
curl "https://api.vyora.ai/v1/agents?limit=10&offset=20" \ -H "X-API-KEY: vya_live_your_key_here"
Response
{
"agents": [
{ "id": "abc123-...", "name": "Home Loan Agent", "language": "hi-IN", "agent_type": "outbound" },
{ "id": "def456-...", "name": "Admission Enquiry", "language": "en-IN", "agent_type": "outbound" }
],
"total": 2,
"limit": 50,
"offset": 0
}Get call
/v1/calls/:call_idFetch the full record for a single call — status, transcript, recording URL, and AI analysis. Use the call_id returned by POST /v1/calls. Note: transcript and analysis are only available after all_processing_completed fires.
Request
curl https://api.vyora.ai/v1/calls/abc123xyz \ -H "X-API-KEY: vya_live_your_key_here"
Response
{
"call_id": "abc123xyz",
"agent_id": "def456-...",
"agent_name": "Home Loan Agent",
"contact_name": "Rahul Sharma",
"phone_number": "+919876543210",
"status": "completed",
"direction": "outbound",
"duration_seconds": 47,
"recording_url": "https://cdn.vyora.ai/recordings/abc123.mp3",
"transcript": [
{ "bot": "Hi Rahul, I'm calling about your home loan inquiry..." },
{ "user": "Yes, I was interested in learning more..." }
],
"analysis": {
"summary": "Lead expressed strong interest, asked about EMI options.",
"classification": "Interested"
},
"called_at": "2026-05-24T10:30:00Z"
}{ "error": "Call not found" }Also returned if the call belongs to a different workspace — IDs are not guessable but access is always scoped to your API key.
Polling for completion
If you need synchronous-style behaviour without webhooks, poll until status is completed and analysis is non-null. Webhooks are more efficient for production use.
async function waitForAnalysis(callId, apiKey, maxWaitMs = 60000) {
const start = Date.now();
while (Date.now() - start < maxWaitMs) {
const res = await fetch(`https://api.vyora.ai/v1/calls/${callId}`,
{ headers: { 'X-API-KEY': apiKey } });
const call = await res.json();
if (call.status === 'completed' && call.analysis) return call;
await new Promise(r => setTimeout(r, 3000)); // poll every 3s
}
throw new Error('Timed out waiting for call analysis');
}Trigger a call
/v1/callsStarts an outbound AI call immediately. The agent will call the number, run the conversation, and deliver results via webhook.
curl -X POST https://api.vyora.ai/v1/calls \
-H "X-API-KEY: vya_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"phone_number": "+919876543210",
"agent_name": "Home Loan Agent",
"custom_args": {
"name": "Rahul Sharma",
"product": "Home Loan"
}
}'Request body
phone_numberrequiredstringagent_namestringagent_idstringcustom_argsobjectResponse
{
"call_id": "abc123xyz",
"status": "registered"
}{
"error": "Insufficient credits"
}Webhooks
Register a webhook URL in Settings → Integrations. Vyora will POST to that URL after each call event. Your endpoint must respond with 200 within 5 seconds.
Request headers
Every webhook request includes these headers:
POST https://your-server.com/webhook Content-Type: application/json X-Vyora-Event: call_completed X-Vyora-Signature: sha256=a4b3c2d1e0f9... User-Agent: Vyora-Webhooks/1.0
X-Vyora-EventEvent name, e.g. call_completed
X-Vyora-SignatureHMAC-SHA256 signature for verification
User-AgentAlways Vyora-Webhooks/1.0
Signature verification
Every webhook includes an X-Vyora-Signature header — an HMAC-SHA256 of the raw request body signed with your webhook secret. Find your secret in Settings → Integrations. Always verify the signature before processing the event to prevent spoofed requests.
// Express.js — verify signature before processing
const crypto = require('crypto');
function verifySignature(rawBody, signature, secret) {
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
// Use timingSafeEqual to prevent timing attacks
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const sig = req.headers['x-vyora-signature'];
const secret = process.env.VYORA_WEBHOOK_SECRET;
if (!sig || !verifySignature(req.body, sig, secret)) {
return res.status(401).json({ error: 'Invalid signature' });
}
const body = JSON.parse(req.body);
const event = req.headers['x-vyora-event'];
if (event === 'call_completed') {
console.log(`Call ${body.call_id} ended — status: ${body.status}`);
}
if (event === 'all_processing_completed') {
console.log('Analysis ready:', body.analysis?.summary);
}
res.status(200).json({ received: true });
});Always use timing-safe comparison (crypto.timingSafeEqual / hmac.compare_digest) to prevent timing attacks. Never compare signatures with ===.
Example payload
{
"event": "call_completed",
"call_id": "abc123xyz",
"phone_number": "+919876543210",
"contact_name": "Rahul Sharma",
"agent_id": "your-agent-id",
"agent_name": "Home Loan Agent",
"status": "completed",
"direction": "outbound",
"duration_seconds": 47,
"recording_url": "https://cdn.vyora.ai/recordings/abc123.mp3",
"transcript": [
{ "bot": "Hi Rahul, I'm calling about your home loan inquiry..." },
{ "user": "Yes, I was interested in learning more..." }
],
"analysis": {
"summary": "Lead expressed strong interest, asked about EMI options.",
"classification": "Interested"
},
"campaign_id": "campaign_456",
"custom_args": { "name": "Rahul Sharma", "product": "Home Loan" },
"called_at": "2026-05-24T10:30:00Z",
"timestamp": "2026-05-24T10:31:15Z"
}Event types
call_startedcall_completedall_processing_completedSelect which events to receive in Settings → Integrations. Unsubscribed events are not delivered.
Error codes
Ready to build?
Generate your API key from the dashboard and make your first call in under 2 minutes.