Place calls via API

About 5 minutesUpdated July 2026

After this page, your backend can trigger a real phone call with one POST. Qalyb dials the number, runs the agent, and reports back via the API and webhooks when the call completes.

Before you start, make sure you have:
A live API key — see Authentication
A configured agent — see Create agents via API
A destination phone number in E.164 format (e.g. +971501234567)

Place the call

One POST does it. The endpoint is scoped to the agent that will run the call: POST /v1/agents/{id}/calls.

curl · bash
curl -X POST https://api.qalyb.ai/v1/agents/agt_abc123/calls \
  -H "Authorization: Bearer sk-live-..." \
  -H "Content-Type: application/json" \
  -d '{
    "phoneNumber": "+971501234567",
    "variables": {
      "customer_name": "Layla",
      "appointment_window": "Sunday afternoon"
    }
  }'

From the TypeScript SDK:

place-call.ts · ts
import { Qalyb } from '@qalyb/sdk';

const qalyb = new Qalyb({ apiKey: process.env.QALYB_API_KEY! });

const call = await qalyb.agents.startCall('agt_abc123', {
  phoneNumber: '+971501234567',
  variables: {
    customer_name: 'Layla',
    appointment_window: 'Sunday afternoon',
  },
});

console.log(call.id, call.status);

What you get back

You get back a call record immediately. The call is now queued — Qalyb dials within a second or two and transitions through ringing, in_progress, then completed or failed.

json
{
  "id": "call_abc123",
  "agentId": "agt_abc123",
  "phoneNumber": "+971501234567",
  "status": "queued",
  "createdAt": "2026-05-09T12:34:56Z"
}

Fetch a call later

GET /v1/calls/{id} returns the latest status, duration, and (when available) the transcript turns.

curl · bash
curl https://api.qalyb.ai/v1/calls/call_abc123 \
  -H "Authorization: Bearer sk-live-..."

List calls for an agent

GET /v1/agents/{id}/calls returns recent calls scoped to the agent. Filter with status and limit (max 100).

curl · bash
curl "https://api.qalyb.ai/v1/agents/agt_abc123/calls?limit=20" \
  -H "Authorization: Bearer sk-live-..."

Polling vs. webhooks

For one-off scripts, polling GET /v1/calls/{id} works fine. For production, register a webhook on call.completed and call.failed instead — much less noisy and you get the transcript URL in the same payload.

Variables and personalization

The variables object is interpolated into the agent's system prompt with {{name}} placeholders. Use it to inject anything dynamic — customer names, order IDs, dates — without forking your agent for every campaign.

Common errors

StatusMeaning
400Phone number isn't valid E.164, or the agent isn't a voice agent.
401API key missing or revoked.
402Account doesn't have enough credit for the destination country.
404Agent ID doesn't exist in this workspace.
Was this guide helpful?