Skip to content

Action Types ​

Complete reference for all actions you can return from event handlers.

Overview ​

Actions are responses that tell the Flow service what to do next. All actions require a session_id and type field.

Base Action Structure ​

typescript
interface BaseAction {
  session_id: string; // UUID from the event's session.id
  type: string;       // Action type identifier
}

Action Summary ​

Action TypeDescriptionPrimary Use Case
speakSpeak text or SSMLRespond to user with synthesized speech
audioPlay pre-recorded audioPlay hold music, pre-recorded messages
mix_audioLoop a background sound mixed into speechAdd ambient noise (café, office, train station) under the agent
hangupEnd the callTerminate conversation
transferTransfer to another numberRoute to human agent or department
barge_inManually interrupt playbackStop current audio immediately
configure_transcriptionChange STT language(s) mid-callSwitch recognition language without hanging up

Speak Action ​

Speaks text or SSML to the user.

typescript
interface AiFlowActionSpeak {
  type: "speak";
  session_id: string;

  // Either text OR ssml (not both)
  text?: string; // Plain text to speak
  ssml?: string; // SSML markup for advanced control

  // Optional configurations
  tts?: TtsConfig;      // TTS provider settings
  barge_in?: BargeInConfig; // Barge-in behavior
  user_input_timeout_seconds?: number; // Wait this long for the caller to start
  vad?: VadConfig;          // Tune end-of-turn silence (advanced — see /sdk/vad)
}

Examples:

typescript
// Simple text
return {
  type: "speak",
  session_id: event.session.id,
  text: "Hello, how can I help you?",
};

// With SSML
return {
  type: "speak",
  session_id: event.session.id,
  ssml: `
    <speak version="1.0" xml:lang="en-US">
      <voice name="en-US-JennyNeural">
        <prosody rate="slow">Please listen carefully.</prosody>
        <break time="500ms"/>
        Your account balance is <say-as interpret-as="currency">$42.50</say-as>
      </voice>
    </speak>
  `,
};

// With custom TTS provider
return {
  type: "speak",
  session_id: event.session.id,
  text: "Hello in a different voice",
  tts: {
    provider: "azure",
    language: "en-US",
    voice: "en-US-JennyNeural",
  },
};

Audio Action ​

Plays pre-recorded audio to the user.

typescript
interface AiFlowActionAudio {
  type: "audio";
  session_id: string;
  audio: string; // Base64 encoded WAV (16kHz, mono, 16-bit)
  barge_in?: BargeInConfig;
}

Example:

typescript
// Play hold music or pre-recorded message
return {
  type: "audio",
  session_id: event.session.id,
  audio: base64EncodedWavData,
  barge_in: {
    strategy: "minimum_characters",
    minimum_characters: 3,
  },
};

Audio Format Requirements:

  • Format: WAV
  • Sample Rate: 16kHz
  • Channels: Mono
  • Bit Depth: 16-bit PCM
  • Encoding: Base64

Mix Audio Action ​

Play a looping background sound (e.g. train station, café, office) under the call. The loop plays continuously for the rest of the session — both during the assistant's TTS turns and during silences. Sending mix_audio again replaces the active loop; sending with stop: true removes it. The loop is dropped automatically when the session ends.

typescript
import { readFileSync } from "node:fs";

interface AiFlowActionMixAudio {
  type: "mix_audio";
  session_id: string;
  /** Base64-encoded WAV (16 kHz, mono, 16-bit PCM). Required unless stop=true. */
  audio?: string;
  /** Mix volume for the background loop, 0.0–1.0. Defaults to 0.5. */
  volume?: number;
  /** When true, removes the active background loop. */
  stop?: boolean;
}

Example — start an ambient loop alongside the greeting:

typescript
// Load and base64-encode the loop once at startup
const AMBIENT_AUDIO = readFileSync("./cafe.wav").toString("base64");

onSessionStart: async (event) => {
  return [
    {
      type: "mix_audio",
      session_id: event.session.id,
      audio: AMBIENT_AUDIO,
      volume: 0.3,
    },
    {
      type: "speak",
      session_id: event.session.id,
      text: "Welcome, how can I help you?",
    },
  ];
};

Example — stop the ambient before hanging up:

typescript
onUserSpeak: async (event) => {
  if (event.text.toLowerCase().includes("goodbye")) {
    return [
      { type: "mix_audio", session_id: event.session.id, stop: true },
      { type: "speak", session_id: event.session.id, text: "Goodbye!" },
      { type: "hangup", session_id: event.session.id },
    ];
  }
};

Audio Format Requirements: identical to the audio action — WAV, 16 kHz, mono, 16-bit PCM, base64-encoded. Same FFmpeg conversion command applies.

Best practice — keep ambient quiet. Background loops should sit under the agent's voice. Start around volume: 0.3 and adjust from there. Loudness-normalize source files to about -30 LUFS so different presets stay comparable at a given volume value.

Hangup Action ​

