> For a complete page index of the Captain API documentation, fetch https://docs.captain.dev/llms.txt?excludeSpec=true

# Create S3 Sync

POST https://api.captain.dev/v2/collections/{collection_name}/sync/s3
Content-Type: application/json

Create a Sync for a collection and start the initial backfill. AWS S3 authenticates with cross-account assume-role (recommended) or an access key. Works across S3-compatible cloud storage: AWS S3, Google Cloud Storage, Cloudflare R2, Supabase Storage, and Backblaze B2 (each has its own create endpoint). Returns the sync; indexing runs asynchronously.

Reference: https://docs.captain.dev/reference/sync/s3/create

## Request

### Path parameters

- `collection_name` (string, required) — Destination collection.

### Headers

- `authorization` (string, optional, nullable) — Bearer \{api\_key}. Your Captain API key.

### Body (application/json)

This endpoint expects a S3SyncCreateRequestDocs.

- `bucket` (string, required) — Bucket to keep in sync with the collection.
- `auth` (S3SyncCreateRequestDocsAuth, required) — Auth for reading the bucket: assume-role (AWS S3) or access-key (S3 or S3-compatible). Non-S3 stores require access-key auth.
- `processing_type` (enum, required) — Parsing tier. 'advanced' = full document understanding; 'basic' = faster/cheaper.
  - Allowed values: `advanced`, `basic`, `auto`
