Overview
Reality Defender provides a WebSocket interface for submitting real-time media to the backend platform for deepfake analysis. Each WebSocket connection corresponds to a single media stream and operates through a structured sequence of JSON-formatted request and response packets, alongside binary media data.
This article documents the full packet flow for the Live Media Scan interface, including connection setup, stream lifecycle management, media transmission, and protocol-level notices. It is intended for technical implementers building or maintaining a producer integration.
To retrieve analysis results for a specific session, use the /stream_results endpoint of the Session API. The same API Key used for the WebSocket connection may also be used with that REST API.
Prerequisites
Before establishing a WebSocket connection, ensure the following are in place:
API Key: Generated from the Reality Defender Dashboard. Must be passed as the
X-API-KEYheader when establishing the WebSocket connection.Session ID: A customer-provided identifier (
session_id) that associates the stream with a session on the Reality Defender backend. A UUID is recommended to ensure uniqueness. If uniqueness cannot be guaranteed, use the/stream_resultsendpoint to retrieve all streams associated with a givensession_id.Platform access: Your organization must have an active account on the Reality Defender platform, with familiarity with the RD Dashboard. Contact customer success if access is needed.
Packet Structure
All packets share a common structure: a type, a subtype, any required attributes, and a payload. There are three packet types:
request— Sent by the producer; always requires a response from the consumer.response— Sent by the consumer in reply to a request.notice— Sent by either party; does not require a response.
Step 1: Connection and Hello Notice
Upon establishing the WebSocket connection, the consumer sends a notice/hello to declare the protocol version and capability limits it supports. The producer does not respond to this notice, but must use it to ensure that the subsequent request/start is compliant.
{
"type": "notice",
"subtype": "hello",
"payload": {
"version": 2,
"version_min": 1,
"limits": {
"max_chunk_size_bytes": 800000,
"max_response_tout_ms": 6000,
"max_media_tout_ms": 10000,
"max_media_pause_tout_ms": 600000,
"max_delay_ms": 10000
},
"allowed_media": [
"audio/basic",
"audio/wav"
]
}
}Limit fields:
Field | Value | Description |
| 800000 | Maximum size per media chunk in bytes. |
| 6000 | Maximum time the producer should wait for a response. |
| 10000 | Maximum time the consumer will wait without receiving media (enforced for v2 producers). |
| 600000 | Maximum time a stream may remain paused before the consumer closes the session (10 minutes). |
| 10000 | Maximum delay duration the consumer may request in a single delay notice. |
Step 2: Stream Start Request/Response
The producer initiates the stream by sending a request/start. This must be the first request after the hello notice.
{
"type": "request",
"subtype": "start",
"version": 2,
"session_id": "session-123",
"media_type": "audio/wav",
"payload": {
"bitrate": 128000,
"analysis_channel": "1.1",
"primary_source_id": "phone_number",
"source_ids": {
"phone_number": "+1234567890",
"display_name": "John Doe",
"file_name": "call-123-audio.wav",
"email": "johndoe@example.com"
},
"metadata": {},
"properties": {
"direction": "inbound",
"session_type": "call"
}
}
}
Field notes:
version: Declares the protocol version the producer intends to use. Omitting this field causes the consumer to treat the session as version 1. An unrecognised value results in an error response and the connection is closed.bitrate: A hint to the consumer about the duration of each media chunk. Omit this field for static file types (e.g.image/jpeg) or when the bitrate is unknown. For variable bitrate media, set this to the average nominal bitrate.analysis_channel: Specifies thetrack.channelto analyse in multi-track or multi-channel media. Track and channel numbers are 1-based (e.g.1.1= first channel of the first track). Omit for single-channel media.primary_source_id: Must match one of the keys present in thesource_idsmap. Optional.source_ids: A map of identifying fields for the media source. Custom fields may be included; by convention, custom keys should begin withx_(e.g.x_cisco_ucid).metadata: Opaque properties to Reality Defender that the producer wants associated with the session.properties.direction: Accepted values:"inbound","outbound","unknown".properties.session_type: Accepted values:"call","file","unknown".properties.test: Optional boolean, defaults tofalse.
Paused Stream Start
A stream may be started in a paused state by including "paused": true in the payload. In this mode, the consumer acknowledges the start request normally, but the producer must not send media until it receives a notice/transmission_start from the consumer.
{
"type": "request",
"subtype": "start",
"version": 2,
"session_id": "session-123",
"media_type": "audio/basic",
"payload": {
"paused": true
}
}
Note: If the producer sends binary media before receiving notice/transmission_start, the paused state is automatically cleared and the media is processed normally.
Start Response — Success
{
"type": "response",
"subtype": "start",
"status": "success",
"payload": {
"stream_id": "uuid-123"
}
}
The consumer returns a UUID (stream_id) that uniquely identifies this stream on the backend. All subsequent requests must include this stream_id.
Start Response — Failure
{
"type": "response",
"subtype": "start",
"status": "fail",
"payload": {
"code": "INVALID_API_KEY",
"message": "The API key is either missing or invalid"
}
}
If the start request fails, the consumer closes the connection.
Step 3: Sending Media Chunks
Once a successful start response is received (or once notice/transmission_start is received for paused streams), the producer may begin sending media as binary chunks over the WebSocket connection.
Chunks must not exceed the
max_chunk_size_byteslimit advertised in the hello notice.For constant bitrate encodings, the consumer calculates time offsets based on the declared bitrate.
For variable bitrate encodings, the media is expected to be in a container that provides timing information.
The producer must maintain a steady stream of media. If no media is received and the stream is not paused, and the gap exceeds
max_media_tout_ms, the consumer will generate a timeout error and close the session.
WAV container note: When using WAV containers for streaming (where the total length is unknown), set the Data Length field to 0xFFFFFFFF in both the main header and the data segment. If the total length is known (e.g. when sending a static file), the length may be set correctly.
Step 4: Stream Pause Request/Response (v2 only)
If the producer is temporarily unable to send media, it may issue a request/pause. While paused, the media idle timeout is suspended and the max_media_pause_tout_ms timeout applies instead. The paused state is automatically cancelled when the producer resumes sending binary media.
Note: The pause request is only available to version 2 producers. Sending it from a version 1 producer will return an error response.
{
"type": "request",
"subtype": "pause",
"stream_id": "uuid-123"
}Pause Response — Success
{
"type": "response",
"subtype": "pause",
"status": "success",
"payload": {
"stream_id": "uuid-123"
}
}Note: Only the success response is defined for the pause request. If the pause request is invalid (e.g. sent by a version 1 producer), the consumer will return an error notice and close the session.
Pause Expiring Notice
If the pause timeout is approaching, the consumer sends a notice/pause_expiring to warn the producer that the session will be closed if media is not resumed within 30 seconds.
{
"type": "notice",
"subtype": "pause_expiring",
"stream_id": "uuid-123",
"payload": {
"expires_in_ms": 30000
}
}Upon receiving this notice, the producer has two options:
Resume media — Begin sending binary media chunks to cancel the paused state and continue the session normally.
Re-issue the pause request — Send another
request/pausewith the samestream_idto reset the pause timer for a furthermax_media_pause_tout_ms. This may be repeated as many times as necessary and is the recommended approach when the producer expects to remain unable to send media for an extended period.
Step 5: Stream Stop Request/Response
To complete the session, the producer must send a request/stop and wait for the corresponding response before closing the connection. No further requests are permitted after a stop is successfully processed.
{
"type": "request",
"subtype": "stop",
"stream_id": "uuid-123",
"payload": {
"reason": "NORMAL"
}
}Reason values:
Value | Description |
| All media was sent successfully. |
| An error occurred on the producer side prior to completion. |
| The producer did not receive a timely response from the consumer. |
Stop Response — Success
{
"type": "response",
"subtype": "stop",
"status": "success",
"payload": {
"stream_id": "uuid-123",
"total_bytes": 1024000,
"stream_start": "2024-01-15T10:30:00.123Z",
"stream_stop": "2024-01-15T10:32:08.623Z"
}
}The producer may use the payload attributes for verification. After receiving a successful stop response, the producer must close the connection.
Stop Response — Failure
{
"type": "response",
"subtype": "stop",
"status": "fail",
"payload": {
"code": "INVALID_STREAM_ID",
"message": "The stream id is either missing or invalid"
}
}The consumer closes the connection after sending either a success or failure stop response.
Consumer-Initiated Notices
In addition to responding to producer requests, the consumer may send the following notices at any point during a session.
Stream Delay Notice
If the producer is sending media faster than real-time (typically when transmitting a pre-recorded file) and the consumer is experiencing a backlog, the consumer will request a delay.
{
"type": "notice",
"subtype": "delay",
"stream_id": "uuid-123",
"payload": {
"delay_ms": 1350
}
}The producer should pause transmission for the specified duration before resuming. The delay will not exceed max_delay_ms as advertised in the hello notice.
Transmission Start Notice (v2 only)
When a stream is started in the paused state, the consumer sends notice/transmission_start to signal that the producer should begin sending media. This is triggered by a backend signal.
{
"type": "notice",
"subtype": "transmission_start",
"stream_id": "uuid-123"
}Upon receiving this notice, the producer should begin sending media chunks as soon as possible. The media idle timeout (max_media_tout_ms) is now in effect.
Transmission Stop Notice
The consumer may instruct the producer to stop transmitting media. Upon receiving this notice, the producer should issue a request/stop and close the connection.
{
"type": "notice",
"subtype": "transmission_stop",
"stream_id": "uuid-123",
"payload": {
"reason": "analysis_complete"
}
}Reason values:
Value | Description |
| Deepfake analysis has completed. Results are available via the |
| The transmission ended normally. |
| The transmission ended due to an error condition. |
| The transmission ended because a timeout was exceeded. |
Error Notice
Any protocol violation (e.g. a media chunk exceeding the maximum size) will cause the consumer to generate an error notice and close the session.
{
"type": "notice",
"subtype": "error",
"stream_id": "uuid-123",
"payload": {
"message": "Media chunk exceeds the maximum size."
}
}Keepalive Behavior
The consumer sends WebSocket Ping frames at a regular interval (default: every 30 seconds).
The producer's WebSocket implementation is expected to respond automatically with Pong frames.
If a Pong is not received within the Pong timeout (default: 10 seconds), the consumer increments an internal missed-pong counter.
If the number of consecutive missed Pongs exceeds the configured threshold (default: 2), the consumer closes the connection.
Change Log: v2 vs. v1
This section is intended for producers with an existing v1 integration.
# | Change | Details |
1 | Protocol version field | A |
2 | Hello notice version | The hello notice now advertises |
3 | Paused stream start | A new |
4 |
| New consumer notice sent to a paused stream when the backend signals that transmission should begin. |
5 |
| Replaces |
6 | Media idle timeout corrected |
|
7 |
| The pause request is not available to version 1 producers and will return an error response if attempted. |