Developers
API: trigger outbound calls
Place calls from your own systems.
What the trigger API does
The trigger API places a real outbound call with one of your published agents. You send a JSON body, the agent resolves its phone numbers and prompt variables from it, and the platform hands the call to your carrier. This is how a CRM, a job queue or a backend workflow starts a conversation without anyone opening the console.
It is a dispatch API, not a call-control API. You start the call, and the result comes back later through the post-call webhook.
Before you start
- The agent must be published and its status must be Active. A draft cannot be triggered, and a paused agent will refuse the call.
- The agent's Call direction must be outgoing. An incoming-only agent cannot be dispatched this way.
- The from-number must be imported into the workspace under a carrier that supports outbound dialling. Import numbers under Phone Numbers. A SIP-only number cannot place outbound calls.
- The workspace needs a positive balance and enough headroom under its limits. See Limits & Quotas.
Endpoint
POST https://api.voicesquad.ai/v1/agents/{agent_uuid}/triggeragent_uuid is the agent's identifier. The console's Copy API URL action on an outgoing agent gives you this exact URL. Rather than assembling the URL by hand, copy it: on the Agents list, the row menu for an outgoing agent has Copy API URL, and inside the agent editor the Conversation Trigger accordion has an Outbound API section with a Copy cURL helper that gives you a ready to run request for this agent.
Authentication
The endpoint uses HTTP Basic authentication with your workspace API credentials. The auth ID is the username and the auth token is the password.
Authorization: Basic base64(YOUR_AUTH_ID:YOUR_AUTH_TOKEN)Find the pair in the console under Settings, then General, in the API Credentialssection. There is one active pair per workspace, created with the workspace. An admin can rotate it, and rotation revokes the previous pair immediately, so deploy the new values before you rotate.
The request body
The body is free-form JSON, and a form-encoded body is accepted too. Every key in it becomes a call variable, usable anywhere the agent accepts variables as {{key}}: the universal prompt, the welcome message, the human transfer destination, the end call instructions, and the outbound number templates.
That last one is how the call gets its numbers. In the agent's Conversation Trigger accordion, Outgoing call to and Outgoing call from are each either a literal number in E.164 form or a variable such as {{to_number}}. Whatever template is configured is resolved against the body of your request. So if the agent is configured to call {{to_number}}, your body must carry a to_number key.
Payload schema validation
The agent's payload schema, defined in the editor's payload editor, is validated before anything is dispatched. Each entry has a key, a type, a required flag, a description and an example. The rules are:
- A key marked required must be present and must not be empty.
- A key typed as a number must parse as a number.
- A key typed as a boolean accepts a real boolean, or the strings
true,false,0and1. - Keys that are not in the schema are allowed through and still become variables. The schema is a floor, not a whitelist.
If validation fails, nothing is dialled and you get a single error listing every violation at once, so you can fix them in one pass rather than one request at a time.
Example request
curl -X POST \
"https://api.voicesquad.ai/v1/agents/efa64971-0000-0000-0000-000000000000/trigger" \
-u "YOUR_AUTH_ID:YOUR_AUTH_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"to_number": "+14155551234",
"customer_name": "Alex Mercer",
"invoice_id": "INV-20481",
"amount_due": 149.5,
"is_repeat_customer": true
}'Here the agent is configured to dial {{to_number}}, and its prompt can greet the caller by {{customer_name}} and quote {{invoice_id}} without any of that being hardcoded into the agent.
The success response
Every response is wrapped in the same envelope, with the useful part under data.
{
"status_code": 200,
"error_code": null,
"message": "OK",
"api_id": "3f2a91c4-0000-0000-0000-000000000000",
"data": {
"session_uuid": "9c15b8de-0000-0000-0000-000000000000",
"carrier_call_id": "CA00000000000000000000000000000000",
"carrier": "twilio",
"status": "dispatched"
}
}session_uuididentifies the call session. It is the same call you will see in Conversations, and the same id the post-call webhook reports.carrier_call_idandcarrieridentify the call at your telephony provider.statusisdispatched.
Errors
Errors use the same five envelope keys, with error_code filled in and message explaining the specific failure. Branch on error_code, not on the message text.
| HTTP | error_code | What it means |
|---|---|---|
| 404 | AGENT_NOT_FOUND | No published version of this agent exists, or the UUID is wrong. A never-published draft looks like this. |
| 401 | TRIGGER_CREDENTIALS_NOT_CONFIGURED | The workspace has no API credentials to authenticate against. Create them under Settings, General. |
| 401 | TRIGGER_CREDENTIALS_INVALID | The auth ID or auth token does not match. Most often a rotated pair still in use somewhere. |
| 409 | AGENT_NOT_ACTIVE | The agent exists and is published but is not Active. A paused agent returns this until you resume it. |
| 409 | AGENT_NOT_OUTBOUND | The agent is configured for incoming calls only, so it cannot be dispatched outbound. |
| 422 | TRIGGER_PAYLOAD_INVALID | The body failed payload schema validation. The message lists every violation, joined by semicolons. |
| 400 | TRIGGER_MISSING_TO | No destination number could be resolved. Usually the agent dials a variable your body did not include. |
| 400 | FROM_NUMBER_NOT_IMPORTED | The resolved from-number is not imported into this workspace under a carrier that can dial out. |
| 402 | INSUFFICIENT_BALANCE | The workspace balance cannot cover the call. Recharge under Billing. |
| 429 | CONCURRENCY_LIMIT | The workspace already has its maximum number of calls in flight. Retry shortly. |
| 429 | DAILY_LIMIT | The daily call limit has been reached. It resets at midnight in the workspace timezone. |
| 429 | DAILY_SPEND_CAP | The daily spend cap has been reached. It resets at midnight in the workspace timezone. |
| 502 | OUTBOUND_DISPATCH_FAILED | The carrier refused or failed to accept the call. Safe to retry. |
| 422 | VALIDATION_ERROR | The request itself was malformed, for example invalid JSON. |
Throttling
Your workspace safety caps are the throughput levers you control. The three that turn into a 429 are Max concurrent calls, Daily call limit and Daily spend cap, all configured under Settings, Limits & Quotas. The two daily caps reset at midnight in the workspace timezone.
Build for this rather than against it. If you are dialling a list, treat CONCURRENCY_LIMIT as a signal to slow down and retry with backoff, and treat DAILY_LIMIT and DAILY_SPEND_CAP as a signal to stop for the day, since retrying before the reset will only fail again.
Response envelope and correlation
Every JSON response, success or failure, has the same five keys: status_code, error_code, message, api_id and data. The api_id is a correlation id for the request. If you send an X-Api-Id header, it is echoed back in both the body and the X-Api-Id response header. If you do not, one is generated for you.
Log it. When you need help with a specific request, the api_id is what identifies it.
What happens next
- Your request is validated, the call is dispatched to the carrier, and you get
dispatchedback immediately. - A call session is created. It appears in Conversations and you can watch it live.
- When the carrier reports the call answered, audio is bridged into the agent and the conversation runs.
- On hangup, the call is finalised: duration, cost and usage are rolled up, then the post-call evaluation runs.
- Once evaluation completes, the post-call webhook fires with the transcript, summary and extracted variables.
Inbound agents
Incoming agents are not started from application code. Each has its own voice webhook URL, which you paste into the number's configuration at your carrier. When someone dials that number, the carrier calls the URL, and the platform answers with the instructions that bridge the caller into the agent.
You never call that URL yourself, and it does not take an API credential. Its only client is your telephony provider. Everything else about an incoming agent, including its knowledge, its tools and its transcripts, works exactly as it does for an outgoing one.