> ## 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.

# Iconik

> Connect Iconik DAM to Mixpeek for automated media asset processing and search

## Overview

[Iconik](https://iconik.io) is a cloud-native media asset management platform. By connecting Iconik to Mixpeek, you can automatically sync your media library — enabling search, classification, and analysis across video, image, and audio assets.

Iconik uses the same **connection sync** pattern as all other Mixpeek storage integrations. Mixpeek polls Iconik for assets, downloads proxy files, and creates bucket objects with full metadata. It can also parse editorial project files into **footage ↔ ad relationships** (see [Project-file linkage](#project-file-linkage)). Optionally, you can configure webhooks for real-time delete and update events.

## Prerequisites

* An Iconik account with assets
* An Iconik **App ID** and **Auth Token** with read access to assets, proxies, and files
* A Mixpeek account with an active namespace

## Configuration

### Connection-level fields

| Field            | Required | Description                                                                                                                                                                                                        |
| ---------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `auth_token`     | Yes      | Iconik authentication token (JWT or API token)                                                                                                                                                                     |
| `app_id`         | Yes      | Iconik application ID (UUID format)                                                                                                                                                                                |
| `webhook_secret` | No       | Shared signing secret for inbound Iconik webhooks. Required only if you want Mixpeek to cascade-delete objects when assets are deleted in Iconik (see [Webhooks: delete and update](#webhooks-delete-and-update)). |

### Sync-level fields

| Field                      | Required | Default      | Description                                                  |
| -------------------------- | -------- | ------------ | ------------------------------------------------------------ |
| `source_path`              | No       | `iconik://`  | Sync all assets, or filter by collection                     |
| `sync_mode`                | No       | `continuous` | `initial_only` or `continuous`                               |
| `polling_interval_seconds` | No       | 300          | How often to check for new/modified assets (continuous mode) |
| `skip_duplicates`          | No       | `true`       | Skip assets already synced with the same modification time   |
| `reconcile_on_sync`        | No       | `false`      | Remove objects whose source assets no longer exist in Iconik |
| `provider_filters`         | No       | —            | Filter by collection IDs, asset status, or media type        |

## Setup

<Steps>
  <Step title="Create Iconik API credentials">
    1. In the Iconik admin panel, go to **Admin > Integrations > Applications**
    2. Click **Create Application**
    3. Copy the **App ID** and **Auth Token** — you'll need both for the Mixpeek connection

    <Tip>
      Use a dedicated application for the Mixpeek integration rather than a personal token. Application tokens don't expire when a user leaves the organization.
    </Tip>
  </Step>

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

    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="Iconik Production",
          provider_type="iconik",
          provider_config={
              "credentials": {
                  "auth_token": "YOUR_ICONIK_AUTH_TOKEN",
                  "app_id": "YOUR_ICONIK_APP_ID"
              }
          },
          test_before_save=True
      )

      print(connection.connection_id)  # e.g. conn_3010b0af974c8d83
      ```

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

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

      const connection = await client.organizations.connections.create({
        name: "Iconik Production",
        provider_type: "iconik",
        provider_config: {
          credentials: {
            auth_token: "YOUR_ICONIK_AUTH_TOKEN",
            app_id: "YOUR_ICONIK_APP_ID",
          },
        },
        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": "Iconik Production",
          "provider_type": "iconik",
          "provider_config": {
            "credentials": {
              "auth_token": "YOUR_ICONIK_AUTH_TOKEN",
              "app_id": "YOUR_ICONIK_APP_ID"
            }
          },
          "test_before_save": true
        }'
      ```
    </CodeGroup>

    Save the returned `connection_id`.
  </Step>

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

    <CodeGroup>
      ```python Python theme={null}
      bucket = client.buckets.create(
          namespace_id="your-namespace-id",
          name="iconik-assets",
          description="Media assets from Iconik",
          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="iconik://",
          sync_mode="continuous",
          polling_interval_seconds=300,
          skip_duplicates=True
      )
      ```

      ```bash cURL theme={null}
      # Create bucket
      curl -X POST https://api.mixpeek.com/v1/buckets \
        -H "Authorization: Bearer YOUR_API_KEY" \
        -H "X-Namespace: YOUR_NAMESPACE" \
        -H "Content-Type: application/json" \
        -d '{
          "bucket_name": "iconik-assets",
          "description": "Media assets from Iconik"
        }'

      # Create sync config
      curl -X POST "https://api.mixpeek.com/v1/buckets/$BUCKET_ID/syncs" \
        -H "Authorization: Bearer YOUR_API_KEY" \
        -H "X-Namespace: YOUR_NAMESPACE" \
        -H "Content-Type: application/json" \
        -d '{
          "connection_id": "conn_YOUR_CONNECTION_ID",
          "source_path": "iconik://",
          "sync_mode": "continuous",
          "polling_interval_seconds": 300,
          "skip_duplicates": true
        }'
      ```
    </CodeGroup>
  </Step>

  <Step title="Verify ingestion">
    Monitor the sync status in Studio or via the API. Assets will be automatically downloaded (proxy files) and processed through your collection's feature extractors.

    ```bash theme={null}
    curl "https://api.mixpeek.com/v1/buckets/$BUCKET_ID/syncs" \
      -H "Authorization: Bearer YOUR_API_KEY" \
      -H "X-Namespace: YOUR_NAMESPACE"
    ```
  </Step>
</Steps>

## Collection traversal and directory mapping

When you specify `collection_ids` in `provider_filters`, the connector recursively traverses the Iconik collection hierarchy (up to 10 levels deep) and maps the collection tree to a `directory_path` on each synced object.

For example, an Iconik collection structure like:

```
Brand Campaign (root collection)
├── 01 Product Shots
│   ├── 01 Ingredients
│   └── 08 Outros
├── 02 UGC Footage
│   ├── 01 Talent (Before)
│   │   ├── 00 Young
│   │   └── 01 Mature
│   └── 02 Talent (After)
└── 03 High-End Footage
```

produces objects with `directory_path` values like:

* `Brand Campaign/01 Product Shots/08 Outros`
* `Brand Campaign/02 UGC Footage/01 Talent (Before)/01 Mature`
* `Brand Campaign/03 High-End Footage`

This path is available in `source_metadata.directory_path` and can be used for filtering in retrievers.

### Glob filtering with `path_patterns`

Use `path_patterns` in `provider_filters` to include only assets whose `directory_path` matches one or more glob patterns. Patterns use standard `fnmatch` syntax and are case-insensitive.

```json theme={null}
{
  "provider_filters": {
    "collection_ids": ["15202dd4-9b00-11ef-8481-fedcde789d87"],
    "media_type": "video",
    "path_patterns": ["*UGC*", "*High-End*"]
  }
}
```

| Pattern                | Matches                                    |
| ---------------------- | ------------------------------------------ |
| `*UGC*`                | Any path containing "UGC"                  |
| `Brand Campaign/01*`   | All paths under "01 Product Shots"         |
| `*Talent*`             | Before and After talent folders            |
| `Brand Campaign/*/01*` | First subfolder in each top-level category |
| `*Outros*`             | Only the Outros folder                     |

## Iconik metadata on objects and retriever results

When the connector syncs an Iconik asset into a bucket, it captures metadata from two sources and exposes them as **`source_metadata`** on the resulting bucket object.

### Asset-level fields

These come from the Iconik asset record directly:

| Field             | Description                                |
| ----------------- | ------------------------------------------ |
| `iconik_asset_id` | Iconik asset UUID                          |
| `title`           | Asset title                                |
| `status`          | Asset status (e.g., `ACTIVE`)              |
| `media_type`      | Media type (`video`, `image`, `audio`)     |
| `date_created`    | Asset creation timestamp                   |
| `date_modified`   | Last modification timestamp                |
| `date_imported`   | When the asset was imported into Iconik    |
| `is_online`       | Whether the asset is currently online      |
| `archive_status`  | Archive state of the asset                 |
| `analyze_status`  | Iconik analysis status                     |
| `category`        | Asset category                             |
| `type`            | Iconik object type (e.g., `ASSET`)         |
| `external_id`     | External reference ID                      |
| `created_by_user` | Iconik user ID who created the asset       |
| `updated_by_user` | Iconik user ID who last modified the asset |
| `directory_path`  | Collection hierarchy path (see above)      |
| `thumbnail_url`   | Keyframe/thumbnail URL (if available)      |
| `proxy_url`       | Pre-signed proxy download URL              |

### Custom metadata from views

The connector automatically discovers all metadata views configured in your Iconik workspace and fetches custom metadata for each asset across all views. Fields are flattened from Iconik's nested `field_values` format into simple key-value pairs.

Example fields (depending on your Iconik configuration):

| Field             | Description                 |
| ----------------- | --------------------------- |
| `Keywords`        | Tag cloud / keywords        |
| `ProjectName`     | Project or campaign name    |
| `Category`        | Asset category              |
| `Description`     | Asset description           |
| `FolderNamePaths` | Iconik folder path metadata |
| `CreatorName`     | Creator / uploader name     |

All populated custom metadata fields are included automatically — no configuration needed. If you want to limit metadata to a specific view, set `metadata_view_id` in the connection's `provider_config`:

```json theme={null}
{
  "provider_config": {
    "credentials": { "auth_token": "...", "app_id": "..." },
    "metadata_view_id": "97324f86-55ba-11ef-877b-c2a940a89d9c"
  }
}
```

## Project-file linkage

Beyond per-asset metadata, the Iconik connector captures the **relationships between assets** that come from editorial (NLE) projects. For Iconik **`NLE_PROJECT` assets** (e.g. an Adobe Premiere project — one per produced ad), the connector reads Iconik's **relations** — the media assets the project uses, already parsed by Iconik — and attaches typed, directed **[edges](/retrieval/stages/traverse-edge)** to the object — Mixpeek's first-class model for customer-owned relationships between objects.

When the project file itself is downloadable (native `.prproj`, `.fcpxml`, or an `xmeml` `.xml` export), the connector additionally parses it to enrich each edge with **clip order and timeline ticks** — matched to the relations by footage file name. This is how an assembled ad is linked to every piece of footage it uses, with its position in the cut — captured as a **saved value** on the object at ingestion, not recomputed at query time.

### What gets captured

For an NLE project asset, the connector emits one edge per related media asset, stored at the **root** of the object under `edges`:

| Edge field                                      | Description                                                                                                                                                                                                                                                   |
| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `type`                                          | `uses_footage` for related video assets; `uses_media` for audio/image/other (with `attributes.media_type`)                                                                                                                                                    |
| `target_object_id`                              | The footage object this relation references, resolved from the source asset id. Until that footage object exists in Mixpeek, the edge preserves the source asset reference and is flagged `attributes.target_unresolved` so a later reconcile can rewrite it. |
| `direction`                                     | `out` (ad → footage)                                                                                                                                                                                                                                          |
| `attributes.iconik_asset_id`                    | The related Iconik asset's id (the durable foreign key)                                                                                                                                                                                                       |
| `attributes.clip_order`                         | The clip's order within the ad sequence (1-based; from the project-file parse)                                                                                                                                                                                |
| `attributes.start_ticks_in` / `start_ticks_out` | Clip position in Adobe ticks (`254,016,000,000` per second). `attributes.tick_semantics` says what they measure: `"timeline"` (position in the ad — native `.prproj`) or `"source"` (in/out within the source footage — `xmeml` exports)                      |

The connector also sets two root-level signals on the ad object:

| Field           | Description                                                                                                                       |
| --------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `is_final_ad`   | `true` when the asset is an assembled/produced ad (a project file with clips) — distinguishing it from raw pre-production footage |
| `ad_clip_count` | Number of footage clips composited into the ad                                                                                    |

Plain media assets (raw footage) get no edges and pay no extra API calls — linkage capture is gated to NLE project assets. Everything is fully **fail-open**: a relations error or a missing/malformed project file never blocks asset ingestion (edges without a parseable project file simply carry no tick attributes).

<Note>
  Edges and these signals are **customer-owned data** and live at the object **root**, never under `_internal`. They flow automatically from the object through your collections into the document's search payload, so they are available to retrievers.
</Note>

### Traversing the relationships

Once footage↔ad edges are on your documents, the [`traverse_edge`](/retrieval/stages/traverse-edge) retriever stage follows them at query time — e.g. starting from an ad, fetch every piece of footage it uses, carrying the clip order and start-ticks of each:

```json theme={null}
{
  "stage_id": "traverse_edge",
  "parameters": { "edge_type": "uses_footage", "direction": "out" }
}
```

<Note>
  This linkage is a **generalizable** capability of Mixpeek's source-adapter framework — any connector whose source carries a companion/sidecar file (an NLE project, an XMP sidecar, a per-object `.json`) can populate edges the same way. The Adobe Premiere `xmeml` parser is the Iconik-specific piece.
</Note>

## File resolution

The Iconik connector resolves downloadable files in priority order:

1. **Proxy URL** — pre-signed download URL from `GET /files/v1/assets/{id}/proxies/`
2. **Original file URL** — download URL from `GET /files/v1/assets/{id}/formats/`

Per asset, the connector makes: one asset metadata call, one proxy URL resolution call, and one metadata view call per discovered view (views are cached after the first asset).

## Webhooks: delete and update

Mixpeek handles Iconik webhook events to keep your index in sync in real time, without waiting for the next poll cycle.

### How it works

1. Iconik POSTs events to a Mixpeek endpoint that includes your `connection_id`.
2. Mixpeek verifies the `X-Iconik-Signature` header against the `webhook_secret` stored on that connection.
3. **`assets.asset_deleted`** — Mixpeek finds every object synced from that Iconik asset and deletes them, cascading through `OBJECT_DELETED` to remove derived documents from your collections.
4. **`assets.asset_updated`** — Mixpeek re-evaluates the asset against each sync config's `metadata_filters`. If the asset no longer matches **and `reconcile_on_sync` is enabled**, the corresponding objects are unindexed.
5. **`assets.asset_created`** — Acknowledged; the asset will be picked up on the next sync poll.

### Setup

<Steps>
  <Step title="Add a webhook secret to the connection">
    Pick any high-entropy string (32+ chars) and store it as `webhook_secret` in the Iconik 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": {
            "auth_token": "...",
            "app_id": "...",
            "webhook_secret": "your-32-char-random-string"
          }
        }
      }'
    ```
  </Step>

  <Step title="Register the webhook in Iconik">
    In the Iconik admin panel:

    1. Go to **Admin > Integrations > Webhooks**
    2. Click **Create Webhook**
    3. Set the **URL** to `https://api.mixpeek.com/v1/webhooks/iconik/{connection_id}` — replace `{connection_id}` with the Mixpeek connection ID
    4. Subscribe to events: **Asset Created**, **Asset Updated**, **Asset Deleted**
    5. Save the webhook
  </Step>

  <Step title="Verify with a test delete">
    Delete a synced asset in Iconik 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": "assets.asset_deleted",
      "handled": true,
      "asset_id": "e0f0ec84-4d63-11f1-99fa-b221c0ff30c8",
      "deleted_objects": 1
    }
    ```
  </Step>
</Steps>

### Signature format

Mixpeek verifies inbound Iconik webhooks using HMAC-SHA256:

* Header: `X-Iconik-Signature: <hex_hmac_sha256>`
* HMAC computed as `HMAC_SHA256(webhook_secret, 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 delete/update/create, `false` for unrecognized event types. |
| `400`  | Connection has no `webhook_secret` configured, or payload is not valid JSON.                        |
| `401`  | `X-Iconik-Signature` is missing, malformed, or the HMAC doesn't match.                              |
| `404`  | `connection_id` in the URL is not an Iconik connection.                                             |

## Modification detection

When `skip_duplicates` is `true` (default), re-syncing the same Iconik account skips assets whose `date_modified` hasn't changed since the last sync. This makes continuous syncing efficient — only new or modified assets are re-processed.

When `skip_duplicates` is `false`, every asset is re-downloaded and re-processed on each sync cycle, replacing existing objects with fresh ones.

## Reconciliation

When `reconcile_on_sync` is enabled, each sync cycle checks whether previously synced assets still exist in Iconik. Assets that have been deleted from Iconik are automatically removed from your bucket.

```bash theme={null}
curl -X POST "https://api.mixpeek.com/v1/buckets/$BUCKET_ID/syncs" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "X-Namespace: YOUR_NAMESPACE" \
  -H "Content-Type: application/json" \
  -d '{
    "connection_id": "conn_YOUR_CONNECTION_ID",
    "source_path": "iconik://",
    "reconcile_on_sync": true
  }'
```

<Warning>
  Reconciliation checks each indexed object against the Iconik API on every sync cycle. For large libraries (10k+ assets), this adds API calls proportional to the number of indexed objects. Use it when stale objects are unacceptable.
</Warning>

## Provider filters

Filter which Iconik assets get synced using `provider_filters`:

```json theme={null}
{
  "provider_filters": {
    "collection_ids": ["col_abc", "col_def"],
    "status": "ACTIVE",
    "media_type": "video"
  }
}
```

| Filter           | Description                                       |
| ---------------- | ------------------------------------------------- |
| `collection_ids` | Only sync assets from specific Iconik collections |
| `status`         | Filter by asset status (e.g., `ACTIVE`)           |
| `media_type`     | Filter by media type (`video`, `image`, `audio`)  |

## Sync modes

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

## Troubleshooting

<AccordionGroup>
  <Accordion title="401 Unauthorized on connection test">
    Verify your App ID and Auth Token are correct. The App ID is a UUID (e.g., `e0f0ec84-4d63-...`). Tokens can be regenerated in the Iconik admin panel under **Admin > Integrations > Applications**.
  </Accordion>

  <Accordion title="Assets not appearing in sync">
    Only assets with proxy files or original files available are synced. Check that your Iconik credentials have read access to the files API (`GET /files/v1/assets/{id}/proxies/`).
  </Accordion>

  <Accordion title="Duplicate objects appearing">
    Ensure `skip_duplicates` is set to `true` on your sync config. This deduplicates assets by their Iconik asset ID and modification timestamp.
  </Accordion>

  <Accordion title="Deleted assets still in bucket">
    Enable `reconcile_on_sync` on your sync config, or configure webhooks to handle `assets.asset_deleted` events for real-time cleanup.
  </Accordion>

  <Accordion title="Webhook 401 errors">
    The `X-Iconik-Signature` header doesn't match. Verify the `webhook_secret` on your Mixpeek connection matches what Iconik is using to sign payloads.
  </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
