Example: OpenAI Realtime on Azure

Use the VoxEngine OpenAI Realtime client with an Azure OpenAI Realtime deployment.
View as Markdown

For the complete documentation index, see llms.txt.

Overview

This example answers an inbound call and bridges call audio to an Azure OpenAI Realtime deployment using OpenAI.createRealtimeAPIClient().

Use this pattern when you have an Azure OpenAI Realtime model deployment and want VoxEngine call control, recording, media bridging, and OpenAI-compatible Realtime session handling in the same scenario.

⬇️ Jump to the Full VoxEngine scenario.

Prerequisites

  • An Azure subscription with access to Azure OpenAI in Microsoft Foundry Models.
  • A Microsoft Foundry or Azure OpenAI resource in a region that supports GPT Realtime models. Check Microsoft’s Realtime audio model and region documentation before creating the deployment.
  • Quota for the selected Realtime model and deployment type. Azure OpenAI quota is region-specific, so confirm the requested model has available quota in the target region. See Azure OpenAI quotas and limits.
  • An Azure OpenAI Realtime model deployment, for example gpt-realtime-1.5. The model value in this VoxEngine scenario must match the Azure deployment name.
  • The Azure OpenAI resource endpoint from Foundry. The current Azure v1 API format uses /openai/v1 in the endpoint URL. See Azure OpenAI v1 API.
  • Store the Azure OpenAI API key in Voximplant Secrets under AZURE_API_KEY.
  • Store the Azure OpenAI endpoint in Voximplant Secrets under AZURE_OPENAI_BASE_URL.
  • Create a Voximplant routing rule that points your test destination to this scenario.

Azure setup checklist

  1. Create or select a Microsoft Foundry project with an Azure OpenAI resource.
  2. Confirm the target region supports your Realtime model and has quota.
  3. Deploy a GPT Realtime model from the Foundry Build area. For gpt-realtime-1.5, use the deployed model name as the AZURE_OPENAI_MODEL value in the scenario.
  4. Open the deployment details and copy both the API key and Azure OpenAI endpoint.
  5. Add the API key to Voximplant Secrets as AZURE_API_KEY.
  6. Add the Azure OpenAI endpoint to Voximplant Secrets as AZURE_OPENAI_BASE_URL.
  7. Keep the AZURE_OPENAI_MODEL scenario constant set to the Azure deployment name, not just the model family name unless you used the same value for the deployment name.
  8. Test the deployment in the Foundry Audio playground before routing live calls through Voximplant.

Microsoft’s Azure OpenAI v1 documentation shows endpoint values like https://your-resource.openai.azure.com/openai/v1/.

VoxEngine accepts the same endpoint with or without the openai/v1 path. Both of these are valid for baseUrl:

  • https://your-resource.openai.azure.com/openai/v1/
  • https://your-resource.openai.azure.com/

Architecture

How it works

  • The scenario reads AZURE_API_KEY and AZURE_OPENAI_BASE_URL from Voximplant Secrets.
  • baseUrl points the OpenAI Realtime client at the Azure OpenAI resource.
  • model uses the Azure deployment name.
  • VoxEngine.sendMediaBetween(call, voiceAIClient) bridges call audio to the Realtime client after the session is updated.
  • responseCreate(...) after SessionUpdated creates the audible greeting for the caller.
  • The barge-in handler clears the media buffer when the caller starts speaking.

Usage highlights

  • Create the Realtime client with OpenAI.createRealtimeAPIClient(...).
  • Set baseUrl from AZURE_OPENAI_BASE_URL to route the VoxEngine OpenAI module to Azure instead of OpenAI’s default endpoint.
  • Set model to the Azure deployment name.
  • Use sessionUpdate(...) to configure Realtime instructions, voice, output modalities, and turn detection.
  • Bridge audio with VoxEngine.sendMediaBetween(call, voiceAIClient).
  • Handle barge-in with InputAudioBufferSpeechStarted and clearMediaBuffer().

Full VoxEngine scenario

