I have an inbound call flow where:
Incoming call β handled by /incoming, which connects the call to Ultravox AI through a .
AI Agent conversation β if the caller asks for a human, the AI triggers /transferCall/:fromNumber.
Transfer call β /transferCall returns Plivo XML with a to /agentDial.
Expected next step β Plivo should call /agentDial, which responds with to connect the human agent.
The issue is at step 3 β 4:
/transferCall runs and returns the as expected.
But Plivo never makes a request to /agentDial.
This means the call never dials out to the human agent, and it just gets stuck.
Iβm unsure if the problem is with how Iβm using (maybe I should return directly inside /transferCall?) or if Iβm missing something in Plivoβs call flow setup.
What I tried
I configured the AI Agent (Ultravox) to use the transferCall tool, which triggers my /transferCall/:fromNumber endpoint.
In /transferCall, I return an XML pointing to /agentDial.
I verified that /transferCall is definitely called (I see Received transferCall for ... in the logs).
I expected Plivo to immediately make a POST to /agentDial, which would then run my logic to connect the caller to the human agent.
What I expected
After /transferCall is triggered, Plivo should hit /agentDial.
The /agentDial endpoint should respond with and connect the caller to the configured HUMAN_AGENT_NUMBER.
The call should seamlessly transfer from the AI Agent to the human agent.
import express from "express";
import plivo from "plivo";
const app = express();
const PUBLIC_URL = process.env.PUBLIC_URL;
const PLIVO_NUMBER = process.env.PLIVO_NUMBER;
const HUMAN_AGENT_NUMBER = process.env.HUMAN_AGENT_NUMBER;
// Transfer Call
app.post("/transferCall/:fromNumber", (req, res) => {
const fromNumber = req.params.fromNumber;
console.log(`Received transferCall for ${fromNumber}`);
res.type("text/xml").send(`<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Redirect>${PUBLIC_URL}/agentDial</Redirect>
</Response>`);
});
// Agent Dial
app.post("/agentDial", (req, res) => {
console.log("π₯ *** AGENT DIAL ENDPOINT CALLED ***");
try {
const response = new plivo.Response();
response.addSpeak("I will now transfer you to a human agent.");
const dial = response.addDial({
callerId: PLIVO_NUMBER,
action: `${PUBLIC_URL}/dial-status`,
method: "POST",
});
dial.addNumber(HUMAN_AGENT_NUMBER);
res.type("text/xml").send(response.toXML());
} catch (error) {
console.error(error);
res.type("text/xml").send(`
<Response>
<Speak>Could not connect to agent.</Speak>
</Response>`);
}
});
app.listen(3000, () => console.log("Server running on port 3000"));