> ## Documentation Index
> Fetch the complete documentation index at: https://docs.modulate.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Deepfake Detection Streaming

> Real-time deepfake detection over WebSocket, with per-frame verdicts and confidence scores delivered as analysis windows complete.

Real-time synthetic voice detection over WebSocket. Streams audio to the server and receives per-frame verdicts (`synthetic`, `non-synthetic`, or `no-content`) with confidence scores as analysis windows complete.

For a conceptual explanation of how detection works — including windowing, silence trimming, and the `no-content` verdict — see [Deepfake Detection](/get-started/deepfake).

## Endpoint

```text theme={null}
wss://platform.modulate.ai/api/velma-2-synthetic-voice-detection-streaming
```

## Authentication

Pass your API key as a query parameter when opening the connection.

```text theme={null}
wss://platform.modulate.ai/api/velma-2-synthetic-voice-detection-streaming?api_key=YOUR_API_KEY&audio_format=s16le&sample_rate=16000&num_channels=1
```

<Warning>
  Unlike the batch endpoint, the streaming API does not use an `X-API-Key` header. The key must be in the query string at connection time.
</Warning>

## Query parameters

| Parameter | Type | Required | Description |
| - | - | - | - |
| `api_key` | string | Yes | Your API key |
| `audio_format` | string | Yes | Audio encoding format — see [Deepfake Detection](/get-started/deepfake) |
| `sample_rate` | integer | Conditional | Required for raw (headerless) formats. One of: `8000`, `11025`, `16000`, `22050`, `32000`, `44100`, `48000`, `96000` |
| `num_channels` | integer | Conditional | Required for raw formats. 1–8 |

For supported format values and format selection guidance, see [Deepfake Detection](/get-started/deepfake).

## Connection flow

1. Connect with `api_key`, `audio_format`, and (for raw formats) `sample_rate` and `num_channels`.
2. Stream audio as **binary** WebSocket frames. Frames can be any size.
3. Receive `frame` JSON messages as analysis windows complete.
4. Send an **empty text frame** (`""`) to signal end of audio.
5. Receive a `done` message with total duration and frame count.
6. The connection closes automatically.

## Server messages

### Frame result

Sent each time an analysis window is complete.

```json theme={null}
{
  "type": "frame",
  "frame": {
    "start_time_ms": 0,
    "end_time_ms": 4000,
    "verdict": "synthetic",
    "confidence": 0.9732
  }
}
```

| Field | Type | Description |
| - | - | - |
| `start_time_ms` | integer | Frame start time in the audio stream (ms) |
| `end_time_ms` | integer | Frame end time in the audio stream (ms) |
| `verdict` | string | `"synthetic"`, `"non-synthetic"`, or `"no-content"` |
| `confidence` | float | Confidence in the verdict, 0.0–1.0 |

### Done

```json theme={null}
{
  "type": "done",
  "duration_ms": 12500,
  "frame_count": 10
}
```

| Field | Type | Description |
| - | - | - |
| `duration_ms` | integer | Total duration of the streamed audio in milliseconds |
| `frame_count` | integer | Total number of frames analyzed |

### Error

```json theme={null}
{
  "type": "error",
  "error": "Invalid audio_format='mid'. Valid values: ['3g2', '3ga', ...]"
}
```

## WebSocket close codes

| Code | Meaning |
| - | - |
| `1000` | Normal closure after a successful `done` message |
| `1003` | Invalid query parameters (bad format, sample rate, or channels) |
| `1011` | Internal server error |
| `4001` | The `api_key` query parameter is missing or invalid |
| `4002` | Audio could not be decoded or does not match the declared format |
| `4003` | The request is not permitted |
| `4004` | The API key does not have access to this model |
| `4029` | Insufficient credits |
| `4030` | Concurrent request limit reached |
| `4031` | Monthly usage limit reached |

An `error` JSON message is sent before the connection closes (except on `1000`).

## Rate limits

* Concurrent connection limits apply per model.
* A connection that exceeds a limit closes with `4029` (insufficient credits), `4030` (concurrent request limit), or `4031` (monthly usage limit).

## Related

* [Deepfake Detection](/get-started/deepfake) — windowing, silence trimming, and scoring explained
* [Deepfake Detection](/get-started/deepfake) — format options for the streaming endpoint
* [Which API should I use?](/guides/which-api) — batch vs streaming tradeoffs
* [Authentication and rate limits](/guides/authentication)


## AsyncAPI