- `prefix` (string, optional, default: ) — Key prefix to scope the sync (e.g. 'docs/2024/'). Empty syncs the whole bucket.
- `region` (string, optional, default: us-east-1) — Region of the bucket (AWS region for S3, or the provider's region, e.g. 'auto' for R2, 'us-west-004' for Backblaze B2).
- `storage_type` (enum, optional, default: s3) — Cloud storage type. 's3' = AWS S3 (assume-role or access-key). 'r2'/'supabase'/'backblaze' are S3-compatible and require access-key auth with an endpoint_url.
  - Allowed values: `s3`, `r2`, `supabase`, `backblaze`
- `include_patterns` (list of string, optional) — Glob patterns; only matching keys are synced. Empty includes everything under the prefix.
- `exclude_patterns` (list of string, optional) — Glob patterns; matching keys are excluded.
- `deletion_policy` (enum, optional, default: mirror) — How to propagate objects removed from the source: `mirror` removes them from the collection so they no longer appear in search; `archive` keeps the document's content but marks it archived, excluded from search by default and surfaced with `include_archived: true`; `ignore` leaves the indexed copy in place.
  - Allowed values: `mirror`, `archive`, `ignore`
- `metadata_mapping` (map from string to string, optional, nullable) — Maps an S3 object tag/key to a Captain metadata field name.
- `custom_metadata` (map from string to any, optional) — Static metadata applied to every synced document.
- `sync_interval_minutes` (integer, optional, nullable) — Scheduled reconcile cadence. MINIMUM 5 minutes (the scheduler ticks every 5 min); values below 5 are silently raised to 5; >=5 honored exactly. null/omitted = manual (events + on-demand only). For sub-5-min propagation use the event webhook.

## Response

### 201

Successful Response

- `sync_id` (string, optional)
- `collection_name` (string, optional)
- `bucket` (string, optional)
- `prefix` (string, optional)
- `region` (string, optional)
- `storage_type` (enum, optional) — The sync's cloud storage type. Returned by the list endpoint (GET /v2/syncs) only; other sync endpoints omit this field.
  - Allowed values: `s3`, `gcs`, `r2`, `supabase`, `backblaze`, `azure`
- `auth_method` (enum, optional) — How the sync authenticates to the bucket: 'iam_role' (AWS cross-account assume-role), 'access_key' (S3-compatible key pair), or 'service_account' (GCS service-account JSON).
  - Allowed values: `iam_role`, `access_key`, `service_account`, `account_key`
- `account_name` (string, optional, nullable) — Azure Blob syncs only: the storage account name. Null for other providers.
- `endpoint_url` (string, optional, nullable) — S3-compatible endpoint URL (access-key syncs on non-AWS providers); null for AWS S3. Returned by the list endpoint (GET /v2/syncs) only; other sync endpoints omit this field.
- `processing_type` (enum, optional)
  - Allowed values: `advanced`, `basic`, `auto`
- `include_patterns` (list of string, optional)
- `exclude_patterns` (list of string, optional)
- `deletion_policy` (enum, optional)
  - Allowed values: `mirror`, `archive`, `ignore`
- `status` (enum, optional)
  - Allowed values: `active`, `paused`, `inactive`
- `secret_set` (boolean, optional) — True once an event-webhook secret has been minted.
- `sns_subscribe_url` (string, optional, nullable) — SNS subscribe URL; only surfaced by the subscribe-webhook endpoint.
- `last_backfill_job_id` (string, optional, nullable)
- `last_reconcile_at` (string, optional, nullable)
- `sync_interval_minutes` (integer, optional, nullable) — Effective (already-clamped) cadence; null = manual.
- `next_sync_at` (integer, optional, nullable) — Epoch ms of the next due scheduled reconcile.
- `sync_state` (enum, optional, nullable)
  - Allowed values: `idle`, `running`, `error`
- `last_sync_at` (integer, optional, nullable)
- `last_sync_error` (string, optional, nullable)
- `created_at` (string, optional)
- `updated_at` (string, optional, nullable)

## Types

### S3SyncCreateRequestDocsAuth

Auth for reading the bucket: assume-role (AWS S3) or access-key (S3 or S3-compatible). Non-S3 stores require access-key auth.

## Examples

### Assume-role auth (recommended)

**Request**

```json
{
  "bucket": "my-company-docs",
  "auth": {
    "type": "assume_role",
    "role_arn": "arn:aws:iam::123456789012:role/captain-s3-read",
    "external_id": "captain-abc123"
  },
  "processing_type": "advanced",
  "prefix": "knowledge-base/",
  "region": "us-east-1",
  "include_patterns": [
    "*.pdf",
    "*.docx"
  ],
  "exclude_patterns": [
    "drafts/*"
  ],
  "deletion_policy": "mirror",
  "custom_metadata": {
    "team": "research",
    "source": "s3"
  },
  "sync_interval_minutes": 15
}
```

**Response**

```json
{
  "sync_id": "sync_7e0abee6e110457db2c8",
  "collection_name": "company-knowledge",
  "bucket": "my-company-docs",
  "prefix": "knowledge-base/",
  "region": "us-east-1",
  "auth_method": "iam_role",
  "processing_type": "advanced",
  "include_patterns": [
    "*.pdf",
    "*.docx"
  ],
  "exclude_patterns": [
    "drafts/*"
  ],
  "deletion_policy": "mirror",
  "status": "active",
  "secret_set": false,
  "sns_subscribe_url": null,
  "last_backfill_job_id": "91f2aa031d8f4e7d8877c4564eb486bd-1786120498",
  "last_reconcile_at": null,
  "sync_interval_minutes": 15,
  "next_sync_at": 1786120589056,
  "sync_state": "idle",
  "last_sync_at": null,
  "last_sync_error": null,
  "created_at": "2026-08-07T16:34:58.188233+00:00",
  "updated_at": "2026-08-07T16:34:58.612676+00:00"
}
```

**SDK Code**

```python Python REST
import requests

BASE_URL = "https://api.captain.dev"
API_KEY = "your_api_key"

headers = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json"
}

response = requests.post(
    f"{BASE_URL}/v2/collections/company-knowledge/sync/s3",
    headers=headers,
    json={
        "bucket": "my-company-docs",
        "prefix": "knowledge-base/",
        "region": "us-east-1",
        "auth": {
            "type": "assume_role",
            "role_arn": "arn:aws:iam::123456789012:role/captain-s3-read",
            "external_id": "captain-abc123"
        },
        "processing_type": "advanced",
        "include_patterns": [
            "*.pdf",
            "*.docx"
        ],
        "exclude_patterns": [
            "drafts/*"
        ],
        "deletion_policy": "mirror",
        "custom_metadata": {
            "team": "research",
            "source": "s3"
        },
        "sync_interval_minutes": 15
    }
)

print(response.json())
```

```typescript TypeScript REST
const BASE_URL = "https://api.captain.dev";
const API_KEY = "your_api_key";

const response = await fetch(
    `${BASE_URL}/v2/collections/company-knowledge/sync/s3`,
    {
        method: "POST",
        headers: {
            "Authorization": `Bearer ${API_KEY}`,
            "Content-Type": "application/json"
        },
        body: JSON.stringify({
            bucket: "my-company-docs",
            prefix: "knowledge-base/",
            region: "us-east-1",
            auth: {
                type: "assume_role",
                role_arn: "arn:aws:iam::123456789012:role/captain-s3-read",
                external_id: "captain-abc123"
            },
            processing_type: "advanced",
            include_patterns: ["*.pdf", "*.docx"],
            exclude_patterns: ["drafts/*"],
            deletion_policy: "mirror",
            custom_metadata: {
                team: "research",
                source: "s3"
            },
            sync_interval_minutes: 15
        })
    }
);

const data = await response.json();
console.log(data);
```

### Access-key auth

**Request**

```json
{
  "bucket": "my-company-docs",
  "auth": {
    "type": "access_key",
    "access_key_id": "AKIAIOSFODNN7EXAMPLE",
    "secret_access_key": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
  },
  "processing_type": "advanced",
  "prefix": "knowledge-base/",
  "region": "us-east-1",
  "include_patterns": [
    "*.pdf",
    "*.docx"
  ],
  "exclude_patterns": [
    "drafts/*"
  ],
  "deletion_policy": "mirror",
  "custom_metadata": {
    "team": "research",
    "source": "s3"
  },
  "sync_interval_minutes": 15
}
```

**Response**

```json
{
  "sync_id": "sync_7e0abee6e110457db2c8",
  "collection_name": "company-knowledge",
  "bucket": "my-company-docs",
  "prefix": "knowledge-base/",
  "region": "us-east-1",
  "auth_method": "access_key",
  "processing_type": "advanced",
  "include_patterns": [
    "*.pdf",
    "*.docx"
  ],
  "exclude_patterns": [
    "drafts/*"
  ],
  "deletion_policy": "mirror",
  "status": "active",
  "secret_set": false,
  "sns_subscribe_url": null,
  "last_backfill_job_id": "91f2aa031d8f4e7d8877c4564eb486bd-1786120498",
  "last_reconcile_at": null,
  "sync_interval_minutes": 15,
  "next_sync_at": 1786120589056,
  "sync_state": "idle",
  "last_sync_at": null,
  "last_sync_error": null,
  "created_at": "2026-08-07T16:34:58.188233+00:00",
  "updated_at": "2026-08-07T16:34:58.612676+00:00"
}
```

**SDK Code**

```python Python REST
import requests

BASE_URL = "https://api.captain.dev"
API_KEY = "your_api_key"

headers = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json"
}

response = requests.post(
    f"{BASE_URL}/v2/collections/company-knowledge/sync/s3",
    headers=headers,
    json={
        "bucket": "my-company-docs",
        "prefix": "knowledge-base/",
        "region": "us-east-1",
        "auth": {
            "type": "access_key",
            "access_key_id": "AKIAIOSFODNN7EXAMPLE",
            "secret_access_key": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
        },
        "processing_type": "advanced",
        "include_patterns": [
            "*.pdf",
            "*.docx"
        ],
        "exclude_patterns": [
            "drafts/*"
        ],
        "deletion_policy": "mirror",
        "custom_metadata": {
            "team": "research",
            "source": "s3"
        },
        "sync_interval_minutes": 15
    }
)

print(response.json())
```

```typescript TypeScript REST
const BASE_URL = "https://api.captain.dev";
const API_KEY = "your_api_key";

const response = await fetch(
    `${BASE_URL}/v2/collections/company-knowledge/sync/s3`,
    {
        method: "POST",
        headers: {
            "Authorization": `Bearer ${API_KEY}`,
            "Content-Type": "application/json"
        },
        body: JSON.stringify({
            bucket: "my-company-docs",
            prefix: "knowledge-base/",
            region: "us-east-1",
            auth: {
                type: "access_key",
                access_key_id: "AKIAIOSFODNN7EXAMPLE",
                secret_access_key: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
            },
            processing_type: "advanced",
            include_patterns: ["*.pdf", "*.docx"],
            exclude_patterns: ["drafts/*"],
            deletion_policy: "mirror",
            custom_metadata: {
                team: "research",
                source: "s3"
            },
            sync_interval_minutes: 15
        })
    }
);

const data = await response.json();
console.log(data);
```