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

# Mux

> Connect Mux video infrastructure to Mixpeek for automated video asset processing

## Overview

[Mux](https://mux.com) is a video infrastructure platform for building video experiences. By connecting Mux to Mixpeek, you can automatically process your video assets through feature extraction pipelines — enabling search, classification, and analysis across your entire video library.

## Prerequisites

* A Mux account with video assets
* A Mux access token with **Mux Video** read permissions
* A Mixpeek account with an active namespace
* **Static renditions or MP4 support enabled on your Mux assets** (see below)

<Warning>
  **Static renditions are required.** By default, Mux assets only have HLS streaming — no downloadable MP4 files. Mixpeek needs MP4 renditions to download and process your videos. Assets without static renditions will be **skipped** during sync.

  Enable static renditions when creating assets:

  ```json theme={null}
  {
    "input": [{"url": "https://example.com/video.mp4"}],
    "playback_policy": ["public"],
    "static_renditions": [{"resolution": "720p"}]
  }
  ```

  Or enable them on existing assets in the [Mux Dashboard](https://dashboard.mux.com) under each asset's settings.
</Warning>

## Configuration

### Connection-level fields

| Field                 | Required | Description                                                                                                                                                                                                   |
| --------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `access_token_id`     | Yes      | Mux access token ID (UUID format)                                                                                                                                                                             |
| `access_token_secret` | Yes      | Mux access token secret                                                                                                                                                                                       |
| `webhook_secret`      | No       | Shared signing secret for inbound Mux webhooks. Required only if you want Mixpeek to cascade-delete objects when assets are deleted in Mux (see [Cascade delete via webhooks](#cascade-delete-via-webhooks)). |

### Sync-level fields

| Field                           | Required | Default      | Description                                                                                                                                   |
| ------------------------------- | -------- | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `source_path`                   | No       | `mux://`     | Sync all assets, or `mux://{asset_id}` for a specific asset                                                                                   |
| `sync_mode`                     | No       | `continuous` | `initial_only` or `continuous`                                                                                                                |
| `polling_interval_seconds`      | No       | 300          | How often to check for new assets (continuous mode)                                                                                           |
| `file_filters.metadata_filters` | No       | —            | Array of metadata filter rules applied to Mux asset fields (see [Metadata filtering](#metadata-filtering))                                    |
| `reconcile_on_sync`             | No       | `false`      | Re-check previously indexed assets on each sync and unindex any that no longer match metadata filters (see [Reconciliation](#reconciliation)) |

## Setup

<Steps>
  <Step title="Create a Mux access token">
    1. Go to [Mux Dashboard → Settings → Access Tokens](https://dashboard.mux.com/settings/access-tokens)
    2. Click **Generate new token**
    3. Select **Mux Video** with **Read** permissions
    4. Copy the **Token ID** and **Token Secret** immediately — the secret is only shown once
  </Step>

  <Step title="Create the connection in Mixpeek">
    In the Mixpeek Studio, go to **Settings → Storage Connections → Add Connection** and select **Mux**.

    Or via the API:

    <CodeGroup>
      ```python Python theme={null}
      from mixpeek import Mixpeek

      client = Mixpeek(api_key="YOUR_API_KEY")

      connection = client.organizations.connections.create(
          name="Mux Production",
          provider_type="mux",
          provider_config={
              "credentials": {
                  "type": "access_token",
                  "access_token_id": "a3b02074-dbca-47b6-...",
                  "access_token_secret": "Am9+RGn2mhmz..."
              }
          },
          test_before_save=True
      )
      ```

      ```javascript JavaScript theme={null}
      import Mixpeek from "mixpeek";

      const client = new Mixpeek({ apiKey: "YOUR_API_KEY" });

      const connection = await client.organizations.connections.create({
        name: "Mux Production",
        provider_type: "mux",
        provider_config: {
          credentials: {
            type: "access_token",
            access_token_id: "a3b02074-dbca-47b6-...",
            access_token_secret: "Am9+RGn2mhmz...",
          },
        },
        test_before_save: true,
      });
      ```

      ```bash cURL theme={null}
      curl -X POST https://api.mixpeek.com/v1/organizations/connections \
        -H "Authorization: Bearer YOUR_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "name": "Mux Production",
          "provider_type": "mux",
          "provider_config": {
            "credentials": {
              "type": "access_token",
              "access_token_id": "a3b02074-dbca-47b6-...",
              "access_token_secret": "Am9+RGn2mhmz..."
            }
          },
          "test_before_save": true
        }'
      ```
    </CodeGroup>
  </Step>

  <Step title="Create a bucket with Mux sync">
    Create a bucket and configure it to sync from your Mux connection:

    ```python Python theme={null}
    bucket = client.buckets.create(
        namespace_id="your-namespace-id",
        name="mux-videos",
        description="Video assets from Mux",
        blob_type="video"
    )

    sync = client.buckets.syncs.create(
        namespace_id="your-namespace-id",
        bucket_id=bucket.bucket_id,
        connection_id=connection.connection_id,
        source_path="mux://",
        sync_mode="continuous",
        polling_interval_seconds=300
    )
    ```
  </Step>

  <Step title="Verify ingestion">
    Monitor the sync status in Studio or via the API. Video assets in `ready` status will be automatically downloaded and processed through your collection's feature extractors.
  </Step>
</Steps>

## Mux metadata on objects and retriever results

When the connector syncs a Mux asset into a bucket, it captures the Mux identifiers and exposes them as **`source_metadata`** on the resulting bucket object. This metadata flows through unchanged to downstream documents and is returned alongside every retriever match — so your application can render results directly from Mux without falling back to the S3 mirror.

| Field             | Description                                                                                               |
| ----------------- | --------------------------------------------------------------------------------------------------------- |
| `asset_id`        | Mux asset ID — use to look the asset up via the Mux API                                                   |
| `playback_id`     | Primary public/signed playback ID                                                                         |
| `playback_ids`    | Full list of playback IDs on the asset                                                                    |
| `playback_url`    | HLS manifest URL (`https://stream.mux.com/{playback_id}.m3u8`) ready for `<mux-player>` or any HLS client |
| `thumbnail_url`   | Default Mux thumbnail (`https://stream.mux.com/{playback_id}/thumbnail.jpg`)                              |
| `duration`        | Asset duration in seconds                                                                                 |
| `resolution_tier` | Source quality tier (e.g. `1080p`, `1440p`)                                                               |
| `status`          | Mux asset status at sync time                                                                             |
| `aspect_ratio`    | Asset aspect ratio (e.g. `16:9`)                                                                          |

Example object payload:

```json theme={null}
{
  "object_id": "obj_7fa70fd60a0547152df57cff",
  "bucket_id": "bkt_648b4be8",
  "source_metadata": {
    "asset_id": "5sCF1Yk3rC0102zMVEh74jJE9pT6KFeZ1N8gcQZ3l53FI",
    "playback_id": "YGDmuLw7AOiQKwvCZbHAGjdZRZwxMqqg1iBELyJig5E",
    "playback_url": "https://stream.mux.com/YGDmuLw7AOiQKwvCZbHAGjdZRZwxMqqg1iBELyJig5E.m3u8",
    "thumbnail_url": "https://stream.mux.com/YGDmuLw7AOiQKwvCZbHAGjdZRZwxMqqg1iBELyJig5E/thumbnail.jpg",
    "duration": 23.86,
    "resolution_tier": "1080p",
    "status": "ready",
    "aspect_ratio": "16:9"
  }
}
```

In retriever results, the same `source_metadata` is attached to each match. A typical UI flow is:

```javascript theme={null}
// Each search result carries the original Mux IDs — no S3 hop needed
results.forEach((match) => {
  const { playback_id, playback_url, thumbnail_url } = match.source_metadata;
  renderMuxPlayer({ playbackId: playback_id, poster: thumbnail_url });
});
```

## Webhooks: delete and update

Mixpeek handles two Mux webhook event types to keep your index in sync with Mux automatically.

### How it works

1. Mux POSTs events to a Mixpeek endpoint that includes your `connection_id`.
2. Mixpeek verifies the `Mux-Signature` header against the `webhook_secret` stored on that connection.
3. **`video.asset.deleted`** — Mixpeek finds every object synced from that Mux asset and deletes them, cascading through `OBJECT_DELETED` to remove derived documents from your collections.
4. **`video.asset.updated`** — Mixpeek re-fetches the asset's current metadata from Mux and re-evaluates it against each sync config's `metadata_filters`. If a previously non-matching asset now matches, it becomes eligible for indexing on the next sync. If the asset no longer matches **and `reconcile_on_sync` is enabled**, the corresponding objects are unindexed. Without `reconcile_on_sync`, the event is acknowledged but no objects are removed.

### Setup

<Steps>
  <Step title="Generate a signing secret and attach it to the connection">
    Pick any high-entropy string (32+ chars) and store it as `webhook_secret` in the Mux connection's credentials. You can set it at create time or patch an existing connection.

    ```bash cURL theme={null}
    curl -X PATCH https://api.mixpeek.com/v1/organizations/connections/{connection_id} \
      -H "Authorization: Bearer YOUR_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "provider_config": {
          "credentials": {
            "type": "access_token",
            "access_token_id": "...",
            "access_token_secret": "...",
            "webhook_secret": "your-32-char-random-string"
          }
        }
      }'
    ```
  </Step>

  <Step title="Register the webhook in the Mux dashboard">
    In the [Mux Dashboard → Settings → Webhooks](https://dashboard.mux.com/settings/webhooks), add a new endpoint:

    * **URL:** `https://api.mixpeek.com/v1/webhooks/mux/{connection_id}` — replace `{connection_id}` with the Mixpeek connection ID returned when you created the connection.
    * **Signing secret:** the **same** value you put in `webhook_secret`.
    * **Events:** at minimum `video.asset.deleted` and `video.asset.updated`. You can subscribe to additional events; Mixpeek will acknowledge them and ignore any it doesn't act on.
  </Step>

  <Step title="Verify with a test delete">
    Delete a synced asset in Mux (or use the dashboard's "Send test event" button) and confirm the corresponding object disappears from your bucket. The webhook returns a JSON body documenting what it did:

    ```json theme={null}
    {
      "received": true,
      "event_type": "video.asset.deleted",
      "handled": true,
      "asset_id": "5sCF1Yk3rC0102zMVEh74jJE9pT6KFeZ1N8gcQZ3l53FI",
      "deleted_objects": 1
    }
    ```
  </Step>
</Steps>

### Signature format

Mixpeek follows the same scheme Mux documents for outgoing webhooks:

* Header: `Mux-Signature: t=<unix_ts>,v1=<hex_hmac_sha256>`
* HMAC computed as `HMAC_SHA256(webhook_secret, f"{t}.{raw_body}")` over the **exact raw bytes** of the request body.
* Signatures are compared with `hmac.compare_digest` to avoid timing attacks.

### Response codes

| Status | Meaning                                                                                         |
| ------ | ----------------------------------------------------------------------------------------------- |
| `200`  | Event received. `handled` is `true` for `video.asset.deleted`, `false` for ignored event types. |
| `400`  | Connection has no `webhook_secret` configured, or payload is not valid JSON.                    |
| `401`  | `Mux-Signature` is missing, malformed, or the HMAC doesn't match.                               |
| `404`  | `connection_id` in the URL is not a Mux connection.                                             |

## Source path format

| Path               | Behavior                              |
| ------------------ | ------------------------------------- |
| `mux://`           | Sync all video assets in ready status |
| `mux://{asset_id}` | Sync a specific asset by ID           |

## Asset filtering

Only assets in `ready` status are synced. Assets that are `preparing` or `errored` are skipped automatically. You can also use file filters to narrow sync scope:

```python theme={null}
sync = client.buckets.syncs.create(
    namespace_id="your-namespace-id",
    bucket_id=bucket.bucket_id,
    connection_id=connection.connection_id,
    source_path="mux://",
    file_filters={
        "min_size": 1000000,  # Skip assets under ~1MB (estimated)
    }
)
```

## Metadata filtering

You can filter which Mux assets get synced based on **asset-level metadata** — `passthrough`, `meta.external_id`, or any field captured from the Mux asset. This is useful when you want a single Mux environment connected to Mixpeek but only certain assets indexed.

Metadata filters are evaluated against the asset's metadata dict (which includes `passthrough`, `duration`, `resolution_tier`, `status`, etc.). Each filter specifies a `field`, `operator`, and `value`.

### Supported operators

| Operator                 | Description                    | Example                                    |
| ------------------------ | ------------------------------ | ------------------------------------------ |
| `contains`               | Field value contains substring | `passthrough` contains `vi:1`              |
| `equals`                 | Exact match                    | `status` equals `ready`                    |
| `not_equals`             | Does not match                 | `resolution_tier` not\_equals `audio_only` |
| `not_contains`           | Does not contain substring     | `passthrough` not\_contains `skip`         |
| `gt`, `lt`, `gte`, `lte` | Numeric comparison             | `duration` gt `10`                         |
| `exists`                 | Field is present and non-empty | `passthrough` exists `true`                |

### Example: sync only flagged assets

A common pattern is to use the Mux `passthrough` field as a sync selector. Your application sets a flag on assets that should be indexed, and Mixpeek only syncs matching assets.

<CodeGroup>
  ```python Python theme={null}
  sync = client.buckets.syncs.create(
      namespace_id="your-namespace-id",
      bucket_id=bucket.bucket_id,
      connection_id=connection.connection_id,
      source_path="mux://",
      file_filters={
          "metadata_filters": [
              {
                  "field": "passthrough",
                  "operator": "contains",
                  "value": "vi:1"
              }
          ]
      }
  )
  ```

  ```bash cURL theme={null}
  curl -X POST "https://api.mixpeek.com/v1/buckets/$BUCKET_ID/syncs" \
    -H "Authorization: Bearer $MIXPEEK_API_KEY" \
    -H "X-Namespace: $NAMESPACE_ID" \
    -H "Content-Type: application/json" \
    -d '{
      "connection_id": "conn_abc123",
      "source_path": "mux://",
      "file_filters": {
        "metadata_filters": [
          {
            "field": "passthrough",
            "operator": "contains",
            "value": "vi:1"
          }
        ]
      }
    }'
  ```
</CodeGroup>

With this configuration, an asset with `passthrough: "myapp|vi:1|v:abc"` would be synced, while `passthrough: "myapp|vi:0|v:abc"` would be skipped.

<Tip>
  **Metadata filters work with any sync provider**, not just Mux. The same `metadata_filters` syntax applies to S3, GCS, and all other storage connections — the filters are evaluated against whatever metadata the provider exposes for each file.
</Tip>

## Reconciliation

When `reconcile_on_sync` is enabled, each sync cycle re-checks all previously indexed assets against the current metadata filters. Assets that no longer match are automatically unindexed.

This is useful when your application changes asset metadata after initial sync — for example, removing the visual-index flag from a Mux asset's `passthrough`. Without reconciliation, the already-indexed object would remain in the bucket. With reconciliation, it gets cleaned up on the next sync.

```bash theme={null}
curl -X PATCH "https://api.mixpeek.com/v1/buckets/$BUCKET_ID/syncs/$SYNC_ID" \
  -H "Authorization: Bearer $MIXPEEK_API_KEY" \
  -H "X-Namespace: $NAMESPACE_ID" \
  -H "Content-Type: application/json" \
  -d '{"reconcile_on_sync": true}'
```

<Warning>
  Reconciliation queries the source provider for each indexed object on every sync cycle. For large libraries (10k+ assets), this adds API calls proportional to the number of indexed objects. Use it when metadata changes are common and stale objects are unacceptable.
</Warning>

## Sync modes

| Mode           | Description                                    |
| -------------- | ---------------------------------------------- |
| `initial_only` | Sync all current assets once                   |
| `continuous`   | Poll for new assets at the configured interval |

## Troubleshooting

<AccordionGroup>
  <Accordion title="401 Unauthorized on connection test">
    Verify your access token ID and secret are correct. The token ID is a UUID (e.g., `a3b02074-dbca-47b6-...`), not the environment ID. Tokens can be regenerated in the [Mux Dashboard](https://dashboard.mux.com/settings/access-tokens).
  </Accordion>

  <Accordion title="Assets not appearing in sync">
    Only assets with `ready` status and at least one playback ID are synced. Check your asset status in the Mux Dashboard. Assets that are still encoding (`preparing`) will be picked up on the next sync cycle.
  </Accordion>

  <Accordion title="Download fails for specific assets">
    Assets need a public or signed playback ID **and** either static renditions or MP4 support enabled. By default, Mux assets only have HLS streaming — MP4 downloads require explicit configuration.

    To enable static renditions when creating an asset via the Mux API:

    ```json theme={null}
    {
      "input": [{"url": "https://example.com/video.mp4"}],
      "playback_policy": ["public"],
      "static_renditions": [{"resolution": "720p"}]
    }
    ```

    You can also enable static renditions on existing assets in the Mux Dashboard under the asset's settings. Mixpeek will try multiple rendition qualities (low, medium, high, highest) and use the first available one.
  </Accordion>
</AccordionGroup>

## Related

* [Buckets](/ingestion/buckets) — How bucket sync works
* [Webhooks](/operations/webhooks) — How outbound Mixpeek webhooks work
* [Storage Connections API](/api-reference/organization-connections/create-storage-connection) — Full API reference
