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

# Supabase Storage

> Sync files from Supabase Storage buckets into Mixpeek using the S3-compatible API.

> [!NOTE]
>
> Supabase Storage exposes an S3-compatible API that Mixpeek talks to directly. You can authenticate with dedicated S3 access keys (recommended) or with a project's `anon` + `service_role` JWTs in session-token mode.

## Overview

The Supabase integration lets Mixpeek pull objects from any Supabase Storage bucket into your Mixpeek buckets for processing. Each file becomes a Mixpeek bucket object, automatically batched into the collections that source the bucket.

Mixpeek derives the endpoint from your project reference — the short URL hash in your project's Dashboard URL (`https://<ref>.supabase.co`). You do not need to manage endpoints by hand.

## Prerequisites

* A Supabase project with at least one Storage bucket.
* Either:
  * **S3 access keys** (recommended): a dedicated key pair generated in **Project Settings → Storage → S3 Access Keys**, or
  * **Session-token credentials**: the project's `anon` key and `service_role` key from **Project Settings → API**.

## Configuration

### Connection-Level Fields

| Field | Required | Description |
| - | - | - |
| `project_ref` | Yes | Supabase project reference (the short hash in `https://<ref>.supabase.co`) |
| `region` | Yes | Region that hosts the project (e.g., `us-east-2`, `eu-west-1`) |
| `credentials.type` | Yes | `access_key` or `session_token` |
| `credentials.access_key_id` | for `access_key` | S3 access key ID generated in Supabase |
| `credentials.secret_access_key` | for `access_key` | S3 secret access key — encrypted at rest |
| `credentials.anon_key` | for `session_token` | Project `anon` JWT |
| `credentials.service_role_key` | for `session_token` | Project `service_role` JWT — encrypted at rest |

### Sync-Level Fields

| Field | Required | Description |
| - | - | - |
| `source_path` | Yes | `<supabase-bucket>/<optional-prefix>` — e.g. `user-uploads/photos/` |
| `sync_mode` | No | `continuous` (default) or `initial_only` |
| `polling_interval_seconds` | No | Seconds between polls in `continuous` mode |
| `include_patterns` | No | Glob patterns to include (e.g. `["*.mp4", "*.jpg"]`) |
| `exclude_patterns` | No | Glob patterns to exclude |
| `modified_since` | No | ISO 8601 timestamp; only sync files modified after this date |

## Setup

**1. Generate credentials in Supabase**

**Option A — Dedicated S3 keys (recommended):**

1. Open your project in the [Supabase Dashboard](https://supabase.com/dashboard).
2. Go to **Project Settings → Storage → S3 Access Keys**.
3. Click **New access key**, give it a name (e.g. `mixpeek-sync`) and copy the `access_key_id` + `secret_access_key` immediately — the secret is shown only once.

**Option B — Session-token credentials:**

1. Go to **Project Settings → API**.
2. Copy the `anon` key and the `service_role` key. Treat `service_role` like a password — it has full access to Storage.

> [!WARNING]
>
> Session-token mode is convenient when you don't have permission to mint S3 keys, but the `service_role` JWT is a superuser credential. Prefer dedicated S3 keys scoped to the buckets you actually need.

**2. Create the storage connection in Mixpeek**

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

client = Mixpeek(api_key="your-mixpeek-api-key")

connection = client.organizations.connections.create(
    name="Supabase Uploads",
    provider_type="supabase",
    provider_config={
        "project_ref": "abcdefghijklmnopqrst",
        "region": "us-east-2",
        "credentials": {
            "type": "access_key",
            "access_key_id": "supabase_ak_...",
            "secret_access_key": "supabase_sk_...",
        },
    },
)
print(f"Connection: {connection['connection_id']}")
```

```javascript JavaScript theme={null}
import { Mixpeek } from 'mixpeek-sdk'

const client = new Mixpeek({ apiKey: 'your-mixpeek-api-key' })

const connection = await client.organizations.connections.create({
  name: 'Supabase Uploads',
  provider_type: 'supabase',
  provider_config: {
    project_ref: 'abcdefghijklmnopqrst',
    region: 'us-east-2',
    credentials: {
      type: 'access_key',
      access_key_id: 'supabase_ak_...',
      secret_access_key: 'supabase_sk_...',
    },
  },
})
console.log('Connection:', connection.connection_id)
```

```bash cURL theme={null}
curl -X POST https://api.mixpeek.com/v1/organizations/connections \
  -H "Authorization: Bearer YOUR_MIXPEEK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Supabase Uploads",
    "provider_type": "supabase",
    "provider_config": {
      "project_ref": "abcdefghijklmnopqrst",
      "region": "us-east-2",
      "credentials": {
        "type": "access_key",
        "access_key_id": "supabase_ak_...",
        "secret_access_key": "supabase_sk_..."
      }
    }
  }'