Ends the call.

typescript
interface AiFlowActionHangup {
  type: "hangup";
  session_id: string;
}

Example:

typescript
onUserSpeak: async (event) => {
  if (event.text.toLowerCase().includes("goodbye")) {
    return {
      type: "hangup",
      session_id: event.session.id,
    };
  }
};

Transfer Action ​

Transfers the call to another phone number. Pass an optional timeout to enable transfer fallback — if the target doesn't pick up (or rejects / hangs up), the service re-emits session_start with the same session.id so the agent can handle the call again. That event carries transfer_failed_reason telling you whether the target was busy, declined, never answered, or could not be reached at all.

typescript
interface AiFlowActionTransfer {
  type: "transfer";
  session_id: string;
  target_phone_number: string; // E.164 format without leading + recommended
  caller_id_name: string;
  caller_id_number: string;
  /** Optional transfer timeout in seconds (5–120). Enables transfer fallback. */
  timeout?: number;
}

Example:

typescript
// Transfer to sales department — fall back to the agent after 30s of no answer
return {
  type: "transfer",
  session_id: event.session.id,
  target_phone_number: "1234567890",
  caller_id_name: "Sales Department",
  caller_id_number: "1234567890",
  timeout: 30,
};

Barge-In Action ​

Manually triggers barge-in (interrupts current playback).

typescript
interface AiFlowActionBargeIn {
  type: "barge_in";
  session_id: string;
}

Example:

typescript
// Manually interrupt current playback
return {
  type: "barge_in",
  session_id: event.session.id,
};

Configure Transcription Action ​

Change the STT (Speech-to-Text) provider and/or recognition language(s) during an active call session without hanging up.

typescript
import { TranscriptionProvider } from "@sipgate/ai-flow-sdk";

interface AiFlowActionConfigureTranscription {
  type: "configure_transcription";
  session_id: string;
  provider?: TranscriptionProvider; // "AZURE" | "AZURE_VOICE_LIVE" | "DEEPGRAM" | "ELEVEN_LABS" | "SIPGATE_QWEN" | "SIPGATE_PARAKEET" — omit to keep current
  languages?: string[];             // BCP-47 codes, 1-4 entries — omit to reset to provider default
  custom_vocabulary?: string[];     // Words/phrases to boost STT recognition
  vad?: VadConfig;                  // Session-wide VAD tuning — see /sdk/vad
}

At least one of provider, languages, custom_vocabulary, or vad should be provided; sending none is a no-op.

Both fields use full replace semantics — they never merge with existing settings.

Examples:

typescript
// Switch to German
return {
  type: "configure_transcription",
  session_id: event.session.id,
  languages: ["de-DE"],
};

// Multi-language detection (German + English)
return {
  type: "configure_transcription",
  session_id: event.session.id,
  languages: ["de-DE", "en-US"],
};

// Switch STT provider to Deepgram
return {
  type: "configure_transcription",
  session_id: event.session.id,
  provider: "DEEPGRAM",
};

// Switch provider AND language in one step
return {
  type: "configure_transcription",
  session_id: event.session.id,
  provider: "DEEPGRAM",
  languages: ["en-US"],
};

// Reset to provider default (automatic detection)
return {
  type: "configure_transcription",
  session_id: event.session.id,
};

Audio gap during restart: Any change requires the transcription engine to restart. Audio during the restart (~100–500 ms for language-only change, ~200–800 ms for provider switch) is dropped.

Multi-language support depends on the active STT provider:

  • Azure: up to 4 languages, all used for simultaneous Language Identification (LID)
  • Azure Voice Live (experimental): multilingual auto-detection across all supplied languages
  • Deepgram: multilingual auto-detection across all supplied languages
  • ElevenLabs: single language only — only the first entry is used; additional entries are silently ignored
  • Qwen (hosted by sipgate) ("SIPGATE_QWEN") / Parakeet (hosted by sipgate) ("SIPGATE_PARAKEET"): single language only — only the first entry is used; additional entries are silently ignored

Barge-in latency after provider switch (for immediate strategy):

  • Azure: ~20–80 ms
  • Deepgram: ~20–100 ms
  • ElevenLabs: ~30–120 ms
  • Qwen / Parakeet (hosted by sipgate): ~30–120 ms

Type Safety ​

All actions are fully typed. Import types from the SDK:

typescript
import type {
  AiFlowAction,
  AiFlowActionSpeak,
  AiFlowActionAudio,
  AiFlowActionMixAudio,
  AiFlowActionHangup,
  AiFlowActionTransfer,
  AiFlowActionBargeIn,
  AiFlowActionConfigureTranscription,
} from "@sipgate/ai-flow-sdk";
import { TranscriptionProvider } from "@sipgate/ai-flow-sdk";

onUserSpeak: async (event) => {
  const action: AiFlowActionSpeak = {
    type: "speak",
    session_id: event.session.id,
    text: "Hello!",
  };
  return action;
};

Next Steps ​