Skip to content

Webhooks

Flex Video integrates with MediaMTX via webhooks to automatically create pipelines when streams are published.

Overview

When a stream is published to MediaMTX (via RTSP, RTMP, or WebRTC), MediaMTX triggers a webhook that:

  1. Creates an ephemeral pipeline
  2. Transcodes the incoming stream
  3. Outputs to the Flex Video RTSP server
  4. Cleans up when the stream ends

MediaMTX Configuration

MediaMTX is pre-configured to call Flex Video webhooks:

# mediamtx.yml (in flex-mtx container)
runOnPublish: >
  curl -X PUT -H "X-API-Key: $FLEX_API_KEY"
  "http://127.0.0.1:3539/flex/triggers/mediaMtx/publish?path=$MTX_PATH"

runOnUnpublish: >
  curl -X DELETE -H "X-API-Key: $FLEX_API_KEY"
  "http://127.0.0.1:3539/flex/triggers/mediaMtx/publish?path=$MTX_PATH"

Webhook Endpoints

Stream Published

PUT /flex/triggers/mediaMtx/publish

Called when a stream starts publishing to MediaMTX.

Query Parameters:

Parameter Description
path MediaMTX stream path
pipelineId Optional custom pipeline ID

Headers:

X-API-Key: <FLEX_API_KEY>

Response:

{
  "status": "ok",
  "pipelineId": "stream-name",
  "action": "play"
}

Stream Unpublished

DELETE /flex/triggers/mediaMtx/publish

Called when a stream stops publishing.

Query Parameters:

Parameter Description
path MediaMTX stream path
pipelineId Optional custom pipeline ID

Response:

{
  "status": "ok",
  "pipelineId": "stream-name",
  "action": "stop"
}

Pipeline Creation

When the publish webhook is triggered:

  1. Pipeline ID is derived from the stream path (sanitized)
  2. Source is set to rtsp://127.0.0.1:8554/{path}
  3. Output is assigned a port in the 50000-55000 range
  4. KLV passthrough and extraction are enabled by default
  5. Pipeline is started automatically

Default Configuration

Triggered pipelines use these defaults:

{
  "mode": "simple",
  "on_demand": false,
  "source": {
    "uri": "rtsp://127.0.0.1:8554/<path>",
    "latency_ms": 200
  },
  "encoding": {
    "codec": "h264",
    "bitrate": 2000,
    "width": 1920,
    "height": 1080,
    "fps": 30,
    "quality": 7
  },
  "output": {
    "uri": "rtsp://0.0.0.0:<auto-port>/<pipeline-id>"
  },
  "klv_config": {
    "pass_klv": true,
    "auto_extract_geolocation": true
  }
}

Pipeline ID Sanitization

Pipeline IDs are sanitized to remove illegal characters:

Input Path Pipeline ID
live/camera-1 livecamera-1
stream.test streamtest
cam@123 cam123

Only alphanumeric, dashes, and underscores are allowed.

Authentication

Webhook endpoints require API key authentication:

curl -X PUT \
  -H "X-API-Key: your-api-key" \
  "http://localhost:3539/flex/triggers/mediaMtx/publish?path=live/stream"

The API key is shared between containers via the FLEX_API_KEY environment variable.

Use Cases

OBS Streaming

  1. Configure OBS to stream to rtmp://server:1935/live/mystream
  2. MediaMTX receives the stream
  3. Webhook creates a transcoding pipeline
  4. Output available at rtsp://server:8731/mystream

RTSP Camera

  1. Configure camera to push to rtsp://server:8554/camera1
  2. MediaMTX receives the stream
  3. Webhook creates a transcoding pipeline
  4. Output available at rtsp://server:8731/camera1

WebRTC Ingest

  1. Use MediaMTX WebRTC API to publish
  2. Webhook creates a transcoding pipeline
  3. Output available as RTSP for broader compatibility

Manual Testing

Test webhooks without MediaMTX:

# Simulate publish
curl -X PUT \
  -H "X-API-Key: $FLEX_API_KEY" \
  "http://localhost:3539/flex/triggers/mediaMtx/publish?path=test-stream"

# Check pipeline created
curl http://localhost:3539/flex/pipeline/test-stream

# Simulate unpublish
curl -X DELETE \
  -H "X-API-Key: $FLEX_API_KEY" \
  "http://localhost:3539/flex/triggers/mediaMtx/publish?path=test-stream"

Troubleshooting

Pipeline Not Created

  1. Check MediaMTX logs: docker logs flex-mtx
  2. Verify FLEX_API_KEY matches in both containers
  3. Check API logs: docker logs flex-manager

Authentication Failed

{"error": "Unauthorized"}

Ensure X-API-Key header is set and matches FLEX_API_KEY.

Pipeline Cleanup Failed

If pipelines aren't cleaned up:

  1. Check if unpublish webhook fired
  2. Manually delete: curl -X DELETE http://localhost:3539/flex/pipeline/<id>

Port Exhaustion

If ports 50000-55000 are exhausted:

  1. Stop unused pipelines
  2. Check for zombie pipelines
  3. Restart flex-manager to reset port allocation