```

To use session-token mode instead, swap the `credentials` block:

```json theme={null}
{
  "type": "session_token",
  "anon_key": "eyJ...anon",
  "service_role_key": "eyJ...service_role"
}
```

**3. Create a sync configuration on your bucket**

```python Python theme={null}
sync = client.buckets.syncs.create(
    bucket_id="bkt_your_bucket_id",
    connection_id=connection["connection_id"],
    source_path="user-uploads/photos/",
    sync_mode="continuous",
    polling_interval_seconds=3600,
)
print(f"Sync: {sync['sync_config_id']}")
```

```bash cURL theme={null}
curl -X POST https://api.mixpeek.com/v1/buckets/bkt_your_bucket_id/syncs \
  -H "Authorization: Bearer YOUR_MIXPEEK_API_KEY" \
  -H "X-Namespace: ns_your_namespace_id" \
  -H "Content-Type: application/json" \
  -d '{
    "connection_id": "conn_your_connection_id",
    "source_path": "user-uploads/photos/",
    "sync_mode": "continuous",
    "polling_interval_seconds": 3600
  }'
```

**4. Trigger your first sync**

```bash theme={null}
curl -X POST https://api.mixpeek.com/v1/buckets/bkt_your_bucket_id/syncs/SYNC_CONFIG_ID/trigger \
  -H "Authorization: Bearer YOUR_MIXPEEK_API_KEY" \
  -H "X-Namespace: ns_your_namespace_id"
```

Mixpeek lists objects under your Supabase prefix, downloads each one, stores it in the Mixpeek-side S3 bucket, and creates a bucket object. Any collection that sources this bucket picks the new objects up on the next batch.

## Advanced Configuration

### File Filtering

```python theme={null}
sync = client.buckets.syncs.create(
    bucket_id="bkt_your_bucket_id",
    connection_id=connection["connection_id"],
    source_path="user-uploads/",
    sync_mode="continuous",
    polling_interval_seconds=3600,
    include_patterns=["*.mp4", "*.mov", "*.jpg"],
    exclude_patterns=["*_thumbnail.*", "*.tmp"],
)
```

### Incremental Sync

Only sync files added or modified after a specific date:

```python theme={null}
sync = client.buckets.syncs.create(
    bucket_id="bkt_your_bucket_id",
    connection_id=connection["connection_id"],
    source_path="user-uploads/",
    sync_mode="continuous",
    polling_interval_seconds=300,
    modified_since="2024-06-01T00:00:00Z",
)
```

## Source Path Format

| Format | Example | Description |
| - | - | - |
| `bucket/prefix` | `user-uploads/photos/` | Preferred — Supabase bucket + prefix |
| `s3://bucket/prefix` | `s3://user-uploads/photos/` | S3-style URI also accepted |
| `bucket` | `user-uploads` | Entire Supabase bucket |

## Sync Modes

| Mode | Description | When to Use |
| - | - | - |
| `continuous` | Polls every `polling_interval_seconds` | Active uploads, near-real-time ingestion. Set a longer interval for a predictable batch cadence |
| `initial_only` | Single import, then completes | Historical backfills, migrations |

## Troubleshooting

> [accordion] Connection test returns 403 / SignatureDoesNotMatch
>
> * With **access\_key** mode: the keys must come from **Project Settings → Storage → S3 Access Keys**, not the general Supabase API keys.
> * With **session\_token** mode: verify `anon_key` and `service_role_key` are both JWTs from the same project and that `project_ref` matches the project they belong to.
> * Confirm `region` matches the region shown in the Supabase Dashboard.

> [accordion] NoSuchBucket when triggering sync
>
> The Supabase bucket in `source_path` does not exist or your credentials cannot see it:
>
> * Double-check the bucket name (case-sensitive).
> * For access keys with bucket scope, confirm the key grants access to the bucket you're syncing.

> [accordion] No files synced from a populated bucket
>
> * The `source_path` prefix is too narrow — widen it, or drop the trailing prefix.
> * `include_patterns` may exclude everything — remove them temporarily to see all files.
> * Check the sync run's `matched` counter in the job log to confirm discovery.

> [accordion] Session-token auth works locally but fails in Mixpeek
>
> Some Supabase projects rotate `anon`/`service_role` keys during upgrades. Refresh both JWTs from **Project Settings → API** and update the connection.

## Related

* [Bucket Syncs](https://docs.mixpeek.com/docs/api-reference/bucket-syncs/create-sync-configuration.md)
* [Storage Connections](https://docs.mixpeek.com/docs/api-reference/organization-connections/create-storage-connection.md)
* [Backblaze B2 Integration](https://docs.mixpeek.com/docs/integrations/object-storage/backblaze.md)
* [Tigris Integration](https://docs.mixpeek.com/docs/integrations/object-storage/tigris.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.