````yaml api/velma_2_synthetic_voice_detection_streaming.yaml streaming-detection
id: streaming-detection
title: Streaming-detection
description: |
  ## WebSocket Close Codes
  - `1000`: Normal closure after the `done` message, or after the
    connection completes.
  - `1003`: Invalid or missing query parameters (unknown `audio_format`,
    invalid `sample_rate` or `num_channels`, a raw format missing
    `sample_rate`/`num_channels`, `sample_rate`/`num_channels` supplied
    without `audio_format`, or `audio_format` omitted). An `error` message
    is sent before the close.
  - `4002`: The audio could not be decoded, or does not match the
    declared raw `audio_format`. An `error` message is sent before the
    close.
  - `1011`: Internal server error. An `error` message is sent before the
    close.
  - `4001`: The `api_key` query parameter is missing or invalid. An
    `error` message is sent before the close.
  - `4003`: The request is not permitted. An `error` message is sent
    before the close.
  - `4004`: The API key does not have access to this model. An `error`
    message is sent before the close.
  - `4029`: The request could not be completed due to insufficient credits.
    An `error` message is sent before the close.
  - `4030`: Concurrent request limit reached. An `error` message is sent
    before the close.
  - `4031`: Monthly usage limit reached. An `error` message is sent before
    the close.
servers:
  - id: production
    protocol: wss
    host: platform.modulate.ai
    bindings: []
    variables: []
address: /api/velma-2-synthetic-voice-detection-streaming
parameters: []
bindings:
  - protocol: ws
    version: latest
    value:
      query:
        type: object
        required:
          - api_key
          - audio_format
        properties:
          api_key:
            type: string
            description: API key used for authentication and usage tracking.
          audio_format:
            type: string
            description: >
              Audio encoding format. Required for all connections. Raw formats

              (headerless samples) also require `sample_rate` and

              `num_channels`; container formats carry that metadata in the

              stream, so those parameters are ignored if supplied. The
              MP4-family

              values (`mp4`, `m4a`, `m4b`, `m4r`, `m4v`, `3gp`, `3gpp`,

              `3ga`, `3g2`, `f4a`, `f4b`) must be sent in a streamable

              layout; otherwise the connection ends with an

              audio-processing error.

              The raw `g722` and `vox` formats are mono-only (`num_channels`

              must be `1`).
            enum:
              - s8
              - s16le
              - s16be
              - s24le
              - s24be
              - s32le
              - s32be
              - u8
              - u16le
              - u16be
              - u24le
              - u24be
              - u32le
              - u32be
              - f32le
              - f32be
              - f64le
              - f64be
              - mulaw
              - alaw
              - g722
              - vox
              - 3g2
              - 3ga
              - 3gp
              - 3gpp
              - 8svx
              - aa3
              - aac
              - ac3
              - act
              - adts
              - aif
              - aifc
              - aiff
              - amb
              - amr
              - asf
              - at3
              - au
              - avr
              - awb
              - bwf
              - c2
              - caf
              - dss
              - dts
              - dtshd
              - eac3
              - ec3
              - f4a
              - f4b
              - flac
              - gsm
              - iff
              - m2a
              - m2ts
              - m4a
              - m4b
              - m4r
              - m4v
              - mka
              - mkv
              - mlp
              - mp+
              - mp1
              - mp2
              - mp3
              - mp4
              - mpa
              - mpc
              - mpga
              - mpp
              - mts
              - oga
              - ogg
              - ogx
              - oma
              - omg
              - opus
              - paf
              - pvf
              - qcp
              - ra
              - rf64
              - rm
              - rmvb
              - snd
              - svx
              - thd
              - ts
              - tta
              - voc
              - vqf
              - w64
              - wav
              - wave
              - weba
              - webm
              - wma
              - wmv
            examples: &ref_0
              - s16le
              - f32le
              - mulaw
              - webm
          sample_rate:
            type: integer
            description: |
              Sample rate in Hz. **Required** when `audio_format` is a raw
              format. Must not be specified without `audio_format`.
            enum:
              - 8000
              - 11025
              - 16000
              - 22050
              - 32000
              - 44100
              - 48000
              - 96000
            examples: &ref_1
              - 16000
              - 48000
          num_channels:
            type: integer
            description: |
              Number of audio channels. **Required** when `audio_format` is
              a raw format. Must be between 1 and 8. Must not be specified
              without `audio_format`.
            minimum: 1
            maximum: 8
            examples: &ref_2
              - 1
              - 2
    schemaProperties:
      - name: query
        type: object
        required: false
        properties:
          - name: api_key
            type: string
            description: API key used for authentication and usage tracking.
            required: true
          - name: audio_format
            type: string
            description: >
              Audio encoding format. Required for all connections. Raw formats

              (headerless samples) also require `sample_rate` and

              `num_channels`; container formats carry that metadata in the

              stream, so those parameters are ignored if supplied. The
              MP4-family

              values (`mp4`, `m4a`, `m4b`, `m4r`, `m4v`, `3gp`, `3gpp`,

              `3ga`, `3g2`, `f4a`, `f4b`) must be sent in a streamable

              layout; otherwise the connection ends with an

              audio-processing error.

              The raw `g722` and `vox` formats are mono-only (`num_channels`

              must be `1`).
            enumValues:
              - s8
              - s16le
              - s16be
              - s24le
              - s24be
              - s32le
              - s32be
              - u8
              - u16le
              - u16be
              - u24le
              - u24be
              - u32le
              - u32be
              - f32le
              - f32be
              - f64le
              - f64be
              - mulaw
              - alaw
              - g722
              - vox
              - 3g2
              - 3ga
              - 3gp
              - 3gpp
              - 8svx
              - aa3
              - aac
              - ac3
              - act
              - adts
              - aif
              - aifc
              - aiff
              - amb
              - amr
              - asf
              - at3
              - au
              - avr
              - awb
              - bwf
              - c2
              - caf
              - dss
              - dts
              - dtshd
              - eac3
              - ec3
              - f4a
              - f4b
              - flac
              - gsm
              - iff
              - m2a
              - m2ts
              - m4a
              - m4b
              - m4r
              - m4v
              - mka
              - mkv
              - mlp
              - mp+
              - mp1
              - mp2
              - mp3
              - mp4
              - mpa
              - mpc
              - mpga
              - mpp
              - mts
              - oga
              - ogg
              - ogx
              - oma
              - omg
              - opus
              - paf
              - pvf
              - qcp
              - ra
              - rf64
              - rm
              - rmvb
              - snd
              - svx
              - thd
              - ts
              - tta
              - voc
              - vqf
              - w64
              - wav
              - wave
              - weba
              - webm
              - wma
              - wmv
            examples: *ref_0
            required: true
          - name: sample_rate
            type: integer
            description: |
              Sample rate in Hz. **Required** when `audio_format` is a raw
              format. Must not be specified without `audio_format`.
            enumValues:
              - 8000
              - 11025
              - 16000
              - 22050
              - 32000
              - 44100
              - 48000
              - 96000
            examples: *ref_1
            required: false
          - name: num_channels
            type: integer
            description: |
              Number of audio channels. **Required** when `audio_format` is
              a raw format. Must be between 1 and 8. Must not be specified
              without `audio_format`.
            examples: *ref_2
            required: false