voxeengine-byollm-azure-openai-rt.js
1/**
2 * Voximplant + Azure OpenAI Realtime API connector demo
3 * Scenario: answer an incoming call and bridge it to Azure OpenAI Realtime.
4 */
5
6require(Modules.OpenAI);
7
8const SYSTEM_PROMPT = `
9You are Voxi, a helpful voice assistant for Voximplant phone callers.
10Keep responses short and telephony-friendly (usually 1-2 sentences).
11`;
12
13const SESSION_CONFIG = {
14 session: {
15 type: "realtime",
16 instructions: SYSTEM_PROMPT,
17 voice: "alloy",
18 output_modalities: ["audio"],
19 turn_detection: {type: "server_vad", interrupt_response: true},
20 },
21};
22
23VoxEngine.addEventListener(AppEvents.CallAlerting, async ({call}) => {
24 let voiceAIClient;
25
26 function terminate(){
27 voiceAIClient?.close();
28 VoxEngine.terminate();
29 }
30
31 call.addEventListener(CallEvents.Disconnected, terminate);
32 call.addEventListener(CallEvents.Failed, terminate);
33
34 try {
35 call.answer();
36 // call.record({hd_audio: true, stereo: true}); // Optional: record the call
37
38 voiceAIClient = await OpenAI.createRealtimeAPIClient({
39 apiKey: VoxEngine.getSecretValue("AZURE_API_KEY"), // API key from Azure
40 baseUrl: VoxEngine.getSecretValue("AZURE_OPENAI_BASE_URL"), // https://{{resource}}.openai.azure.com
41 model: "gpt-realtime-1.5", // align with deployed model
42 onWebSocketClose: (event) => {
43 Logger.write("===AzureOpenAI.WebSocket.Close===");
44 if (event) Logger.write(JSON.stringify(event));
45 VoxEngine.terminate();
46 },
47 });
48
49 //---------------------- Event handlers -----------------------
50 voiceAIClient.addEventListener(OpenAI.RealtimeAPIEvents.SessionCreated, () => {
51 voiceAIClient.sessionUpdate(SESSION_CONFIG);
52 });
53
54 voiceAIClient.addEventListener(OpenAI.RealtimeAPIEvents.SessionUpdated, () => {
55 VoxEngine.sendMediaBetween(call, voiceAIClient);
56 voiceAIClient.responseCreate({instructions: "Greet the caller and ask how you can help."});
57 });
58
59 // Barge-in: clear buffered audio when the caller starts speaking
60 voiceAIClient.addEventListener(OpenAI.RealtimeAPIEvents.InputAudioBufferSpeechStarted, () => {
61 Logger.write("===BARGE-IN: AzureOpenAI.InputAudioBufferSpeechStarted===");
62 voiceAIClient.clearMediaBuffer();
63 });
64
65
66 voiceAIClient.addEventListener(
67 OpenAI.RealtimeAPIEvents.ConversationItemInputAudioTranscriptionCompleted,
68 (event) => {
69 const {transcript} = event.data.payload;
70 if (transcript) Logger.write(`===USER=== ${transcript}`);
71 },
72 );
73
74 voiceAIClient.addEventListener(
75 OpenAI.RealtimeAPIEvents.ResponseOutputAudioTranscriptDelta,
76 (event) => {
77 const {delta} = event.data.payload;
78 if (delta) Logger.write(`===AGENT_DELTA=== ${delta}`);
79 },
80 );
81
82 voiceAIClient.addEventListener(
83 OpenAI.RealtimeAPIEvents.ResponseOutputAudioTranscriptDone,
84 (event) => {
85 const {transcript} = event.data.payload;
86 if (transcript) Logger.write(`===AGENT=== ${transcript}`);
87 },
88 );
89
90 // Consolidated "log-only" handlers - key OpenAI/VoxEngine debugging events
91 [
92 OpenAI.RealtimeAPIEvents.ResponseCreated,
93 OpenAI.RealtimeAPIEvents.ResponseDone,
94 OpenAI.RealtimeAPIEvents.ResponseOutputAudioDone,
95 OpenAI.RealtimeAPIEvents.ConnectorInformation,
96 OpenAI.RealtimeAPIEvents.HTTPResponse,
97 OpenAI.RealtimeAPIEvents.WebSocketError,
98 OpenAI.RealtimeAPIEvents.Unknown,
99 OpenAI.Events.WebSocketMediaStarted,
100 OpenAI.Events.WebSocketMediaEnded,
101 ].forEach((eventName) => {
102 voiceAIClient.addEventListener(eventName, (event) => {
103 Logger.write(`===${event.name}===`);
104 if (event?.data) Logger.write(JSON.stringify(event.data));
105 });
106 });
107 } catch (error) {
108 Logger.write("===UNHANDLED_ERROR===");
109 Logger.write(error);
110 terminate();
111 }
112});

More info