Example: Answering an incoming call

View as Markdown

For the complete documentation index, see llms.txt.

This example answers an inbound Voximplant call and bridges audio to OpenAI Realtime for speech-to-speech conversations. Select a model version to keep the session configuration and complete scenario synchronized. gpt-realtime-2.1 is the default for new applications.

Jump to the Full VoxEngine scenarios.

Prerequisites

Session setup

gpt-realtime-2 and above introduced some breaking changes to the gpt-realtime-1.x session configuration object. Make sure to select the appropriate version in the examples below.

The example configures the OpenAI Realtime session with a system prompt, enables semantic VAD, and uses low reasoning effort.

GPT Realtime 2.1 session setup
voiceAIClient.sessionUpdate({
session: {
type: "realtime",
model: "gpt-realtime-2.1",
instructions: SYSTEM_PROMPT,
reasoning: { effort: "low" },
output_modalities: ["audio"],
audio: {
input: {
turn_detection: {
type: "semantic_vad",
eagerness: "auto",
create_response: true,
interrupt_response: true,
},
},
output: {
voice: "alloy",
},
},
},
});

Connect call audio

Once the session is ready, bridge audio both ways between the call and OpenAI:

Connect call audio
VoxEngine.sendMediaBetween(call, voiceAIClient);

Barge-in

The scenario clears buffered model audio whenever OpenAI detects caller speech:

Barge-in
voiceAIClient.addEventListener(OpenAI.RealtimeAPIEvents.InputAudioBufferSpeechStarted, () => {
voiceAIClient.clearMediaBuffer();
});

Full VoxEngine scenarios

voxeengine-openai-answer-incoming-call.js
/**
* Voximplant + OpenAI Realtime API connector demo
* Scenario: answer an incoming call and bridge it to OpenAI Realtime 2.1.
*/
require(Modules.OpenAI);
const SYSTEM_PROMPT = `
You are Voxi, a helpful voice assistant for phone callers.
Keep responses short and telephony-friendly (usually 1-2 sentences).
`;
const SESSION_CONFIG = {
session: {
type: "realtime",
model: "gpt-realtime-2.1",
instructions: SYSTEM_PROMPT,
reasoning: {effort: "low"},
output_modalities: ["audio"],
audio: {
input: {
turn_detection: {
type: "semantic_vad",
eagerness: "auto",
create_response: true,
interrupt_response: true,
},
},
output: {
voice: "alloy",
},
},
},
};
VoxEngine.addEventListener(AppEvents.CallAlerting, async ({call}) => {
let voiceAIClient;
const eventPayload = (event) => event?.data?.payload || event?.data || {};
const terminate = () => {
voiceAIClient?.close();
VoxEngine.terminate();
};
call.addEventListener(CallEvents.Disconnected, terminate);
call.addEventListener(CallEvents.Failed, terminate);
try {
call.answer();
voiceAIClient = await OpenAI.createRealtimeAPIClient({
apiKey: VoxEngine.getSecretValue("OPENAI_API_KEY"),
model: "gpt-realtime-2.1",
onWebSocketClose: terminate,
});
voiceAIClient.addEventListener(OpenAI.RealtimeAPIEvents.SessionCreated, () => {
voiceAIClient.sessionUpdate(SESSION_CONFIG);
});
voiceAIClient.addEventListener(OpenAI.RealtimeAPIEvents.SessionUpdated, () => {
VoxEngine.sendMediaBetween(call, voiceAIClient); // media connected
voiceAIClient.conversationItemCreate({ // request a greeting
item: {
type: "message",
role: "user",
content: [
{
type: "input_text",
text: "The phone call just connected. "
+ 'Say exactly: "Hello! How can I help today?"',
},
],
},
});
voiceAIClient.responseCreate({}); // ask for the response now
});
// Barge-in: clear buffered audio when the caller starts speaking
voiceAIClient.addEventListener(OpenAI.RealtimeAPIEvents.InputAudioBufferSpeechStarted, () => {
Logger.write("===BARGE-IN: OpenAI.InputAudioBufferSpeechStarted===");
voiceAIClient.clearMediaBuffer();
});
voiceAIClient.addEventListener(
OpenAI.RealtimeAPIEvents.ConversationItemInputAudioTranscriptionCompleted,
(event) => {
const payload = eventPayload(event);
const transcript = payload.transcript || payload.text || payload.delta;
if (transcript) Logger.write(`===USER=== ${transcript}`);
},
);
voiceAIClient.addEventListener(
OpenAI.RealtimeAPIEvents.ResponseOutputAudioTranscriptDone,
(event) => {
const payload = eventPayload(event);
const transcript = payload.transcript || payload.text;
if (transcript) Logger.write(`===AGENT=== ${transcript}`);
},
);
// Consolidated "log-only" handlers - key OpenAI/VoxEngine debugging events
[
OpenAI.RealtimeAPIEvents.ResponseCreated,
OpenAI.RealtimeAPIEvents.ResponseDone,
OpenAI.RealtimeAPIEvents.ResponseOutputAudioDone,
OpenAI.RealtimeAPIEvents.ConnectorInformation,
OpenAI.RealtimeAPIEvents.HTTPResponse,
OpenAI.RealtimeAPIEvents.Error,
OpenAI.RealtimeAPIEvents.WebSocketError,
OpenAI.RealtimeAPIEvents.Unknown,
OpenAI.Events.WebSocketMediaStarted,
OpenAI.Events.WebSocketMediaEnded,
].forEach((eventName) => {
voiceAIClient.addEventListener(eventName, (event) => {
Logger.write(`===${event.name}===`);
if (event?.data) Logger.write(JSON.stringify(event.data));
});
});
} catch (error) {
Logger.write("===UNHANDLED_ERROR===");
Logger.write(error);
terminate();
}
});

More information