> For a complete documentation index, fetch https://docs.voximplant.ai/llms.txt

# Example: Placing an outbound call

> This example starts a VoxEngine session, places an outbound PSTN call, and connects the callee to Gemini Live API when the session is ready.

<blockquote>
  For the complete documentation index, see <a href="/llms.txt">llms.txt</a>.
</blockquote>

## Overview

This example starts a VoxEngine session, places an outbound PSTN call, and connects the callee to Gemini Live API when the session is ready.

**⬇️ Jump to the [Full VoxEngine scenario](#full-voxengine-scenario).**

<Info title="Gemini 3.1 Flash Live Preview">
  This page reflects the current `gemini-3.1-flash-live-preview` flow from Google’s Live API docs:
  [https://ai.google.dev/gemini-api/docs/models/gemini-3.1-flash-live-preview](https://ai.google.dev/gemini-api/docs/models/gemini-3.1-flash-live-preview)
</Info>

## Prerequisites

* Create a routing rule with this scenario attached (outgoing calls don’t use patterns) so you can run it from the Control Panel or trigger it via API: [https://voximplant.com/docs/getting-started/basic-concepts/routing-rules](https://voximplant.com/docs/getting-started/basic-concepts/routing-rules)
* Have a PSTN `destination` number you can dial (E.164 format), for example your mobile number.
* Configure a valid outbound `callerId` (for example, a rented Voximplant number or a verified caller ID): [https://voximplant.com/docs/getting-started/basic-concepts/phone-numbers](https://voximplant.com/docs/getting-started/basic-concepts/phone-numbers)
* Pass `destination` and `callerId` as routing rule custom data (this example reads them from `VoxEngine.customData()`): `{"destination":"+15551234567","callerId":"+15557654321"}`.
* Store your Gemini API key in Voximplant [Secrets](/platform/voxengine/secrets) under `GEMINI_API_KEY`.

<Info title="About outbound Caller ID">
  `VoxEngine.callPSTN(...)` requires a valid callback-capable caller ID (for example, a rented Voximplant number or a verified caller ID). See [https://voximplant.com/docs/getting-started/basic-concepts/phone-numbers](https://voximplant.com/docs/getting-started/basic-concepts/phone-numbers).
</Info>

## Launch the routing rule

For quick testing, you can start this outbound scenario from the Voximplant Control Panel:

1. Open your Voximplant application and go to the **Routing** tab.
2. Select the routing rule that has this scenario attached.
3. Click **Run**.
4. Provide **Custom data** (max 200 bytes) with `destination` and `callerId`:

```json title="Custom data example"
{"destination":"+15551234567","callerId":"+15557654321"}
```

For production, start the routing rule via Management API `startScenarios` (pass `rule_id`, and pass the same JSON string in `script_custom_data`): [https://voximplant.com/docs/references/httpapi/scenarios#startscenarios](https://voximplant.com/docs/references/httpapi/scenarios#startscenarios)

## Alternate outbound destinations

This example uses `VoxEngine.callPSTN(...)` for PSTN dialing. You can also route outbound calls to other destination types in VoxEngine:

* **SIP** (`VoxEngine.callSIP`): dial a SIP URI to reach a PBX, carrier, SIP trunk, or other SIP endpoint.
* **WhatsApp** (`VoxEngine.callWhatsappUser`): place a WhatsApp Business-initiated call (requires a WhatsApp Business account and enabled numbers).
* **Voximplant users** (`VoxEngine.callUser`): calls another app user inside the same Voximplant application such as web SDK, mobile SDK, or SIP user.

Relevant guides:

* [SIP calling options](/getting-started/network-options/sip)
* [Voximplant users calling options](/getting-started/network-options/web-mobile)
* [WhatsApp calling options](/getting-started/network-options/whatsapp)

## Notes

* The example uses the Gemini Developer API (`Gemini.Backend.GEMINI_API`), not Vertex AI.
* The current sample uses `gemini-3.1-flash-live-preview`.
* Audio is connected after `Gemini.LiveAPIEvents.SetupComplete` fires.

<Warning title="Gemini 2.5 compatibility">
  If you are adapting an older `2.5` outbound sample, use `sendRealtimeInput(...)` for the initial prompt on `3.1`. The current `3.1` sample also uses `thinkingConfig: { thinkingLevel: "minimal" }`.
</Warning>

[See the VoxEngine API Reference for more details](https://voximplant.com/docs/references/voxengine/gemini).

## Full VoxEngine scenario

```javascript title={"voxeengine-gemini-place-outbound-call.js"} maxLines={0}
/**
 * Voximplant + Gemini Live API connector demo
 * Scenario: place an outbound PSTN call and bridge it to Gemini Live API.
 */

require(Modules.Gemini);
const SYSTEM_PROMPT = `
You are Voxi, a helpful voice assistant for phone callers.
Keep responses short and telephony-friendly (usually 1-2 sentences).
`;

// -------------------- Gemini Live API settings --------------------
const CONNECT_CONFIG = {
    responseModalities: ["AUDIO"],
    thinkingConfig: {thinkingLevel: "minimal"},
    systemInstruction: {
        parts: [{text: SYSTEM_PROMPT}],
    },
    inputAudioTranscription: {},
    outputAudioTranscription: {},
};

VoxEngine.addEventListener(AppEvents.Started, async () => {
    let voiceAIClient;
    let call;

    try {
        // This can be provided when manually running a routing rule in the Control Panel,
        // or via Management API using the `script_custom_data` parameter.
        // example: {"destination": "+15551234567","callerId": "+15557654321"}
        const {destination, callerId} = JSON.parse(VoxEngine.customData());

        // Place the outbound call
        call = VoxEngine.callPSTN(destination, callerId);
        // Alternative outbound paths (uncomment to use):
        // call = VoxEngine.callUser({username: destination, callerid: callerId});
        // call = VoxEngine.callSIP(`sip:${destination}@your-sip-domain`, callerId);
        // call = VoxEngine.callWhatsappUser({number: destination, callerid: callerId});

        // Termination functions - add cleanup and logging as needed
        call.addEventListener(CallEvents.Disconnected, VoxEngine.terminate);
        call.addEventListener(CallEvents.Failed, VoxEngine.terminate);

        call.addEventListener(CallEvents.Connected, async () => {
            // call.record({ hd_audio: true, stereo: true });  // Optional: record the call

            voiceAIClient = await Gemini.createLiveAPIClient({
                apiKey: VoxEngine.getSecretValue('GEMINI_API_KEY'),
                model: "gemini-3.1-flash-live-preview",
                backend: Gemini.Backend.GEMINI_API,
                connectConfig: CONNECT_CONFIG,
                onWebSocketClose: () => {
                    Logger.write(`===Gemini.WebSocket.Close===`);
                    VoxEngine.terminate();
                },
            });

            voiceAIClient.addEventListener(Gemini.LiveAPIEvents.SetupComplete, () => {
                VoxEngine.sendMediaBetween(call, voiceAIClient);
                voiceAIClient.sendRealtimeInput({
                    text: "Say hello and ask how you can help.",
                });
            });

            // Capture transcripts + handle barge-in
            voiceAIClient.addEventListener(Gemini.LiveAPIEvents.ServerContent, (event) => {
                const payload = event?.data?.payload || {};
                if (payload.inputTranscription?.text) {
                    Logger.write(`===USER=== ${payload.inputTranscription.text}`);
                }
                if (payload.outputTranscription?.text) {
                    Logger.write(`===AGENT=== ${payload.outputTranscription.text}`);
                }
                if (payload.interrupted) {
                    Logger.write("===BARGE-IN=== Gemini.LiveAPIEvents.ServerContent");
                    voiceAIClient.clearMediaBuffer();
                }
            });

            // Log all Gemini events for illustration/debugging
            [
                Gemini.LiveAPIEvents.SetupComplete,
                Gemini.LiveAPIEvents.ServerContent,
                Gemini.LiveAPIEvents.ToolCall,
                Gemini.LiveAPIEvents.ToolCallCancellation,
                Gemini.LiveAPIEvents.ConnectorInformation,
                Gemini.LiveAPIEvents.Unknown,
                Gemini.Events.WebSocketMediaStarted,
                Gemini.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("===SOMETHING_WENT_WRONG===");
        Logger.write(error);
        voiceAIClient?.close();
        VoxEngine.terminate();
    }
});

```