Call Routing
HostDesk supports call routing operations: transferring calls to other numbers and putting callers on hold/resume. These are available via the API and as LLM tools the agent can invoke during a conversation.
Transfer a call
Transfer connects a third party to the existing call room. The original caller stays connected (warm transfer / conference-style).
API endpoint
POST /api/v1/calls/{room_name}/transfer
{
"phone_number": "+14155559999",
"announce": "Transferring you to a specialist..."
}
Response:
{
"room_name": "echoai-out-abc123",
"transfer_identity": "sip-transfer-14155559999-f8a2",
"message": "Transferred to +14155559999. Both parties are now in room echoai-out-abc123."
}
As an LLM tool
The agent can call transfer_call during a conversation:
tools = [
{
"type": "function",
"function": {
"name": "transfer_call",
"description": "Transfer the current call to another phone number",
"parameters": {
"type": "object",
"properties": {
"phone_number": {
"type": "string",
"description": "E.164 phone number to transfer to"
},
"reason": {
"type": "string",
"description": "Reason for the transfer"
}
},
"required": ["phone_number"]
}
}
}
]
When the LLM decides to transfer, HostDesk dials the target number via SIP and adds them to the room.
Hold and resume
Hold mutes the caller's audio track so they can't hear the agent (or plays hold music). Resume unmutes.
How it works
Hold/resume is implemented via LiveKit track muting:
- Hold: The agent mutes the caller's audio subscription and optionally plays a hold audio track
- Resume: The agent unmutes the caller's audio and stops the hold track
API usage
POST /api/v1/calls/{room_name}/hold
POST /api/v1/calls/{room_name}/resume
Both return 200 OK with the current room state.
As an LLM tool
tools = [
{
"type": "function",
"function": {
"name": "hold_call",
"description": "Put the caller on hold",
"parameters": {"type": "object", "properties": {}}
}
},
{
"type": "function",
"function": {
"name": "resume_call",
"description": "Take the caller off hold",
"parameters": {"type": "object", "properties": {}}
}
}
]
Requirements
- An active call in a LiveKit room
- A provisioned outbound SIP trunk (for transfers)
- A primary phone number configured as caller ID
Authorization: Bearer <api_key>header
Common patterns
Transfer to a department
@handler.register("transfer_to_support")
def transfer_to_support(room_name: str) -> str:
client.calls.transfer(room_name, phone_number="+18005551234")
return "Transferring you to our support team now."
Conditional transfer
The agent can decide to transfer based on the conversation:
User: "I need to speak to a real person." Agent: "Of course, let me transfer you to our team." (Agent calls transfer_call tool)