Skip to content

Recording and VOD ​

Record live broadcasts, then play them back as HLS or download them with S3 tools.

The commands reuse API, MOQ_API_TOKEN, PID, and KID from the quickstart. The project's Recordings page does the same through the dashboard.

Record broadcasts ​

A recording rule records every broadcast whose path matches one of its patterns, from the moment it goes live. This records everything under cameras and keeps it for 7 days:

sh
curl --fail-with-body --silent --show-error "$API/projects/$PID/recording/rules" \
  -H "Authorization: Bearer $MOQ_API_TOKEN" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: "recording-rule-1"' \
  --data '{"label":"Cameras","patterns":["cameras/**"],"retentionDays":7}'

Patterns are relative to the project and use the same grammar as tokens. retentionDays is 1, 7, 30, 90, 180, or 365; more than 7 needs a payment method. Set vodEnabled to false to pause a rule without deleting it. The account token needs media:write.

Your own bucket ​

To keep recordings in an S3-compatible bucket you own, add bucket to the rule with an endpoint, region, bucket name, and a key that can write to it. Your bucket's lifecycle owns retention, and the secret is never returned. Set delivery to true, with a key that can also read, to play recordings back through the CDN.

List recordings ​

sh
curl --fail-with-body --silent --show-error "$API/projects/$PID/recording/sessions" \
  -H "Authorization: Bearer $MOQ_API_TOKEN" | jq '.items[] | {id, broadcastPath, status, durationMs}'

A recording is LIVE while its broadcast is, then ENDED. To follow changes, pass the response's sinceCursor back as since. A webhook for recording.ready saves polling.

Play a recording ​

sh
REC=<recording id>
PLAY=$(curl --fail-with-body --silent --show-error "$API/projects/$PID/recording/sessions/$REC/play" \
  -H "Authorization: Bearer $MOQ_API_TOKEN")
URL=$(printf '%s' "$PLAY" | jq -er '.url')
VOD_TOKEN=$(printf '%s' "$PLAY" | jq -er '.token')
ffplay -headers "Authorization: Bearer $VOD_TOKEN" "$URL"

url is an HLS playlist, and token grants that recording's playlists and media until expiresAt. Send the token as an Authorization: Bearer header or as the jwt query parameter. Call play again for a fresh one. A recording still LIVE has a growing playlist. The account token needs media:read.

The player is any HLS player. To embed one, give your page the URL and token from your server, never the account token.

Download with S3 tools ​

Managed recordings are readable through an S3-compatible endpoint, so aws-cli, rclone, and S3 SDKs can list and download them. Fetch the project's credentials once:

sh
S3=$(curl --fail-with-body --silent --show-error "$API/projects/$PID/recording/s3" \
  -H "Authorization: Bearer $MOQ_API_TOKEN")

The credentials alone read nothing. Each request also needs a media token that subscribes to the broadcasts you want, as the session token. Mint one with subscribe: ["**"] for everything, set S3_TOKEN to it, then:

sh
export AWS_ACCESS_KEY_ID=$(printf '%s' "$S3" | jq -er '.accessKeyId')
export AWS_SECRET_ACCESS_KEY=$(printf '%s' "$S3" | jq -er '.secretAccessKey')
export AWS_SESSION_TOKEN="$S3_TOKEN"
export AWS_REGION=auto
ENDPOINT=$(printf '%s' "$S3" | jq -er '.endpoint')
BUCKET=$(printf '%s' "$S3" | jq -er '.bucket')
aws s3 ls --recursive "s3://$BUCKET/" --endpoint-url "$ENDPOINT"

Use path-style addressing; any region signs. Only the project owner can fetch the credentials, and they need keys:write. Recordings in your own bucket are not listed here.

Delete ​

Delete one recording with DELETE /v1/projects/{pid}/recording/sessions/{id}, or every recording a rule holds with DELETE /v1/projects/{pid}/recording/rules/{id}/sessions. Storage drains in the background and is metered until it is gone. To delete a rule, set its vodEnabled to false and delete its recordings first.

Cost ​

Recording bills for each GB written and stored, and playback and downloads bill as delivery. Usage and billing lists the meters.