Transfer Destination Request
Resolve and execute a Vapi dynamic transfer (the routeTransfer tool).
routeTransfer is a custom function tool carrying arguments, so it is dispatched as a normal tool-calls message — NOT a transfer-destination-request webhook. (Vapi only fires that webhook for a transferCall tool that supplies no destination; a tool call carrying arguments is treated as a supplied destination and Vapi would try to dial the argument as a phone number, dropping the call. That is the bug this endpoint replaces.)
Flow (Vapi Live Call Control, see https://docs.vapi.ai/calls/call-dynamic-transfers): resolve the TransferDestination from the arguments, then POST the transfer to the call's monitor.controlUrl. We respond with the standard {"results": [...]} custom tool shape.
Tool arguments:
- reason (required): a department name ("Lien Dept", "Intake Dept", "Settlement Dept", "Opening Dept", "Prelit Dept", "Calendar Dept", "Client Services", "Office") maps to the customer's TransferDestination rows by name; "case" routes by the case's SmartAdvocate status rules.
- case_number (optional): the synced case to route by when reason="case", copied verbatim from lookupClient.
- announcement (required in the tool schema, tolerated absent here): the line the model SPEAKS itself, mirrored into the argument for logging. The system never speaks it: dev A/B on 2026-08-31 showed every system-spoken slot doubles — the model narrates alongside the tool call on about half of transfer turns (three prompt phrasings could not stop it), and Vapi occasionally double-played the LCC content field even on bare tool calls. Instead the prompt has the model speak the announcement (ending with <flush />) and then call this tool in the same response, and this handler holds the transfer POST until the announcement's TTS actually finishes. The hold is closed-loop, not a blind timer: it arms a TransferAnnouncementGate row and waits for the /webhooks/vapi speech-update events to show the assistant has gone quiet (see _await_announcement_quiet). The tool is sync (async: false), so Vapi blocks the model's next turn during the hold, and the in-flight announcement keeps streaming meanwhile.
Bad or missing arguments degrade to the office fallback, never to a failed transfer. Only when no destination exists at all, or the control URL is missing, does this return a tool error (the model then apologizes and keeps the call going).
Request body
Response
Successful Response