How to Send Voice with AI

Send AI-driven phone calls with a voice agent and process their webhook results.

Send AI-driven phone calls to one or more recipients and interpret the resulting webhook data.

Prerequisites

  1. Get your api-token and app-id from Integrations > API Token in your LigueLead account.
  2. Create a voice agent (optionally with a voice action attached) and copy its id — it is the voice_agent_id of this endpoint.
  3. Collect recipient phone numbers in Brazilian format without the country code (for example, 11999999999).
  4. A webhook URL to receive call results: the one configured for your app, or a webhook_url passed on the send (see How to Receive Webhooks).

Choosing the engine. engine.version decides which brain drives the call, and it is set when you create the agent — never on this dispatch endpoint, which only takes voice_agent_id. Four are available:

VersionWhat it isVoice tuning
lumen-miniLightweight; ignores action_id — an agent that combines the two is rejected (422)stability/similarity_boost/speed
lumen-1Full cascade engine, supports actionssame
prisma-1Realtime speech-to-speechforbidden (422)
horizon-1Realtime speech-to-speech, native pt-BRforbidden (422)

Each engine accepts only the voices listed under it by GET /v1/voice-agent/voices — a voice from one engine is rejected on another. To change an agent's engine later, send a PUT with the whole new engine object; you do not need to delete and recreate the agent. See "Create a Voice Agent" in the API Reference.

Step 1: Send calls with an AI agent

Endpoint: POST /v1/voice-agent/call

Send a campaign title, the ID of the voice agent that will place the calls, and one to 1,000 recipient phone numbers.

curl -X POST "https://api.liguelead.com.br/v1/voice-agent/call" \
  -H "api-token: YOUR_API_TOKEN" \
  -H "app-id: YOUR_APP_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Appointment reminders",
    "voice_agent_id": "f9e8d7c6-b5a4-4321-8fed-cba987654321",
    "phones": ["11999999999", "11888888888"]
  }'

Required fields

FieldTypeConstraintsDescription
titlestring1–200 charactersCampaign title.
voice_agent_idstringUUID; must belong to your accountID of the voice agent that drives the calls.
phonesarray1–1,000 recipientsPhone numbers to dial. Each item can be a phone number string or an object with phone and optional call_context.

Expected response

{
  "campaign_id": "corr-abc123-def456-ghi789",
  "phones_count": 2
}

A 202 Accepted response means the calls were accepted and enqueued for processing. Use the campaign_id to correlate the campaign with its status webhooks.

Webhook After Each Call

When a call ends, the platform sends a webhook to the webhook_url of the send or, when the send carried none, to the URL configured for your app, with campaign.type: "voice_ai". It always carries the action the agent executed, plus the transcript and the recording URL when the call produced them.

The payload, the field reference and the list of action_executed values live in the Voice AI tab of How to Receive Webhooks — the same page that documents the webhooks of every other channel.

Optional: Add context for an individual recipient

Pass a phone object with call_context when the agent needs details that apply only to that recipient. call_context is optional and nullable, and always stored as a single line: every whitespace run — line breaks (\n, \r\n, \r) and tabs included — is collapsed into a single space and both ends are trimmed. The 1–1500 character limit applies to that normalized value, so redundant whitespace never counts against it — an empty string, a value made only of whitespace, or one still longer than 1500 characters after normalization is rejected with 422. Accents and punctuation travel exactly as sent, with one exception: a single quote inside the text (Maria D'Ávila) is replaced by the typographic apostrophe ’ (U+2019). It reads the same to the voice agent, and it is what keeps the value from breaking the dial string used to place the call, where the context travels quoted. Plain strings and objects can be freely mixed in the same phones array (a plain string is equivalent to omitting call_context).

curl -X POST "https://api.liguelead.com.br/v1/voice-agent/call" \
  -H "api-token: YOUR_API_TOKEN" \
  -H "app-id: YOUR_APP_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Appointment reminders",
    "voice_agent_id": "f9e8d7c6-b5a4-4321-8fed-cba987654321",
    "phones": [
      {
        "phone": "11999999999",
        "call_context": "Name: Maria; appointment: 12 August at 14:30."
      }
    ]
  }'

Optional: Configure retries

Provide retry_attempts to enable automatic re-dialing of unanswered calls. The remaining retry fields apply only when you provide retry_attempts.

FieldTypeConstraintsDescription
retry_attemptsinteger1–3Number of re-dial attempts for unanswered calls. Retries are disabled when omitted.
retry_interval_mininteger5–180Minutes between retry attempts.
retry_end_timestringHH:MM; 08:00–21:45 in America/Sao_Paulo; at least 10 minutes in the futureCutoff time for retry attempts.

Optional: Receive the results at another URL

Provide webhook_url to have the results of these calls delivered somewhere other than the app's webhook URL.

FieldTypeConstraintsDescription
webhook_urlstringUp to 512 charactersURL that receives the result of these calls instead of the app's webhook URL, called exactly as written (query string included); see How to Receive Webhooks.

Limits

ResourceLimit
Phone numbers per request1000
title length1–200 characters
retry_attempts1–3
retry_interval_min5–180 minutes
retry_end_time window08:00–21:45 (America/Sao_Paulo)
call_context length1–1500 characters (after whitespace normalization)
webhook_url length512 characters
Request body size250 KB

Troubleshooting

IssueWhat to check
404 responseConfirm that voice_agent_id exists and belongs to your account.
422 responseCheck the UUID, campaign title, recipient list, retry values, any call_context values, and webhook_url.
413 Payload Too Large responseReduce the number of recipients or the size of their call_context values. The request body limit is 250 KB.
No DTMF data in the webhookExpected behavior: AI agent calls do not collect DTMF, so campaign.dtmf is never included.

