# Find Moments API

> Identify and extract key moments from videos using natural-language queries.

## Find Moments API

The Find Moments API lets you describe the moments you want using natural language — such as `"funny reactions"` or `"product demos"` — and the API finds and extracts matching clips with timestamps, titles, descriptions, and hashtags from videos of all lengths, including hours-long content. If export is enabled, the response also includes rendered video download links for each clip, with optional auto-reframe that keeps the main subject centered and Animated Caption overlays for more engaging outputs.

You can publish clips generated by Find Moments directly to connected social media accounts. See the [Social Media Publishing API](https://wayin.ai/api-docs/social-media-publishing/) to connect accounts and create publishing tasks.

## Supported Video Sources

The API accepts URLs from the following platforms: YouTube, Vimeo, Dailymotion, Kick, Twitch, TikTok, Facebook, Zoom, Rumble and more.

You can also search [local video files you upload](https://wayin.ai/api-docs/upload/) — local upload requires a **Starter** plan or above.

---

## Submit Find Moments Task

```
POST https://wayinvideo-api.wayin.ai/api/v2/clips/find-moments
```

### Request Body

When rendering clips, you can enable features such as **Animated Caption**, **AI Reframe**, and optional **AI Hook** text overlays. With AI Reframe, the system detects the main subject in the frame, keeps that subject centered, optimizes the crop for the chosen aspect ratio, and selects the most suitable layout based on the structure of the scene. These features are controlled by parameters whose names start with `enable_` (see the table below).

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `video_url` | string | Yes | — | The URL of the source video. For locally uploaded files, use the file identifier returned by the [Upload API](https://wayin.ai/api-docs/upload/). |
| `query` | string | Yes | `""` | Natural-language query describing the moments you want (e.g. `"funny reactions"`, `"product demos"`) |
| `project_name` | string | No | `""` | Custom task name |
| `source_lang` | string | No | `null` | Source language of the video (see [Supported Languages](https://wayin.ai/api-docs/supported-languages/)). When `null`, the system auto-detects the original language. |
| `target_lang` | string | No | `null` | Target language for output content including clip titles, descriptions, and subtitles (see [Supported Languages](https://wayin.ai/api-docs/supported-languages/)). When `null`, the output language matches `source_lang`. |
| `limit` | number | No | `null` | Maximum number of clips to return, ranked by virality score from highest to lowest. When `null` or omitted, all clips are returned. |
| `enable_export` | boolean | No | `false` | See below. When `false`, only clip time ranges, titles, and descriptions are returned (no rendering); when `true`, clips are rendered immediately and each clip includes an export link. You can also export later with different styles via the [Export Existing Clips](#export-existing-clips) endpoint. |
| `resolution` | string | No | `SD_480` | Output resolution: `SD_480`, `HD_720`, `FHD_1080`, `QHD_2K`, `UHD_4K`. Only used when `enable_export` is `true`. |
| `enable_caption` | boolean | No | `false` | Whether to add Animated Caption when rendering. Only used when `enable_export` is `true`. When `true`, `caption_display` and `cc_style_tpl` take effect; when `false`, the export has no Animated Caption. |
| `caption_display` | string | No | `original` | Caption mode: `both`, `original`, `translation`. Only used when `enable_export` and `enable_caption` are both `true`. |
| `cc_style_tpl` | string | No | `temp-7` | Caption style template ID (see [Subtitle Styles](https://wayin.ai/api-docs/subtitles-style/)). Only used when `enable_export` and `enable_caption` are both `true`. |
| `enable_ai_hook` | boolean | No | `false` | Whether to add an automatically generated, attention-grabbing text hook at the beginning or end of each rendered clip. Only used when `enable_export` is `true`. When `true`, `ai_hook_script_style` and `ai_hook_position` take effect; when `false`, no AI hook is added. |
| `ai_hook_script_style` | string | No | `serious` | Style of the generated hook text. Allowed values: `serious`, `casual`, `informative`, `conversational`, `humorous`, `parody`, `inspirational`, `dramatic`, `empathetic`, `persuasive`, `neutral`, `excited`, `calm`. Only used when `enable_export` and `enable_ai_hook` are both `true`. |
| `ai_hook_position` | string | No | `beginning` | Position of the generated hook text. Allowed values: `beginning`, `end`. Only used when `enable_export` and `enable_ai_hook` are both `true`. |
| `enable_ai_reframe` | boolean | No | `false` | Enable AI Reframe. Only used when `enable_export` is `true`. When `true`, `ratio` is required; when `false`, the video is exported with its original aspect ratio unchanged. |
| `ratio` | string | Yes when `enable_ai_reframe` is `true` | — | Aspect ratio: `RATIO_9_16`, `RATIO_1_1`, `RATIO_4_5`, `RATIO_16_9`. Only used when `enable_export` is `true`, and required when `enable_ai_reframe` is `true`. |
| `reframe_layout` | string | No | `Auto` | AI Reframe layout. Only used when `enable_export` and `enable_ai_reframe` are both `true`. Default `Auto`: the model picks the best layout for the frame (omit the field or pass an empty string for the same behavior). When set to another allowed value for the chosen `ratio`, reframe uses that fixed layout. See [Reframe layout values](#reframe-layout-values). |

### Reframe layout values

Allowed `reframe_layout` values depend on `ratio`. `Auto` is always allowed (default); omitting the field or passing an empty string behaves the same. Pass layout names **exactly** as below (case- and spacing-sensitive).

| `ratio` | Allowed `reframe_layout` values |
|---------|-----------------------------------|
| `RATIO_16_9` | `Auto`, `Full`, `Fit`, `Grid 4`, `Split 2`, `Trio`, `PiP`, `OTS`, `Screen First` |
| `RATIO_9_16` | `Auto`, `Full`, `Fit`, `Grid 4`, `Split 2`, `Trio`, `PiP`, `Screen First`, `Gameplay A`, `Gameplay B` |
| `RATIO_1_1` | `Auto`, `Full`, `Fit`, `Grid 4`, `Trio` |
| `RATIO_4_5` | `Auto`, `Full`, `Fit`, `Grid 4`, `Split 2`, `Trio`, `PiP`, `Screen First`, `Gameplay A`, `Gameplay B` |

**`enable_export` behavior**

- When `enable_export` is empty or `false`, the API only returns clip time ranges, titles, descriptions, and related metadata. No rendering is performed, and there are no export links in the result. The parameters `ratio`, `reframe_layout`, `resolution`, `caption_display`, `enable_caption`, `cc_style_tpl`, `enable_ai_hook`, `ai_hook_script_style`, `ai_hook_position`, and `enable_ai_reframe` have no effect at task creation time. You can later render selected clips with the [Export Existing Clips](#export-existing-clips) endpoint.
- When `enable_export` is `true`, those parameters take effect, each clip is rendered immediately, and the result includes a download link for each clip. Because each clip is rendered, processing may take longer.

<div class="tabs" data-labels="With export|Without export" data-group="export-mode"></div>

Request body sets `enable_export` to `true`. Clips are rendered; each clip includes an `export_link`.

**Request**

```bash
curl -X POST https://wayinvideo-api.wayin.ai/api/v2/clips/find-moments \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "x-wayinvideo-api-version: v2" \
  -d '{
    "video_url": "https://www.youtube.com/watch?v=example",
    "query": "sample query",
    "project_name": "sample project name",
    "enable_export": true,
    "resolution": "FHD_1080",
    "enable_caption": true,
    "enable_ai_reframe": true,
    "ratio": "RATIO_9_16"
  }'
```

**Submit response**

```json
{
  "data": {
    "id": "proj_moment_789",
    "name": "sample project name",
    "status": "CREATED"
  }
}
```

<div class="tab-divider"></div>

Request body omits `enable_export` or sets it to `false`. Only clip time ranges, titles, descriptions, and tags are returned; no rendering, no export links.

**Request**

```bash
curl -X POST https://wayinvideo-api.wayin.ai/api/v2/clips/find-moments \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "x-wayinvideo-api-version: v2" \
  -d '{
    "video_url": "https://www.youtube.com/watch?v=example",
    "query": "sample query",
    "project_name": "sample project name"
  }'
```

**Submit response**

```json
{
  "data": {
    "id": "proj_moment_456",
    "name": "sample project name",
    "status": "CREATED"
  }
}
```

<div class="tabs-end"></div>

| Field | Type | Description |
|-------|------|-------------|
| `id` | string | Unique task identifier |
| `name` | string | Task name |
| `status` | string | `CREATED`, `QUEUED`, `ONGOING`, `SUCCEEDED`, `FAILED` |

---

## Examples

Common Find Moments scenarios. Replace `YOUR_API_KEY` with a key from the [API Dashboard](https://wayin.ai/wayinvideo/api-dashboard).

### Find funny moments in a YouTube video

```bash
curl -X POST https://wayinvideo-api.wayin.ai/api/v2/clips/find-moments \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "x-wayinvideo-api-version: v2" \
  -H "Content-Type: application/json" \
  -d '{
    "video_url": "https://www.youtube.com/watch?v=EXAMPLE",
    "query": "funny reactions"
  }'
```

### Extract product-demo segments from a long marketing video

```bash
curl -X POST https://wayinvideo-api.wayin.ai/api/v2/clips/find-moments \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "x-wayinvideo-api-version: v2" \
  -H "Content-Type: application/json" \
  -d '{
    "video_url": "https://www.youtube.com/watch?v=EXAMPLE",
    "query": "product demos and feature walkthroughs",
    "limit": 10
  }'
```

### Find sports highlights and export as vertical clips with captions

```bash
curl -X POST https://wayinvideo-api.wayin.ai/api/v2/clips/find-moments \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "x-wayinvideo-api-version: v2" \
  -H "Content-Type: application/json" \
  -d '{
    "video_url": "https://www.youtube.com/watch?v=EXAMPLE",
    "query": "goal moments and key plays",
    "enable_export": true,
    "resolution": "FHD_1080",
    "enable_caption": true,
    "enable_ai_reframe": true,
    "ratio": "RATIO_9_16"
  }'
```

---

## Get Find Moments Results

Poll for results until `status` is `SUCCEEDED`.

> **Incremental results:** When `status` is `ONGOING`, each call returns the clips generated so far — you can start processing partial results immediately. When `status` changes to `SUCCEEDED`, the response contains the complete set of clips.

```
GET https://wayinvideo-api.wayin.ai/api/v2/clips/find-moments/results/{id}
```

### Path Parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `id` | string | Yes | The task ID returned by the submit endpoint |

### Example Request

```bash
curl -X GET https://wayinvideo-api.wayin.ai/api/v2/clips/find-moments/results/proj_moment_456 \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "x-wayinvideo-api-version: v2"
```

<div class="tabs" data-labels="With export|Without export" data-group="export-mode"></div>

When the task was submitted with **`enable_export: true`**, each clip includes an `export_link` for the rendered video:

```json
{
  "data": {
    "id": "proj_moment_789",
    "name": "sample project name",
    "status": "SUCCEEDED",
    "expire_at": 1775831883112,
    "cost_usage": 120.0,
    "clips": [
      {
        "idx": 0,
        "title": "sample title",
        "begin_ms": 120000,
        "end_ms": 185000,
        "thumbnail": "https://cdn.example.com/thumb/moment_001.jpg",
        "tags": ["product", "announcement"],
        "desc": "sample description",
        "score": 81,
        "export_link": "https://cdn.example.com/export/moment_001.mp4"
      }
    ]
  }
}
```

<div class="tab-divider"></div>

When the task was submitted **without** `enable_export` (or with `enable_export: false`), clips do not include `export_link`:

```json
{
  "data": {
    "id": "proj_moment_456",
    "name": "sample project name",
    "status": "SUCCEEDED",
    "expire_at": 1775831883112,
    "cost_usage": 120.0,
    "clips": [
      {
        "idx": 0,
        "title": "sample title",
        "begin_ms": 120000,
        "end_ms": 185000,
        "thumbnail": "https://cdn.example.com/thumb/moment_001.jpg",
        "tags": ["product", "announcement"],
        "desc": "sample description",
        "score": 81
      }
    ]
  }
}
```

<div class="tabs-end"></div>

### Response Fields

| Field | Type | Description |
|-------|------|-------------|
| `id` | string | Unique task identifier |
| `name` | string | Task name |
| `status` | string | `CREATED`, `QUEUED`, `ONGOING`, `SUCCEEDED`, `FAILED` |
| `error_message` | string | Error reason (only present when `status` is `FAILED`) |
| `expire_at` | integer | Expiration timestamp in milliseconds (epoch). After this time, the task expires and results can no longer be retrieved via the results endpoint. The expiration period depends on your subscription plan. See the [Subscription Plans](https://wayin.ai/wayinvideo/settings/plan) page for details. `-1` means the result does not expire while a paid subscription is active. After the paid subscription ends, the result is kept for one more month and then expires. |
| `cost_usage` | number | API units consumed for this request |
| `clips` | array | List of clip objects (see below). When `status` is `ONGOING`, this contains the clips generated so far (partial results); when `status` is `SUCCEEDED`, this contains all clips (final results). |

### Clip Object

| Field | Type | Description |
|-------|------|-------------|
| `idx` | integer | Clip index (0-based, ranked by viral potential) |
| `title` | string | AI-generated clip title |
| `begin_ms` | number | Start time in milliseconds |
| `end_ms` | number | End time in milliseconds |
| `thumbnail` | string | Thumbnail image URL |
| `tags` | string[] | AI-generated hashtags |
| `desc` | string | AI-generated description |
| `score` | number | Viral potential score (0–100, higher is better) |
| `export_link` | string | Rendered video download URL (when `enable_export` is true). A new link is generated each time you call the results endpoint. Each link expires after 24 hours — please download the video before it expires. If the link has expired, call the results endpoint again to get a new one. |

---

## Re-export Existing Clips

If you want to render clips later or re-export them with a different subtitle style, aspect ratio, AI hook, overlays, or other export settings, use the [Clips Export API](https://wayin.ai/api-docs/clips-export/).

For Find Moments projects, pass the task `id` returned by `POST /api/v2/clips/find-moments` as `project_id` in the export request.


---

## FAQ

### How does Find Moments differ from AI Clipping?

[AI Clipping](https://wayin.ai/api-docs/ai-clipping/) returns clips ranked by viral potential automatically — no query needed. **Find Moments** lets you describe what you want in natural language (e.g. `"funny reactions"`, `"product demos"`, `"goal moments"`) and returns matching clips only.

### Can I limit the number of returned moments?

Yes. Pass `limit: N` to return only the top-N matches ranked by relevance. Useful when the source video is long and you only want the strongest matches.

### Does Find Moments support partial results?

Yes — when polling, segments with `status: ONGOING` already contain the clips generated so far, so you can begin downstream processing without waiting for the full task to finish.
