Calls

Every connected conversation is a call with its own ID. Dial sessions create calls for you. You can also place a single call to one number, act on a live call from your app, and read the record afterwards.

Place a single call

A single call dials one number for an agent who is already connected. It runs the same pre-dial checks, detection and recording as a dial session. Use it for click-to-call and scheduled callbacks.

POST/v1/calls

ParametersTypeDescription
torequired string The number to call, E.164.
from string A caller ID you own. Leave it out and set caller_id_pool to have one picked for the lead.
caller_id_pool string Pool to pick the caller ID from.
agent_idrequired string The connected agent who takes the call.
lead_id string Links the call to a lead for calling hours, consent and callback routing.
amd boolean Answering machine detection. Default true.
amd_on_machine hangup | notify What happens when detection hears a machine. Default hangup.
recording smart | off Default smart.
POST/v1/calls
curl https://api.liveleg.dev/v1/calls \
  -H "Authorization: Bearer $LIVELEG_API_KEY" \
  -H "Idempotency-Key: crm-88214-call-1" \
  -d to=+13035550112 \
  -d caller_id_pool=pool_local_presence \
  -d agent_id=agt_207 \
  -d lead_id=led_9Pq1 \
  -d amd=true \
  -d recording=smart

Control a live call

Each action is its own endpoint on the call. It takes effect right away and sends an event when it completes. The agent's browser or SIP phone can do the same through the Voice SDK, and the event then has by set to agent.

EndpointWhat it does
POST /v1/calls/{id}/holdThe prospect hears hold music. The agent can talk to others on the call.
POST /v1/calls/{id}/unholdTakes the prospect off hold.
POST /v1/calls/{id}/muteMutes the agent toward the prospect.
POST /v1/calls/{id}/unmuteUnmutes the agent.
POST /v1/calls/{id}/dtmfSends digits on the prospect's line.
POST /v1/calls/{id}/transferWarm or cold transfer to an agent, an agent pool or a phone number.
POST /v1/calls/{id}/conferenceAdds people to the call.
DELETE /v1/calls/{id}/participants/{participant_id}Removes one person from the call.
POST /v1/calls/{id}/forwardMoves the prospect to another number and frees the agent.
POST /v1/calls/{id}/hangupEnds the call for everyone.
POST /v1/calls/{id}/dispositionSaves the outcome, notes and an optional callback time.

Hold and mute

Hold plays hold music to the prospect. The agent stays connected and can talk to anyone else on the call. Mute stops the agent's audio toward the prospect while the agent still hears them. Neither needs a body. Each one sends call.updated with the new on_hold and muted values.

POST/v1/calls/{id}/hold

POST/v1/calls/cal_8Jq2mT4x/hold
curl -X POST https://api.liveleg.dev/v1/calls/cal_8Jq2mT4x/hold \
  -H "Authorization: Bearer $LIVELEG_API_KEY"
Event
{
  "id": "evt_6Tc40Hd1",
  "type": "call.updated",
  "created_at": "2026-11-03T15:44:12.208Z",
  "livemode": true,
  "data": {
    "call_id": "cal_8Jq2mT4x",
    "action": "hold",
    "on_hold": true,
    "muted": false,
    "by": "agent"
  }
}

Send digits

Send key presses on the prospect's line, for example to reach an extension. digits takes 0 to 9, * and #, up to 32 characters. Each w adds a half-second pause.

POST/v1/calls/{id}/dtmf

POST/v1/calls/cal_8Jq2mT4x/dtmf
curl https://api.liveleg.dev/v1/calls/cal_8Jq2mT4x/dtmf \
  -H "Authorization: Bearer $LIVELEG_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "digits": "3w2#"
  }'

Transfer a call

A warm transfer keeps the first agent on the line while the next person joins. A cold transfer hands the call over and frees the first agent for the next call. Targets are agent:, pool: or a phone number.

POST/v1/calls/{id}/transfer

