I’m using the Node SDK. I’m following this doc to make outbound calls:
In my backend, I’m using createDispatch:
const api = new LiveKitAPI({
host: process.env.LIVEKIT_URL!,
apiKey: process.env.LIVEKIT_API_KEY!,
secret: process.env.LIVEKIT_API_SECRET!,
});
await api.agentDispatch.createDispatch(
roomName,
agentName,
{ metadata: JSON.stringify(metadata) },
);
In the LiveKit agent, I’m creating the SIP participant and waiting for it to join.
The problem is that waitForParticipant doesn’t wait for the participant to answer the call.
"participant joined" is logged immediately after "waiting for participant", and the agent starts talking even though there’s no human on the call yet.
What am I missing?
I’ve also attached a small repro of the LiveKit agent. I assume a backend repro isn’t necessary since it’s just a single call to createDispatch.
import { ServerOptions, cli, defineAgent, log, voice } from '@livekit/agents';
import { LiveKitAPI } from 'livekit-server-sdk';
import * as openai from '@livekit/agents-plugin-openai';
import { audioEnhancement } from '@livekit/plugins-ai-coustics';
import dotenv from 'dotenv';
import { fileURLToPath } from 'node:url';
import { createAgent } from './agent.ts';
dotenv.config({ path: '.env.local' });
export default defineAgent({
entry: async (ctx) => {
const logger = log().child({ name: 'main' });
await ctx.connect();
const toNumber = JSON.parse(ctx.job.metadata).phoneNumber;
logger.info({ toNumber }, 'creating outbound call');
const api = new LiveKitAPI({
host: process.env.LIVEKIT_URL!,
apiKey: process.env.LIVEKIT_API_KEY!,
secret: process.env.LIVEKIT_API_SECRET!,
});
try {
await api.sip.createSipParticipant(
process.env.LIVEKIT_SIP_OUTBOUND_TRUNK!,
toNumber,
ctx.room.name!,
{
participantIdentity: toNumber,
waitUntilAnswered: true,
},
);
logger.info({ toNumber }, 'waiting for participant');
await ctx.waitForParticipant(toNumber);
logger.info({ toNumber }, 'participant joined'); // logged immediately. doesn't wait for participant to answer the call
} catch (error) {
logger.error(error);
ctx.shutdown();
return;
}
const session = new voice.AgentSession({
llm: new openai.realtime.RealtimeModel({
model: 'gpt-realtime-2.1',
voice: 'marin',
inputAudioTranscription: null,
}),
});
await session.start({
agent: createAgent(),
room: ctx.room,
inputOptions: {
noiseCancellation: audioEnhancement({ model: 'quailVfS' }),
},
});
logger.info('generating reply');
session.generateReply({
instructions: 'Greet the user in a helpful and friendly manner.',
});
},
});
cli.runApp(
new ServerOptions({
agent: fileURLToPath(import.meta.url),
agentName: process.env.LIVEKIT_AGENT_NAME!,
}),
);
livekit-outbound-test.zip (57.8 KB)

