# 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](/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](/tokens#scope-a-token). `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](/webhooks) 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](/tokens#mint-with-the-api) 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](/billing) lists the meters.