ParametersTypeDescription
moderequired warm | cold warm keeps the first agent on the call until they leave. cold hands the call over right away.
torequired string agent:agt_..., pool:pool_... or a phone number in E.164.
consult boolean Warm only. The prospect is on hold while the two agents talk, and joins when the transfer completes. Default false.
notes string Shown to the receiving agent with the lead details.
timeout_seconds integer How long the target rings. 10 to 60, default 30.
on_no_answer return_to_agent | voicemail | hangup What happens when the target does not answer. Default return_to_agent.
POST/v1/calls/cal_8Jq2mT4x/transfer
curl https://api.liveleg.dev/v1/calls/cal_8Jq2mT4x/transfer \
  -H "Authorization: Bearer $LIVELEG_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "mode": "warm",
    "to": "agent:agt_closer_09",
    "notes": "Wants a roof inspection quote this week.",
    "timeout_seconds": 30,
    "on_no_answer": "return_to_agent"
  }'

A warm transfer runs in three steps:

  • The target rings. The first agent and the prospect keep talking.
  • The target answers and joins the call. call.transferred arrives with result joined. With consult=true, the prospect is on hold while the two agents talk.
  • The first agent leaves with POST /v1/calls/{id}/transfer/complete or by hanging up in the SDK. The target has the call, the result is completed, and the first agent is free for the next call.
POST/v1/calls/cal_8Jq2mT4x/transfer/complete
curl -X POST https://api.liveleg.dev/v1/calls/cal_8Jq2mT4x/transfer/complete \
  -H "Authorization: Bearer $LIVELEG_API_KEY"

In a cold transfer the first agent is free as soon as the request is accepted. The prospect hears ringing until the target answers. If nobody answers within timeout_seconds, on_no_answer applies. return_to_agent rings the first agent again, or the agent pool when they are on another call. Cancel a transfer before it completes with POST /v1/calls/{id}/transfer/cancel.

resultMeaning
joinedWarm. The target answered and is on the call with the first agent and the prospect.
completedThe first agent left and the target has the call. For cold transfers this is the only success result.
no_answerThe target did not answer within timeout_seconds. on_no_answer was applied.
canceledThe first agent canceled before the transfer completed.
Event
{
  "id": "evt_5Mz71Ka8",
  "type": "call.transferred",
  "created_at": "2026-11-03T15:44:51.733Z",
  "livemode": true,
  "data": {
    "call_id": "cal_8Jq2mT4x",
    "mode": "warm",
    "from_agent_id": "agt_114",
    "to": "agent:agt_closer_09",
    "result": "completed"
  }
}

Add and remove people

Add up to 5 people to a live call: agents, or outside phone numbers such as a manager's mobile. A supervisor added with mode=listen hears everyone and is not heard. Each person gets a participant ID. Joins and departures send call.participant_joined and call.participant_left.

POST/v1/calls/{id}/conference

ParametersTypeDescription
participantsrequired array Up to 5 people. Each has to (agent:agt_... or a phone number in E.164) and mode.
participants[].mode talk | listen listen joins without being heard, for supervisors. Default talk.
POST/v1/calls/cal_8Jq2mT4x/conference
curl https://api.liveleg.dev/v1/calls/cal_8Jq2mT4x/conference \
  -H "Authorization: Bearer $LIVELEG_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "participants": [
      {
        "to": "agent:agt_closer_09",
        "mode": "talk"
      },
      {
        "to": "agent:agt_sup_02",
        "mode": "listen"
      }
    ]
  }'
Response
{
  "call_id": "cal_8Jq2mT4x",
  "participants": [
    {
      "id": "par_1",
      "role": "prospect",
      "to": "+15125550147",
      "mode": "talk",
      "status": "connected"
    },
    {
      "id": "par_2",
      "role": "agent",
      "agent_id": "agt_114",
      "mode": "talk",
      "status": "connected"
    },
    {
      "id": "par_3",
      "role": "agent",
      "agent_id": "agt_closer_09",
      "mode": "talk",
      "status": "ringing"
    },
    {
      "id": "par_4",
      "role": "agent",
      "agent_id": "agt_sup_02",
      "mode": "listen",
      "status": "ringing"
    }
  ]
}

