

Clipping in BlitzReels is a managed workflow. Use `/clips` first when you want a finished short from a YouTube URL or workspace media asset:

1. create a clip run
2. poll `next_action`
3. reselect or repair if requested
4. export when the clip is ready

## Recommended Path [#recommended-path]

Create a managed clip from YouTube:

```bash title="Terminal"
CLIP=$(curl -s -X POST https://blitzreels.com/api/v1/clips \
  -H "Authorization: Bearer $BLITZREELS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "project_name": "Backend clip",
    "source": {
      "source_type": "youtube",
      "youtube_url": "https://www.youtube.com/watch?v=VIDEO_ID"
    },
    "selection": {
      "selection_mode": "auto_best"
    },
    "target": {
      "aspect_ratio": "9:16",
      "min_duration_seconds": 8,
      "max_duration_seconds": 45
    },
    "layout": {
      "layout_mode": "auto",
      "content_type_hint": "auto"
    },
    "captions": {
      "enabled": true
    },
    "qa": {
      "qa_mode": "permissive"
    },
    "export": {
      "auto_export": false
    }
  }')

CLIP_ID=$(echo "$CLIP" | jq -r '.clip.clip_id')
```

For an existing workspace media asset, send `"source_type": "asset"` with `"asset_id": "MEDIA_ASSET_ID"` instead of `youtube_url`.

Poll the clip:

```bash title="Terminal"
curl https://blitzreels.com/api/v1/clips/$CLIP_ID \
  -H "Authorization: Bearer $BLITZREELS_API_KEY"
```

Follow `clip.next_action`:

* `poll` means keep polling.
* `reselect` means choose another suggestion or provide a time range.
* `repair` means run one repair pass.
* `export` means render the clip.
* `stop` means the workflow is complete or failed.

Export when ready:

```bash title="Terminal"
curl -X POST https://blitzreels.com/api/v1/clips/$CLIP_ID/export \
  -H "Authorization: Bearer $BLITZREELS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "resolution": "1080p",
    "format": "mp4"
  }'
```

## Low-Level Project-Bound Fallback [#low-level-project-bound-fallback]

Use this path when you need manual control over ingest, transcript recovery, suggestion apply, or timeline edits.

### 1. Create a project [#1-create-a-project]

```bash title="Terminal"
PROJECT=$(curl -s -X POST https://blitzreels.com/api/v1/projects \
  -H "Authorization: Bearer $BLITZREELS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Backend clip","aspect_ratio":"9:16"}')

PROJECT_ID=$(echo "$PROJECT" | jq -r .id)
```

### 2. Upload local media to the project [#2-upload-local-media-to-the-project]

Request upload info:

```bash title="Terminal"
INIT=$(curl -s -X POST https://blitzreels.com/api/v1/projects/$PROJECT_ID/media \
  -H "Authorization: Bearer $BLITZREELS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"file_name":"long-form.mov","content_type":"video/quicktime"}')

UPLOAD_URL=$(echo "$INIT" | jq -r .upload.uploadUrl)
STORAGE_KEY=$(echo "$INIT" | jq -r .upload.storageKey)
```

Upload the file:

```bash title="Terminal"
curl -X PUT "$UPLOAD_URL" \
  -H "Content-Type: video/quicktime" \
  --upload-file ./long-form.mov
```

Finalize and request transcript plus short suggestions:

```bash title="Terminal"
curl -X POST https://blitzreels.com/api/v1/projects/$PROJECT_ID/media \
  -H "Authorization: Bearer $BLITZREELS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "storage_key":"'"$STORAGE_KEY"'",
    "file_name":"long-form.mov",
    "content_type":"video/quicktime",
    "file_size_bytes": 123456789,
    "auto_transcribe": true,
    "auto_suggest_shorts": true
  }'
```

## Clipping Readiness [#clipping-readiness]

Recover a batch from its source video with
`GET /workspace/media/assets/{asset_id}/clip-batch` or
`client.clipBatches.getForAsset({ assetId })` in the SDK.
This returns the latest persisted batch, including its progress, accepted clips,
and archive URL; `{ "batch": null }` means no batch exists for that workspace asset.
Keep polling while processing continues or the archive is still being prepared.
Retain the batch ID after transient network failures so the same run can resume.

Do not assume ingest completion means clipping is ready. Use the clipping status endpoint as the source of truth for:

* transcript readiness
* short suggestion readiness
* caption readiness for a target project
* canonical duration when asset, transcript, and suggestion durations disagree

```bash title="Terminal"
curl "https://blitzreels.com/api/v1/workspace/media/assets/$MEDIA_ID/clipping-status?project_id=$PROJECT_ID" \
  -H "Authorization: Bearer $BLITZREELS_API_KEY"
```

Important fields:

* `readiness.transcript_ready`
* `readiness.suggestions_ready`
* `readiness.ready_to_apply`
* `readiness.ready_to_export`
* `durations.canonical_duration_seconds`
* `durations.consistency`

## Transcript Recovery [#transcript-recovery]

If transcript is still missing after media processing is complete, use the recovery path:

