API
One outbound call from your system — a CRM event, a form, a missed-call callback. A list on a schedule is Campaigns, not this endpoint.
The agent’s Outgoing settings still apply. This request picks the number, the agent, and optional extra context for this call.
Before you call
Section titled “Before you call”- Plan includes Allow Outbound Calls.
- API key with the Calls group.
- A trunk (or VoIP phone) to dial from — Your own carrier / Voice Logica numbers.
- The agent id — from the agent URL on My Agents, or Copy on a campaign row.
First setup — one call, then Calls
Section titled “First setup — one call, then Calls”POST https://api.voicelogica.ai/api/v1/phones/calls/initiate-callx-api-key: YOUR_API_KEYContent-Type: application/jsonResellers: optional x-company-id to act on a subsidiary. Without it, the key’s own company is used.
Send destinationNumber and agentId. Send sipTrunkId or voipPhoneId unless the company already has an outbound route / default trunk that can carry the call — if neither is sent and no trunk can be resolved, the API returns that no active SIP trunk or VoIP phone was specified.
Trunk (usual):
curl -X POST https://api.voicelogica.ai/api/v1/phones/calls/initiate-call \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "sipTrunkId": "your_sip_trunk_id", "destinationNumber": "+14155552671", "agentId": "your_agent_id" }'VoIP phone id still works — the server resolves it to a trunk.
Success is { "callId": "..." }. If the destination is outside 09:00–21:00 local time, you may get "scheduled": true plus scheduleTime and reason. Open Calls and listen.
destinationNumber in E.164 (+14155552671).
What you can send
Section titled “What you can send”Required for an AI outbound call
| Field | What it does |
|---|---|
destinationNumber | Number to call. |
agentId | Agent that talks. Required for AI outbound; optional only for isInternalCall. |
Call source — send one, or rely on the company outbound default
| Field | What it does |
|---|---|
sipTrunkId | Trunk from Telephony → Trunks. Prefer this. |
voipPhoneId | Legacy line id. Resolved to a trunk. |
callerId | E.164 or SIP URI shown to the recipient. Must be a number that trunk is allowed to present. |
This call only
| Field | What it does |
|---|---|
contextForAi | Appended to the system prompt for this call. |
dynamicVariables | String key/value pairs the prompt can use ({{customer_name}}). |
superVariables | Typed values: { placeholder, value, type } — text / number / boolean / date / time. |
metadata | Your tracking. Stored on the call. Keys starting scenario_ are stripped. |
emailAddress | Where to send the summary / recording. |
welcomeMessageOverride | Spoken instead of the agent greeting. |
isWelcomeMessageAIGenerated | AI writes the greeting for this call. |
scheduledAt | ISO date. Call later instead of now. |
maxRetries | 1–3 if busy / no answer / voicemail. Default 3. |
retryDelayMinutes | 30–1440. Default 30. |
additionalPhoneNumbers | Extra numbers on the same request. |
Do not send fromNumber. The public contract is sipTrunkId / voipPhoneId.
Protections (outbound only)
Section titled “Protections (outbound only)”Inbound is never restricted.
- Time (on) — 09:00–21:00 in the destination country’s local time. Outside that, the call is blocked or scheduled. Bypass:
overrideTimeRestriction: true. - Day (on) — weekends / holidays may be blocked by destination country. Bypass:
overrideDayRestriction: true. - Anti-harassment (off unless you send
useAntiHarassmentProtection: true) — max 3 successful and 3 failed calls per number per day, 1 hour between successful calls, max 5 successful per week, no duplicate active/scheduled call. Campaign Allowed test numbers bypass this.
Bypassing time or day rules can break local law. Turn anti-harassment on for any repeated-contact job.
If it fails
Section titled “If it fails”The body is { "error": "<code>", "reason": "<message>" }.
| Code | Meaning |
|---|---|
call_already_in_progress | A live or scheduled call to this number already exists. |
agent_not_found / voip_phone_not_found | Bad id. |
daily_call_limit_reached | 3 successful calls to this number today (anti-harassment). |
failed_call_limit_reached | 3 failed attempts today. |
cooldown_period_active | Wait 1 hour after a successful call to this number. |
weekly_call_limit_reached | 5 successful calls this week. |
call_already_scheduled / failed_to_schedule_call | Schedule conflict. |
callee_opted_out | This number asked not to be called again. |
insufficient_credits / no_seconds_available / no_channels_available / no_concurrent_calls_available | Plan / credits. |
maximum_authentication_attempts_exceeded | Phone deactivated after repeated auth failures. |
402 is billing. 400 is a bad request or a protection. 500 is the calls server — retry later.
Example
Section titled “Example”const response = await fetch('https://api.voicelogica.ai/api/v1/phones/calls/initiate-call', { method: 'POST', headers: { 'x-api-key': 'YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ destinationNumber: '+14155552671', agentId: 'your_agent_id', sipTrunkId: 'your_sip_trunk_id', contextForAi: 'Customer asked about order ORD123', dynamicVariables: { customer_name: 'Ada', order_id: 'ORD123' }, useAntiHarassmentProtection: true, }),});const result = await response.json();if (result.callId) console.log(result.callId);else console.error(result.error, result.reason);Schedule + retries:
{ "destinationNumber": "+14155552671", "agentId": "your_agent_id", "sipTrunkId": "your_sip_trunk_id", "scheduledAt": "2026-09-16T14:30:00Z", "maxRetries": 2, "retryDelayMinutes": 120}scheduledAt is converted to the destination country’s zone. Protections still apply unless you override them.
What “broken” looks like
Section titled “What “broken” looks like”- 400 “no active SIP trunk” — send
sipTrunkId, or add a trunk with numbers and an outbound default. scheduled: truewhen you expected now — destination local time is outside 09:00–21:00.- Agent talks over “hello” — Outgoing Who speaks first, not this payload.
- Call missing on Calls — wrong company (
x-company-id), or the request never returned acallId.
Troubleshooting
Section titled “Troubleshooting”fromNumber used to work
The public body is sipTrunkId or voipPhoneId. Send the trunk id from Telephony → Trunks.
I posted now and got scheduled: true
Time or day restriction. Wait for the window, or set overrideTimeRestriction / overrideDayRestriction only if you are allowed to.
Building something?
Section titled “Building something?”Write developers@voicelogica.ai — extra test credits and help on the integration.