Remove one person with their participant ID. The call goes on for everyone else. When the last agent leaves, the call ends.

DELETE/v1/calls/{id}/participants/{participant_id}

DELETE/v1/calls/cal_8Jq2mT4x/participants/par_4
curl -X DELETE https://api.liveleg.dev/v1/calls/cal_8Jq2mT4x/participants/par_4 \
  -H "Authorization: Bearer $LIVELEG_API_KEY"

Forward a call

Forward moves the prospect to another phone number and frees the agent at once, with no announcement. Use it to hand a caller to an office line or an answering service. If the number does not answer within timeout_seconds, the call ends. call.transferred arrives with mode forward.

POST/v1/calls/{id}/forward

POST/v1/calls/cal_8Jq2mT4x/forward
curl https://api.liveleg.dev/v1/calls/cal_8Jq2mT4x/forward \
  -H "Authorization: Bearer $LIVELEG_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "+15125550108",
    "timeout_seconds": 30
  }'

Hang up

Hang-up ends the call for everyone on it. call.completed arrives with hangup_by set to agent. In a dial session the next round starts right away.

POST/v1/calls/{id}/hangup

Dispositions and scheduled callbacks

A disposition records the outcome of a call. Codes are your own strings. Send it during the call or after it ends, and it shows on the call record and on call.completed. Set callback_at to schedule a callback with the same agent. callback.scheduled confirms it. How callbacks run is in Scheduled callbacks.

POST/v1/calls/{id}/disposition

ParametersTypeDescription
coderequired string Your outcome code, for example callback_requested or sold.
notes string Free text, up to 2,000 characters.
callback_at string ISO 8601 with offset. Schedules a callback to the lead at that time.
POST/v1/calls/cal_8Jq2mT4x/disposition
curl https://api.liveleg.dev/v1/calls/cal_8Jq2mT4x/disposition \
  -H "Authorization: Bearer $LIVELEG_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "code": "callback_requested",
    "notes": "Owner on a job. Call Thursday after 2 pm.",
    "callback_at": "2026-11-06T14:00:00-06:00"
  }'

Inbound callbacks

When a lead calls back one of your numbers, the call rings the agent who last spoke with them, then the agent pool, then voicemail. Routing settings, hold, the opt-out menu and inbound prices are in Inbound calls and callbacks.

Call records

A call record lists every leg placed for the call, answered or not, with timings, the detection result, billed seconds and cost. Filter by dial session, agent, lead or date range. The cost fields are explained in Cost per call.

GET/v1/call_records

curl
curl "https://api.liveleg.dev/v1/call_records?dial_session_id=dls_31Ka9&limit=50" \
  -H "Authorization: Bearer $LIVELEG_API_KEY"
Response
{
  "id": "cal_8Jq2mT4x",
  "object": "call",
  "dial_session_id": "dls_31Ka9",
  "account_id": "acc_ridgeline",
  "direction": "outbound",
  "from": "+15125550199",
  "to": "+15125550147",
  "agent_id": "agt_114",
  "status": "completed",
  "legs": [
    {
      "id": "leg_a1",
      "to": "+15125550147",
      "result": "bridged",
      "rang_ms": 4120
    },
    {
      "id": "leg_a2",
      "to": "+15125550163",
      "result": "canceled",
      "rang_ms": 15400
    },
    {
      "id": "leg_a3",
      "to": "+15125550108",
      "result": "machine_voicemail",
      "rang_ms": 9800
    }
  ],
  "answered_at": "2026-11-03T15:42:03.542Z",
  "bridged_at": "2026-11-03T15:42:07.412Z",
  "ended_at": "2026-11-03T15:46:29.903Z",
  "amd_result": "human",
  "speech_ended_to_bridge_ms": 980,
  "billed_seconds": 264,
  "hangup_by": "prospect",
  "disposition": "callback_requested",
  "rate_per_minute": "0.12",
  "amount": "0.528",
  "charges": [
    {"item": "outbound_minutes", "quantity": 4.4, "amount": "0.528"}
  ],
  "surcharges": [],
  "total": "0.528"
}