{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://jambonz.org/schema/verbs/listen",
  "minVersion": "0.9.6",
  "title": "Listen",
  "description": "Streams real-time call audio to an external websocket endpoint. The remote endpoint receives raw audio and can optionally send audio back (bidirectional). Used for custom speech processing, real-time analysis, AI agent integration, and recording to external systems.",
  "type": "object",
  "properties": {
    "verb": {
      "const": "listen",
      "description": "The verb name."
    },
    "id": {
      "type": "string",
      "description": "An optional unique identifier for this verb instance."
    },
    "url": {
      "type": "string",
      "format": "uri",
      "description": "The websocket URL to stream audio to.",
      "examples": [
        "wss://myapp.example.com/audio-stream"
      ]
    },
    "actionHook": {
      "$ref": "../components/actionHook",
      "description": "A webhook invoked when the listen session ends. Should return the next verbs to execute."
    },
    "wsAuth": {
      "$ref": "../components/auth",
      "description": "Authentication credentials for the websocket connection."
    },
    "mixType": {
      "type": "string",
      "description": "How to mix the audio channels when streaming. 'mono' sends a single mixed channel, 'stereo' sends caller and callee as separate left/right channels, 'mixed' sends both as a single mixed stream.",
      "enum": [
        "mono",
        "stereo",
        "mixed"
      ],
      "default": "mono"
    },
    "metadata": {
      "type": "object",
      "description": "Arbitrary metadata to send to the websocket endpoint in the initial connection message.",
      "additionalProperties": true
    },
    "sampleRate": {
      "type": "number",
      "description": "The audio sample rate in Hz.",
      "examples": [
        8000,
        16000,
        24000
      ],
      "default": 8000
    },
    "finishOnKey": {
      "type": "string",
      "description": "A DTMF key that ends the listen session when pressed.",
      "examples": [
        "#"
      ]
    },
    "maxLength": {
      "type": "number",
      "description": "Maximum duration in seconds for the listen session."
    },
    "passDtmf": {
      "type": "boolean",
      "description": "If true, forward DTMF events to the websocket endpoint."
    },
    "playBeep": {
      "type": "boolean",
      "description": "If true, play a beep tone before streaming begins."
    },
    "disableBidirectionalAudio": {
      "type": "boolean",
      "description": "If true, disable receiving audio from the websocket endpoint. Audio flows only from the call to the websocket, not back."
    },
    "bidirectionalAudio": {
      "$ref": "../components/bidirectionalAudio",
      "description": "Fine-grained configuration for bidirectional audio."
    },
    "timeout": {
      "type": "number",
      "description": "Time in seconds to wait for audio activity before ending the listen session."
    },
    "transcribe": {
      "$ref": "transcribe",
      "description": "Nested transcribe verb — enables simultaneous real-time transcription of the audio being streamed."
    },
    "earlyMedia": {
      "type": "boolean",
      "description": "If true, begin streaming audio before the call is formally answered."
    },
    "channel": {
      "type": "number",
      "description": "Specific audio channel to stream. Used when streaming a single channel of a multi-channel call."
    }
  },
  "required": [
    "url"
  ],
  "examples": [
    {
      "verb": "listen",
      "url": "wss://myapp.example.com/audio-stream",
      "actionHook": "/listen-complete",
      "sampleRate": 16000,
      "mixType": "stereo"
    },
    {
      "verb": "listen",
      "url": "wss://myapp.example.com/ai-agent",
      "bidirectionalAudio": {
        "enabled": true,
        "streaming": true,
        "sampleRate": 24000
      },
      "metadata": {
        "callType": "support",
        "language": "en-US"
      }
    }
  ]
}
