---
title: "Video API"
description: "Video processing API — upload, transcode, and serve video content"
canonical: "https://docs.ainative.studio/docs/live-streaming/video-api"
last-updated: "2026-10-22T17:48:46.689Z"
---

# Video API

Source: https://docs.ainative.studio/docs/live-streaming/video-api

> Video processing API — upload, transcode, and serve video content

# Video API

The Video API manages standalone video content separate from live streams. It includes WebRTC video sessions (powered by Cloudflare Calls), video CRUD, albums, showcase annotations, semantic search, ML-based recommendations, and engagement analytics.

---

## WebRTC video sessions

Video sessions use Cloudflare Calls for real-time WebRTC. Each session supports multiple participants with individual media tracks (audio, video, screen share).

### Get ICE servers

<span className="badge badge--get">GET</span> `/api/v1/ice-servers`

Get STUN/TURN server configuration for WebRTC. No auth required.

```json
{
  "ice_servers": [
    { "urls": ["stun:stun.l.google.com:19302"] },
    { "urls": ["stun:stun1.l.google.com:19302"] },
    {
      "urls": ["turn:turn.ainative.studio:3478"],
      "username": "ainative",
      "credential": "..."
    }
  ]
}
```

---

### Create session

<span className="badge badge--post">POST</span> `/api/v1/sessions`

Create a new video session backed by Cloudflare Calls.

**Auth required:** Yes  
**Rate limit:** 10 per minute

```json
{
  "session_name": "Team standup",
  "max_participants": 10
}
```

### Get session

<span className="badge badge--get">GET</span> `/api/v1/sessions/{session_id}`

**Auth required:** Yes

### Get active sessions

<span className="badge badge--get">GET</span> `/api/v1/sessions/active`

Get all currently active sessions for the authenticated user.

**Auth required:** Yes

### Get user sessions

<span className="badge badge--get">GET</span> `/api/v1/sessions/user/{user_id}`

Get all sessions for a specific user. Admins can access any user's sessions; regular users can only access their own.

**Auth required:** Yes

### Update session

<span className="badge badge--put">PUT</span> `/api/v1/sessions/{session_id}`

Update session details. Host only.

**Auth required:** Yes (host only)

### Delete session

<span className="badge badge--delete">DELETE</span> `/api/v1/sessions/{session_id}`

Delete a session. Host or admin only.

**Auth required:** Yes

---

### Generate session token

<span className="badge badge--post">POST</span> `/api/v1/sessions/{session_id}/token`

Generate a JWT access token and TURN credentials for joining the session.

**Auth required:** Yes

```json
{
  "token": "eyJ...",
  "turn_credentials": {
    "username": "...",
    "credential": "...",
    "ttl": 86400
  },
  "expires_at": "2026-04-26T10:00:00Z"
}
```

---

### Get participants

<span className="badge badge--get">GET</span> `/api/v1/sessions/{session_id}/participants`

List all participants in a session.

**Auth required:** Yes

---

### Add media track

<span className="badge badge--post">POST</span> `/api/v1/sessions/{session_id}/participants/{participant_id}/tracks`

Add a media track (audio, video, or screen share) to a session via WebRTC SDP offer exchange.

**Auth required:** Yes

```json
{
  "sdp": "v=0\r\no=...",
  "type": "video"
}
```

`type` values: `audio`, `video`, `screen`.

Returns an SDP answer for completing the WebRTC negotiation.

---

## Video CRUD

### Create video

<span className="badge badge--post">POST</span> `/api/v1/videos/`

Upload video metadata. The actual video file must be uploaded separately to Cloudflare Stream or object storage — this endpoint registers it in the platform.

**Auth required:** Yes

| Field | Type | Description |
|-------|------|-------------|
| `title` | string | Video title |
| `description` | string | Video description |
| `video_type` | string | `tutorial`, `webinar`, `demo`, or `other` |
| `video_url` | string | Video source URL |
| `thumbnail_url` | string | Thumbnail URL |
| `duration` | integer | Duration in seconds |
| `tags` | string[] | Tag list |
| `tech_stack` | string[] | Technologies shown |
| `project_url` | string | Related project URL |

### Get video

<span className="badge badge--get">GET</span> `/api/v1/videos/{video_id}`

**Auth required:** Yes

### Update video

<span className="badge badge--put">PUT</span> `/api/v1/videos/{video_id}`

**Auth required:** Yes (owner only)

### Delete video

<span className="badge badge--delete">DELETE</span> `/api/v1/videos/{video_id}`

**Auth required:** Yes (owner only). Returns `204 No Content`.

### List videos