```bash title="Terminal"
JOB=$(curl -s -X POST https://blitzreels.com/api/v1/projects/$PROJECT_ID/transcribe \
  -H "Authorization: Bearer $BLITZREELS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"media_id":"'"$MEDIA_ID"'","force":true,"auto_suggest_shorts":true}')

JOB_ID=$(echo "$JOB" | jq -r .job_id)

curl https://blitzreels.com/api/v1/jobs/$JOB_ID \
  -H "Authorization: Bearer $BLITZREELS_API_KEY"
```

Clipping is ready when transcript has non-zero words and segments.

You can still inspect the raw transcript directly:

```bash title="Terminal"
curl "https://blitzreels.com/api/v1/projects/$PROJECT_ID/transcript?media_id=$MEDIA_ID" \
  -H "Authorization: Bearer $BLITZREELS_API_KEY"
```

## Short Suggestions [#short-suggestions]

Poll suggestions on the workspace asset:

```bash title="Terminal"
curl https://blitzreels.com/api/v1/workspace/media/assets/$MEDIA_ID/short-suggestions \
  -H "Authorization: Bearer $BLITZREELS_API_KEY"
```

Current behavior:

* suggestions are attached to the workspace asset
* draft and saved suggestions are both returned
* `clipping-status` is better than inferring readiness from raw asset processing state

## Apply A Suggestion [#apply-a-suggestion]

Use the public apply endpoint when you want the API to:

* promote the transcript into the project
* add the source clip to the timeline
* trim to the suggestion window
* add captions to the timeline
* optionally mark the suggestion as saved

```bash title="Terminal"
curl -X POST "https://blitzreels.com/api/v1/workspace/media/assets/$MEDIA_ID/short-suggestions/$SUGGESTION_ID/apply" \
  -H "Authorization: Bearer $BLITZREELS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "project_id":"'"$PROJECT_ID"'",
    "caption_style_id":"viral-center",
    "mark_saved":true
  }'
```

The response returns:

* `timeline_item_id`
* `trim_start_seconds`
* `trim_end_seconds`
* `duration_seconds`
* `source_duration_seconds`
* `captions_added`
* `warnings`

When duration values disagree across endpoints, trust `clipping-status.durations.canonical_duration_seconds` over raw asset duration.

## Low-Level Fallback [#low-level-fallback]

Use the low-level timeline endpoints only when you want a custom clip window instead of a saved suggestion.

Insert the source asset on the timeline:

```bash title="Terminal"
INSERT=$(curl -s -X POST https://blitzreels.com/api/v1/projects/$PROJECT_ID/timeline/media \
  -H "Authorization: Bearer $BLITZREELS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
      {
        "asset_id": "'"$MEDIA_ID"'",
        "start_seconds": 0,
        "position_preset": "fullscreen"
      }
    ]
  }')

ITEM_ID=$(echo "$INSERT" | jq -r '.inserted[0].timeline_item_id')
```

Trim to the suggestion window:

```bash title="Terminal"
curl -X POST https://blitzreels.com/api/v1/projects/$PROJECT_ID/timeline/trim \
  -H "Authorization: Bearer $BLITZREELS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "timeline_item_id":"'"$ITEM_ID"'",
    "trim_start_delta_seconds": 43.875,
    "trim_end_delta_seconds": 162.471667,
    "snap_to_frame": true
  }'
```

## Verify Captions And Timeline [#verify-captions-and-timeline]

The apply endpoint already inserts captions. Verify the resulting timeline:

```bash title="Terminal"
curl "https://blitzreels.com/api/v1/projects/$PROJECT_ID/context?mode=timeline" \
  -H "Authorization: Bearer $BLITZREELS_API_KEY"
```

You should see:

* one media item with the trimmed clip duration
* caption content items on the timeline before export
* a project duration consistent with the chosen clip window

## Export [#export]

```bash title="Terminal"
EXPORT=$(curl -s -X POST https://blitzreels.com/api/v1/projects/$PROJECT_ID/export \
  -H "Authorization: Bearer $BLITZREELS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"resolution":"1080p","format":"mp4"}')

EXPORT_ID=$(echo "$EXPORT" | jq -r .export_id)

curl https://blitzreels.com/api/v1/exports/$EXPORT_ID \
  -H "Authorization: Bearer $BLITZREELS_API_KEY"
```

## YouTube Import [#youtube-import]

Use YouTube import when the goal is workspace ingestion:

```bash title="Terminal"
curl -X POST https://blitzreels.com/api/v1/workspace/media/import/youtube \
  -H "Authorization: Bearer $BLITZREELS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://www.youtube.com/watch?v=VIDEO_ID","quality":"720p"}'
```

Important:

* treat this as ingest-first, not export-ready by default
* confirm transcript plus short suggestions before assuming clipping is available
* if the user needs a finished short and the YouTube path does not produce suggestions, switch to a project-bound path

## Quality Checklist [#quality-checklist]

* transcript exists and is non-empty
* at least one short suggestion exists
* chosen clip starts on a hook
* captions are present on the timeline before export
* export duration matches the chosen window
* export aspect ratio and effective resolution match the request

## Related [#related]

* [Project Media API](/docs/project-media)
* [Transcript API](/docs/transcript)
* [Timeline Editing API](/docs/timeline)
* [Jobs and Exports](/docs/jobs-exports)