operations:
  - &ref_14
    id: sendAudio
    title: Send audio
    description: Stream audio data to the server.
    type: send
    messages:
      - &ref_19
        id: audioData
        contentType: application/octet-stream
        payload:
          - type: string
            format: binary
            description: A binary frame containing audio samples.
            x-parser-schema-id: <anonymous-schema-1>
            name: Audio Data
        headers: []
        jsonPayloadSchema:
          type: string
          format: binary
          description: |
            Audio data in the format declared by the `audio_format` query
            parameter. For raw formats this is headerless samples; for
            container formats this is the encoded byte stream. Frames may
            be any size; the server buffers internally.
          x-parser-schema-id: <anonymous-schema-1>
        title: Audio Data
        description: A binary frame containing audio samples.
        example: '{}'
        bindings: []
        extensions:
          - id: x-parser-unique-object-id
            value: audioData
    bindings: []
    extensions: &ref_3
      - id: x-parser-unique-object-id
        value: streaming-detection
  - &ref_15
    id: signalEnd
    title: Signal end
    description: Signal end of audio stream.
    type: send
    messages:
      - &ref_20
        id: endOfStream
        contentType: text/plain
        payload:
          - type: string
            const: ''
            x-parser-schema-id: <anonymous-schema-2>
            name: End of Stream
            description: >-
              An empty text frame signalling that the client has finished
              sending audio.
        headers: []
        jsonPayloadSchema:
          type: string
          const: ''
          x-parser-schema-id: <anonymous-schema-2>
        title: End of Stream
        description: >-
          An empty text frame signalling that the client has finished sending
          audio.
        example: '{}'
        bindings: []
        extensions:
          - id: x-parser-unique-object-id
            value: endOfStream
    bindings: []
    extensions: *ref_3
  - &ref_11
    id: receiveFrameResult
    title: Receive frame result
    description: Receive a per-frame detection result.
    type: receive
    messages:
      - &ref_16
        id: frameResult
        contentType: application/json
        payload:
          - name: Frame Result
            description: A single frame detection result.
            type: object
            properties:
              - name: type
                type: string
                description: frame
                required: true
              - name: frame
                type: object
                required: true
                properties:
                  - name: start_time_ms
                    type: integer
                    description: Frame start time in the original audio stream (ms).
                    examples: &ref_4
                      - 0
                    required: true
                  - name: end_time_ms
                    type: integer
                    description: Frame end time in the original audio stream (ms).
                    examples: &ref_5
                      - 4000
                    required: true
                  - name: verdict
                    type: string
                    description: >
                      - `synthetic` - the frame likely contains AI-generated
                      speech.

                      - `non-synthetic` - the frame likely contains natural
                      human speech.

                      - `no-content` - the frame is silent or contains no usable
                      audio.
                    enumValues:
                      - synthetic
                      - non-synthetic
                      - no-content
                    examples: &ref_6
                      - synthetic
                    required: true
                  - name: confidence
                    type: number
                    description: Confidence in the stated verdict (0-1).
                    examples: &ref_7
                      - 0.9732
                    required: true
        headers: []
        jsonPayloadSchema:
          type: object
          required:
            - type
            - frame
          properties:
            type:
              type: string
              const: frame
              x-parser-schema-id: <anonymous-schema-3>
            frame:
              type: object
              required:
                - start_time_ms
                - end_time_ms
                - verdict
                - confidence
              properties:
                start_time_ms:
                  type: integer
                  minimum: 0
                  description: Frame start time in the original audio stream (ms).
                  examples: *ref_4
                  x-parser-schema-id: <anonymous-schema-4>
                end_time_ms:
                  type: integer
                  minimum: 0
                  description: Frame end time in the original audio stream (ms).
                  examples: *ref_5
                  x-parser-schema-id: <anonymous-schema-5>
                verdict:
                  type: string
                  enum:
                    - synthetic
                    - non-synthetic
                    - no-content
                  description: >
                    - `synthetic` - the frame likely contains AI-generated
                    speech.

                    - `non-synthetic` - the frame likely contains natural human
                    speech.

                    - `no-content` - the frame is silent or contains no usable
                    audio.
                  examples: *ref_6
                  x-parser-schema-id: <anonymous-schema-6>
                confidence:
                  type: number
                  format: double
                  minimum: 0
                  maximum: 1
                  description: Confidence in the stated verdict (0-1).
                  examples: *ref_7
                  x-parser-schema-id: <anonymous-schema-7>
              x-parser-schema-id: Frame
          x-parser-schema-id: FrameResultMessage
        title: Frame Result
        description: A single frame detection result.
        example: |-
          {
            "type": "<string>",
            "frame": {
              "start_time_ms": 123,
              "end_time_ms": 123,
              "verdict": "<string>",
              "confidence": 123
            }
          }
        bindings: []
        extensions:
          - id: x-parser-unique-object-id
            value: frameResult
    bindings: []
    extensions: *ref_3
  - &ref_12
    id: receiveDone
    title: Receive done
    description: Receive the final summary when analysis is complete.
    type: receive
    messages:
      - &ref_17
        id: done
        contentType: application/json
        payload:
          - name: Done
            description: Analysis complete - all frames have been delivered.
            type: object
            properties:
              - name: type
                type: string
                description: done
                required: true
              - name: duration_ms
                type: integer
                description: Total duration of the streamed audio in milliseconds.
                examples: &ref_8
                  - 12500
                required: true
              - name: frame_count
                type: integer
                description: Total number of frames analysed.
                examples: &ref_9
                  - 10
                required: true
        headers: []
        jsonPayloadSchema:
          type: object
          required:
            - type
            - duration_ms
            - frame_count
          properties:
            type:
              type: string
              const: done
              x-parser-schema-id: <anonymous-schema-8>
            duration_ms:
              type: integer
              minimum: 0
              description: Total duration of the streamed audio in milliseconds.
              examples: *ref_8
              x-parser-schema-id: <anonymous-schema-9>
            frame_count:
              type: integer
              minimum: 0
              description: Total number of frames analysed.
              examples: *ref_9
              x-parser-schema-id: <anonymous-schema-10>
          x-parser-schema-id: DoneMessage
        title: Done
        description: Analysis complete - all frames have been delivered.
        example: |-
          {
            "type": "<string>",
            "duration_ms": 123,
            "frame_count": 123
          }
        bindings: []
        extensions:
          - id: x-parser-unique-object-id
            value: done
    bindings: []
    extensions: *ref_3
  - &ref_13
    id: receiveError
    title: Receive error
    description: Receive an error notification.
    type: receive
    messages:
      - &ref_18
        id: error
        contentType: application/json
        payload:
          - name: Error
            description: An error occurred during connection or analysis.
            type: object
            properties:
              - name: type
                type: string
                description: error
                required: true
              - name: error
                type: string
                description: Human-readable error description.
                examples: &ref_10
                  - Internal server error
                  - This request is not permitted.
                  - Missing API key.
                  - Invalid API key.
                  - This API key does not have access to this model.
                  - Insufficient credits.
                  - >-
                    Concurrent request limit reached. Please retry after your
                    in-flight requests complete.
                  - Monthly usage limit reached.
                  - Audio data does not match the declared audio_format.
                  - >-
                    The audio could not be processed. It may be corrupted or in
                    an unsupported format.
                  - >-
                    Invalid audio_format='mid'. Valid values: ['3g2', '3ga',
                    '3gp', '3gpp', '8svx', 'aa3', 'aac', 'ac3', 'act', 'adts',
                    'aif', 'aifc', 'aiff', 'alaw', 'amb', 'amr', 'asf', 'at3',
                    'au', 'avr', 'awb', 'bwf', 'c2', 'caf', 'dss', 'dts',
                    'dtshd', 'eac3', 'ec3', 'f32be', 'f32le', 'f4a', 'f4b',
                    'f64be', 'f64le', 'flac', 'g722', 'gsm', 'iff', 'm2a',
                    'm2ts', 'm4a', 'm4b', 'm4r', 'm4v', 'mka', 'mkv', 'mlp',
                    'mp+', 'mp1', 'mp2', 'mp3', 'mp4', 'mpa', 'mpc', 'mpga',
                    'mpp', 'mts', 'mulaw', 'oga', 'ogg', 'ogx', 'oma', 'omg',
                    'opus', 'paf', 'pvf', 'qcp', 'ra', 'rf64', 'rm', 'rmvb',
                    's16be', 's16le', 's24be', 's24le', 's32be', 's32le', 's8',
                    'snd', 'svx', 'thd', 'ts', 'tta', 'u16be', 'u16le', 'u24be',
                    'u24le', 'u32be', 'u32le', 'u8', 'voc', 'vox', 'vqf', 'w64',
                    'wav', 'wave', 'weba', 'webm', 'wma', 'wmv']
                  - >-
                    Raw audio formats require sample_rate and num_channels query
                    parameters
                  - >-
                    sample_rate and num_channels require audio_format to be
                    specified
                  - >-
                    Invalid sample_rate=50000. Valid values: [8000, 11025,
                    16000, 22050, 32000, 44100, 48000, 96000]
                  - Invalid num_channels=12. Must be between 1 and 8
                  - >-
                    audio_format query parameter is required. Example:
                    audio_format=s16le&sample_rate=16000&num_channels=1
                required: true
        headers: []
        jsonPayloadSchema:
          type: object
          required:
            - type
            - error
          properties:
            type:
              type: string
              const: error
              x-parser-schema-id: <anonymous-schema-11>
            error:
              type: string
              description: Human-readable error description.
              examples: *ref_10
              x-parser-schema-id: <anonymous-schema-12>
          x-parser-schema-id: ErrorResponse
        title: Error
        description: An error occurred during connection or analysis.
        example: |-
          {
            "type": "<string>",
            "error": "<string>"
          }
        bindings: []
        extensions:
          - id: x-parser-unique-object-id
            value: error
    bindings: []
    extensions: *ref_3
sendOperations:
  - *ref_11
  - *ref_12
  - *ref_13
receiveOperations:
  - *ref_14
  - *ref_15
sendMessages:
  - *ref_16
  - *ref_17
  - *ref_18
receiveMessages:
  - *ref_19
  - *ref_20
extensions:
  - id: x-parser-unique-object-id
    value: streaming-detection
securitySchemes: []

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.