<span className="badge badge--get">GET</span> `/api/v1/videos/`

List videos for the authenticated user with filtering and pagination.

**Auth required:** Yes

---

## Video analytics

### Track view

<span className="badge badge--post">POST</span> `/api/v1/videos/{video_id}/track-view`

Track a video view event. Uses SHA-256 IP hashing — raw IP addresses are never stored.

**Auth required:** No (optional — logged-in user's ID is recorded if provided)

```json
{
  "watch_duration": 420,
  "completion_percentage": 73.5,
  "session_id": "optional-session-uuid"
}
```

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `watch_duration` | integer | Yes | Time watched in seconds (≥0) |
| `completion_percentage` | float | Yes | Percent of video watched (0–100) |
| `session_id` | string | No | Session UUID for deduplication |

Returns a `session_id` to use for subsequent track-view calls in the same session.

### Get video analytics

<span className="badge badge--get">GET</span> `/api/v1/videos/{video_id}/analytics`

Get engagement metrics. Only accessible by the video owner.

**Auth required:** Yes (owner only)

```json
{
  "video_id": "video-uuid",
  "total_views": 12430,
  "unique_viewers": 8901,
  "avg_watch_duration": 312.4,
  "avg_completion_rate": 67.2,
  "likes": 432,
  "shares": 89,
  "comments_count": 147
}
```

### Get aggregated analytics

<span className="badge badge--get">GET</span> `/api/v1/videos/{video_id}/analytics/aggregated`

Get time-series analytics with configurable granularity and period.

**Auth required:** Yes (owner only)

| Parameter | Type | Options | Description |
|-----------|------|---------|-------------|
| `granularity` | string | `hourly`, `daily`, `weekly` | Time bucket size |
| `period` | string | `24h`, `7d`, `30d` | Lookback period |

### Get device breakdown

<span className="badge badge--get">GET</span> `/api/v1/videos/{video_id}/analytics/devices`

Get viewer breakdown by device type, browser, and OS.

**Auth required:** Yes (owner only)

### Get watch time distribution

<span className="badge badge--get">GET</span> `/api/v1/videos/{video_id}/analytics/watch-time-distribution`

Get how views are distributed across completion buckets: 0–25%, 25–50%, 50–75%, 75–100%.

**Auth required:** Yes (owner only)

### Get completion rate analytics

<span className="badge badge--get">GET</span> `/api/v1/videos/{video_id}/analytics/completion-rate`

Get detailed completion rate metrics and drop-off points.

**Auth required:** Yes (owner only)

| Parameter | Type | Description |
|-----------|------|-------------|
| `breakdown` | string | Optional: `device` to break down by device type |

### Get geographic analytics

<span className="badge badge--get">GET</span> `/api/v1/videos/{video_id}/analytics/geography`

Get geographic breakdown of viewers by country and city. Privacy-preserving — no raw IPs exposed.

**Auth required:** Yes (owner only)

### Get dashboard overview

<span className="badge badge--get">GET</span> `/api/v1/videos/{video_id}/analytics/dashboard`

Get a comprehensive analytics dashboard including overall metrics, trends compared to the previous period, peak hours, best-performing days, and optional real-time metrics.

**Auth required:** Yes (owner only)

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `include_realtime` | boolean | `false` | Include metrics from the last hour |

---

## Likes and shares

### Like a video

<span className="badge badge--post">POST</span> `/api/v1/videos/{video_id}/like`

Like a video. One like per user — returns `409` if already liked.

**Auth required:** Yes

```json
{
  "status": "success",
  "message": "Video liked successfully",
  "total_likes": 433
}
```

### Unlike a video

<span className="badge badge--delete">DELETE</span> `/api/v1/videos/{video_id}/like`

Remove a like. Returns `404` if the user has not liked the video.

**Auth required:** Yes

### Track share

<span className="badge badge--post">POST</span> `/api/v1/videos/{video_id}/share`

Record a video share event. Auth is optional — unauthenticated shares are tracked anonymously.

**Auth required:** No

```json
{
  "platform": "twitter"
}
```

`platform` is optional. Common values: `twitter`, `facebook`, `linkedin`, `email`.

---

## Video search

Semantic video search powered by ZeroDB embeddings with full-text fallback.

### Search videos

<span className="badge badge--post">POST</span> `/api/v1/projects/{project_id}/videos/search`

Search for videos using natural language queries. Results are ranked by semantic similarity.

**Auth required:** Yes

```json
{
  "query": "python machine learning tutorial for beginners",
  "category": "tutorial",
  "duration_min": 300,
  "duration_max": 3600,
  "author": "alice",
  "tags": ["python", "ml"],
  "limit": 10,
  "offset": 0
}
```

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `query` | string | — | Natural language query (1–500 chars, required) |
| `category` | string | — | Filter: `tutorial`, `webinar`, `showcase`, `demo` |
| `duration_min` | integer | — | Minimum duration in seconds |
| `duration_max` | integer | — | Maximum duration in seconds |
| `author` | string | — | Filter by author name |
| `tags` | string[] | — | Filter by tags (any match) |
| `limit` | integer | `10` | Results per page (max 100) |
| `offset` | integer | `0` | Pagination offset |

### Response

```json
{
  "results": [
    {
      "video_id": "video-uuid",
      "title": "Python ML Tutorial",
      "description": "Learn machine learning with Python",
      "category": "tutorial",
      "duration": 2340,
      "thumbnail_url": "https://...",
      "url": "/videos/video-uuid",
      "author": "alice",
      "tags": ["python", "ml"],
      "similarity_score": 0.92,
      "created_at": "2026-03-15T10:00:00Z"
    }
  ],
  "total": 24,
  "query": "python machine learning tutorial for beginners",
  "query_time_ms": 142.3,
  "limit": 10,
  "offset": 0
}
```

---

### Index video

<span className="badge badge--post">POST</span> `/api/v1/projects/{project_id}/videos/{video_id}/index`

Index or re-index a video for search. Videos are auto-indexed on upload and metadata updates. Use this to manually trigger indexing or fix index issues.

**Auth required:** Yes

```json
{
  "video_id": "video-uuid",
  "title": "Python ML Tutorial",
  "description": "...",
  "category": "tutorial",
  "duration": 2340,
  "thumbnail_url": "https://...",
  "author": "alice",
  "tags": ["python", "ml"]
}
```

**Indexed field weights:** title 50%, description 30%, tags 20%.

---

### Remove from search index

<span className="badge badge--delete">DELETE</span> `/api/v1/projects/{project_id}/videos/{video_id}/index`

Remove a video from the search index. Does not delete the video file itself.

**Auth required:** Yes

---

### Find related videos (search-based)

<span className="badge badge--post">POST</span> `/api/v1/projects/{project_id}/videos/{video_id}/related`

Find videos similar to a specific video using content-based similarity. Uses shared tags and category matching with embedding similarity where available.

**Auth required:** Yes

| Query parameter | Type | Default | Description |
|-----------------|------|---------|-------------|
| `limit` | integer | `5` | Max results (max 20) |
| `category_filter` | string | — | Optional category filter |

---

### Bulk index

<span className="badge badge--post">POST</span> `/api/v1/projects/{project_id}/videos/bulk-index`

Index multiple videos in a single operation. Useful for initial migration or batch re-indexing.

**Auth required:** Yes

```json
[
  {
    "video_id": "...",
    "title": "...",
    "category": "tutorial",
    ...
  }
]
```

Returns a summary: `{ "indexed_count": 45, "failed_count": 2, "errors": [...] }`.

---

## Video recommendations

ML-based recommendation system with multiple algorithm strategies.

### Get related videos

<span className="badge badge--get">GET</span> `/api/v1/videos/{video_id}/related`

Get ML-based recommendations for videos related to the given video. Results are cached for 1 hour.

**Auth required:** Yes

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `limit` | integer | `10` | Max recommendations (max 50) |
| `strategy` | string | `hybrid` | Algorithm: `content`, `collaborative`, or `hybrid` |

| Strategy | Description |
|----------|-------------|
| `content` | Semantic similarity via vector embeddings |
| `collaborative` | User viewing behavior patterns |
| `hybrid` | Weighted combination of both |

```json
{
  "video_id": "source-video-uuid",
  "recommendations": [
    {
      "video_id": "rec-video-uuid",
      "title": "Advanced Python Tutorial",
      "similarity_score": 0.87,
      "rank": 1
    }
  ],
  "strategy": "hybrid",
  "total": 10
}
```

---

### Track recommendation click

<span className="badge badge--post">POST</span> `/api/v1/videos/{video_id}/related/click`

Record when a user clicks a recommendation. Used for CTR analysis and feeding data into the RLHF improvement loop.

**Auth required:** No (optional)

```json
{
  "recommended_video_id": "rec-video-uuid",
  "rank": 1
}
```

---

### Get recommendation analytics

<span className="badge badge--get">GET</span> `/api/v1/videos/{video_id}/related/analytics`

Get CTR metrics for recommendations including total impressions, clicks, average CTR, and breakdown by rank position.

**Auth required:** Yes

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `time_range_days` | integer | `7` | Analytics lookback period (1–90 days) |

---

## Albums

Albums group photos and videos into curated collections.

### Create album

<span className="badge badge--post">POST</span> `/api/v1/albums/`

**Auth required:** Yes

```json
{
  "title": "Coding sessions 2026",
  "description": "My recorded coding sessions",
  "visibility": "public",
  "cover_url": "https://..."
}
```

### Get album

<span className="badge badge--get">GET</span> `/api/v1/albums/{album_id}`

Get album details with all items. Public albums are accessible without auth.

**Auth required:** No (optional)

### List user albums

<span className="badge badge--get">GET</span> `/api/v1/albums/`

Get all albums for the authenticated user.

**Auth required:** Yes

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `page` | integer | `1` | Page number |
| `page_size` | integer | `20` | Items per page (max 100) |

### Update album

<span className="badge badge--put">PUT</span> `/api/v1/albums/{album_id}`

Update album title, description, visibility, or cover image.

**Auth required:** Yes (owner only)

### Delete album

<span className="badge badge--delete">DELETE</span> `/api/v1/albums/{album_id}`

Delete an album and all its items. Returns `204 No Content`.

**Auth required:** Yes (owner only)

### Add item to album

<span className="badge badge--post">POST</span> `/api/v1/albums/{album_id}/items`

Add a photo or video to an album.

**Auth required:** Yes

```json
{
  "media_type": "video",
  "media_id": "video-uuid",
  "caption": "Episode 42"
}
```

### Remove item from album

<span className="badge badge--delete">DELETE</span> `/api/v1/albums/{album_id}/items/{item_id}`

Remove an item. Returns `204 No Content`.

**Auth required:** Yes (owner only)

### Reorder album items

<span className="badge badge--post">POST</span> `/api/v1/albums/{album_id}/reorder`

Change the display order of items in an album. Returns `204 No Content`.

**Auth required:** Yes

```json
{
  "item_orders": [
    { "item_id": "item-uuid-1", "order": 0 },
    { "item_id": "item-uuid-2", "order": 1 }
  ]
}
```

---

## Showcase videos & annotations

Showcase videos are `DEMO` type videos with interactive timed annotations for feature demonstrations.

### Filter showcase videos

<span className="badge badge--get">GET</span> `/api/v1/showcase-videos/showcase`

Filter and search showcase demo videos. Returns only `DEMO` type videos.

**Auth required:** Yes

| Parameter | Type | Description |
|-----------|------|-------------|
| `tech_stack` | string | Comma-separated technologies (e.g., `React,Python`) |
| `tags` | string | Comma-separated tags (e.g., `opensource,tutorial`) |
| `search` | string | Keyword search in title and description |
| `page` | integer | Page number |
| `limit` | integer | Items per page (max 100, default 10) |

```bash
GET /api/v1/showcase-videos/showcase?tech_stack=React,FastAPI&tags=tutorial&search=auth
```

---

### Create annotation

<span className="badge badge--post">POST</span> `/api/v1/showcase-videos/{video_id}/annotations`

Add a timed annotation to a showcase video. Annotations appear as interactive markers during playback.

**Auth required:** Yes (video owner only)

```json
{
  "timestamp": 42.5,
  "title": "Database connection setup",
  "description": "Here we configure the SQLAlchemy engine with connection pooling",
  "annotation_type": "feature",
  "url": "https://docs.ainative.studio/..."
}
```

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `timestamp` | float | Yes | Seconds into the video |
| `title` | string | Yes | Annotation title |
| `description` | string | No | Detail text |
| `annotation_type` | string | Yes | `info`, `feature`, `bug-fix`, or `demo` |
| `url` | string | No | Related URL |

Returns `400` if the timestamp exceeds the video duration.

---

### List annotations

<span className="badge badge--get">GET</span> `/api/v1/showcase-videos/{video_id}/annotations`

Get all annotations for a video in chronological order (sorted by timestamp).

**Auth required:** Yes

| Parameter | Type | Description |
|-----------|------|-------------|
| `type` | string | Filter: `info`, `feature`, `bug-fix`, or `demo` |

---

### Update annotation

<span className="badge badge--patch">PATCH</span> `/api/v1/showcase-videos/{video_id}/annotations/{annotation_id}`

Update an existing annotation. All fields are optional.

**Auth required:** Yes (video owner only)

---

### Delete annotation

<span className="badge badge--delete">DELETE</span> `/api/v1/showcase-videos/{video_id}/annotations/{annotation_id}`

Delete an annotation. Returns `204 No Content`.

**Auth required:** Yes (video owner only)