The exact messages the API returns:

CodeMessageCause
404Voice agent with ID <id> not found or does not belong to clientThe voice_agent_id does not exist for this client.
422Voice agent ID must be a valid UUIDvoice_agent_id is not a valid UUID.
422Title is requiredEmpty title.
422Title must be at most 200 characterstitle longer than 200 characters.
422At least one phone number is requiredEmpty phones array.
422Maximum 1000 phone numbers allowedMore than 1000 numbers in one request.
422Phone number cannot be emptyAn entry in phones is an empty string, or its phone is empty.
422Each phones entry must be a string or an object like { phone, call_context }An entry in phones is neither a string nor an object of that shape.
422call_context cannot be emptycall_context is empty, or only whitespace once normalized.
422call_context must be at most 1500 characterscall_context longer than 1500 characters after normalization.
422retry_end_time must be in HH:MM formatretry_end_time not in HH:MM.
422retry_end_time must be between 08:00 and 21:45Cutoff time outside the allowed window.
422retry_end_time must be at least 10 minutes from now (America/Sao_Paulo)Cutoff time too close to now.
422webhook_url cannot exceed 512 characterswebhook_url longer than 512 characters.
422webhook_url must be a valid URLwebhook_url is not a URL.
422webhook_url must use http or httpswebhook_url uses another protocol.
422webhook_url hostname cannot contain underscoresThe hostname of webhook_url has an underscore.
422webhook_url must have a public hostnameThe hostname of webhook_url has no dot, so it is not a public name.
422webhook_url cannot point to a private or reserved addresswebhook_url points to localhost or a private or reserved IP address.
401Authorization token missing, Authorization app id missing, Authorization failed, …Missing, invalid or blocked api-token/app-id, or an inactive app.
413Payload too large. Maximum allowed size is 250 KB.The JSON body exceeded 250 KB. Send fewer recipients, or shorten their call_context.

End-to-End Example

Create a scheduling action, attach it to an agent, and use that agent to dispatch calls. Each step returns the ID required by the next step.

1. Create the scheduling Action

A voice action gives the agent the ability to execute an operation during a call. Use the returned action ID as action_id in step 2.

curl -X POST "https://api.liguelead.com.br/v1/voice-action" \
  -H "api-token: YOUR_API_TOKEN" \
  -H "app-id: YOUR_APP_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Schedule demonstration",
    "type": "SCHEDULE_EVENT",
    "provider": "microsoft",
    "credentials": {
      "tenant": "YOUR_TENANT_ID",
      "client_id": "YOUR_CLIENT_ID",
      "client_secret": "YOUR_CLIENT_SECRET"
    },
    "config": {
      "calendar_id": "primary",
      "timezone": "America/Sao_Paulo",
      "destination": "[email protected]"
    }
  }'
{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}

Sending an SMS instead

To have the agent text the recipient during the call, create a SEND_SMS action. The text is fixed when you create the action: up to 1600 characters, checked against the same blocked words as POST /v1/sms. It goes to the number being called and is charged to your app like any SMS.

curl -X POST "https://api.liguelead.com.br/v1/voice-action" \
  -H "api-token: YOUR_API_TOKEN" \
  -H "app-id: YOUR_APP_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Send the proposal link",
    "type": "SEND_SMS",
    "provider": "internal",
    "message": "Hi! Here is the link to your proposal: https://example.com/p/123"
  }'

To change the text later, send { "message": "..." } to PUT /v1/voice-action/{id}. When the agent sends the SMS, the call webhook carries action_executed: "send_sms", and the SMS itself reports its delivery in its own webhook, with campaign.type: "sms" and campaign.source: "voice_ai".

If you follow this path, step 2 changes too: use this action's id as action_id, and replace the scheduling instructions in the agent's prompt with ones about the SMS. For example: "You are a sales assistant. Explain the product briefly and, when the recipient is interested, offer to send the proposal link by SMS. Send it only if they agree."

2. Create the Voice Agent with the Action

Create a sales agent that schedules a demonstration. Choose the engine here, as described in the Choosing the engine note; use the action ID from step 1 as action_id.

curl -X POST "https://api.liguelead.com.br/v1/voice-agent" \
  -H "api-token: YOUR_API_TOKEN" \
  -H "app-id: YOUR_APP_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Demonstration Scheduling Agent",
    "prompt": "You are a sales assistant. Explain the product briefly, qualify interest, and schedule a demonstration when the recipient agrees. Use the scheduling action to register the appointment.",
    "greetings": "Hello! I am calling to help you schedule a product demonstration. Do you have a minute?",
    "engine": {
      "version": "lumen-1",
      "voice_id": "RGymW84CSmfVugnA5tvA"
    },
    "action_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
  }'
{
  "id": "f9e8d7c6-b5a4-4321-8fed-cba987654321"
}

3. Dispatch the calls

Use the agent ID from step 2 to send the calls. Any item in phones can be a { phone, call_context } object to provide recipient-specific context; see Optional: Add context for an individual recipient.

curl -X POST "https://api.liguelead.com.br/v1/voice-agent/call" \
  -H "api-token: YOUR_API_TOKEN" \
  -H "app-id: YOUR_APP_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Demonstration scheduling",
    "voice_agent_id": "f9e8d7c6-b5a4-4321-8fed-cba987654321",
    "retry_attempts": 2,
    "phones": [
      "11999999999",
      {
        "phone": "11888888888",
        "call_context": "Name: Maria; interested in a demonstration next week."
      }
    ]
  }'
{
  "campaign_id": "corr-abc123-def456-ghi789",
  "phones_count": 2
}

Did this page help you?