Start a Call
Starts an outbound call to a lead — either with a stored agent, or with an agent that exists only for this one call (an "inline"/"one-time" agent).
Endpoint
POST /api/calls/initiate
Authentication
Requires a valid Bearer JWT. The
call is associated with the project_id from the token.
Request body
Use exactly one of the two agent fields — never both:
| Field | Type | Required | Description |
|---|---|---|---|
lead_id | string | yes | ID of the lead to call. |
agent_id | string | no | ID of a stored agent. |
agent | object | no | Configuration for a one-time ("inline") agent. See below. |
If neither is given, the call uses the phone number's default agent.
Variant A: stored agent
{
"lead_id": "123e4567-e89b-12d3-a456-426614174000",
"agent_id": "456e7890-e89b-12d3-a456-426614174000"
}
Variant B: inline agent (one-time call)
For a call whose script exists only for this one call — without creating, polling, and deleting an agent around it.
{
"lead_id": "123e4567-e89b-12d3-a456-426614174000",
"agent": {
"name": "One-time call: rent increase, flat 3B",
"template_agent_id": "456e7890-e89b-12d3-a456-426614174000",
"ttl_minutes": 120,
"configuration": {
"agentSettings": {
"firstMessage": "Hello, this is an AI assistant from Muster Property Management. Am I speaking with Ms. {{last_name}}?",
"prompt": "You are delivering a notice: the rent for flat 3B increases by 42 euros starting 2027-02-01. Do not answer follow-up questions — note them and say the management office will get back to her."
}
}
}
}
Fields inside agent:
| Field | Type | Required | Description |
|---|---|---|---|
name | string | no | Label for the CRM and logs. Defaults to a dated "One-time call …" name. Max 255 characters. |
configuration | object | yes* | The agent configuration. agentSettings.firstMessage and agentSettings.prompt are required — on their own without template_agent_id, or together with it (see below). |
template_agent_id | string | no | ID of a stored agent whose configuration is the merge base. Voice, booking, transfer and provider settings carry over; only the script changes. |
ttl_minutes | integer | no | Minutes the agent outlives the call before it is deleted. Default 120, range 5–1440. Has to outlive post-call processing (transcript, summary, outcome, webhook). |
* Without template_agent_id, agentSettings.firstMessage and
agentSettings.prompt must be set directly in configuration. With
template_agent_id, only the keys that should change need to be sent — the
rest is inherited from the template.
Behavior
- Mutually exclusive. Sending
agent_idandagenttogether returns400. - An inline agent is stored. Even a one-time agent is created as a real
agent row, because post-call processing (summary, outcome classification,
customer webhook, email notification) reads the agent configuration again.
It runs through the same gate as
POST /api/agents(EU AI Act disclosure in the first message, summary-prompt length limit, language permission, staff-only provider fields) — an inline agent is a shortcut, not a second door into the configuration. - EU AI Act disclosure:
agentSettings.firstMessagemust disclose that an AI assistant is speaking (e.g. "… an AI assistant from …"). Omitting it is a400. - Automatic deletion (TTL): The inline agent expires after
ttl_minutesand is collected by a background reaper. While it exists it does not show up in the agent list and does not count against the AI-assistant plan limit. template_agent_id: The template's configuration is the merge base; the request'sconfigurationis merged over it key by key. An explicit JSONnullremoves an inherited block (e.g. to turn off booking or transfer for this one call). Voice, booking, transfer, provider settings and the after-call email notification are inherited along with it.- A failed dial attempt leaves the inline agent to expire rather than deleting it immediately — an error here doesn't prove nothing was dialed.
Success response
{
"success": true,
"message": "Call initiated successfully",
"provider_call_id": "call-id-123",
"agent_id": "9f1c0f7e-2a44-4f9e-9a0b-2b7c1d3e4f50"
}
agent_id is only present for an inline agent — it is the id of the one-time
agent that was minted. Use it to attribute the call activity, or to delete it
yourself instead of waiting for expiry. With a stored agent_id or the
default agent, this field is omitted from the response.
Error responses
Both agent_id and agent sent
{
"success": false,
"message": "Send either agent_id or agent, not both: agent_id names a stored agent, agent defines a one-time one.",
"provider_call_id": null
}
Missing EU AI Act disclosure in the first message
{
"success": false,
"message": "First message must disclose that the caller is an AI (EU AI Act Art. 50). Add an AI disclosure to the start of the agent's first message, e.g. '… ein KI-Assistent von …' or '… an AI assistant from …'.",
"agent": null
}
agentSettings.firstMessage or agentSettings.prompt missing
{
"success": false,
"message": "agent.configuration.agentSettings.prompt is required and must not be empty",
"provider_call_id": null
}
Unknown template_agent_id
{
"success": false,
"message": "template_agent_id 456e7890-e89b-12d3-a456-426614174000 not found in this project",
"provider_call_id": null
}
Insufficient balance / not enough minutes
{
"success": false,
"message": "Insufficient minutes to start this call",
"provider_call_id": null
}
Database or provider error
{
"success": false,
"message": "Failed to initiate call: ...",
"provider_call_id": null
}