# API reference

> Video Assets Server API 0.1.0: every endpoint, parameter and response. Machine-readable: https://video.shep.bot/openapi.json

## GET /v1/search

Search every source (`searchClips`)

Fans out to every enabled source in parallel (each with its own timeout), then merges and ranks. Words like `4k`, `1080p`, `vertical`, `9:16`, `10s`, `under 30 seconds`, `60fps`, `timelapse` in `q` become filters (see `filters` in the response); explicit parameters win. A single length (`10s`) means at least that long. Unknown orientation, resolution, length or fps stay in the list, ranked below known matches, unless `strict=true`. A slow or failing source never fails the search: it shows up in `providers` with its status.

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `q` | query | string | Short query, written like an editor would. |
| `category` | query | string | Comma-separated categories; a parent includes its children. Top level: nature, city, people, aerial, space, science, tech, transport, food, background, overlay, greenscreen, archive, other; children like `nature.ocean`, `city.skyline`, `space.launch`, `overlay.light`. |
| `style` | query | string | Comma-separated styles (ranked first; filtered only with strict=true): timelapse, slow-motion, loop, animation, visualization, black-white. |
| `orientation` | query | string | Comma-separated: landscape, portrait, square. |
| `min_resolution` | query | string | Short side at least: 720, 1080, 1440, 2160, or hd / fhd / 4k. |
| `min_duration` | query | number | Minimum length in seconds. |
| `max_duration` | query | number | Maximum length in seconds. |
| `min_fps` | query | number | Minimum frame rate. |
| `audio` | query | boolean | Only clips with (true) or without (false) a sound track. |
| `commercial` | query | boolean | Only clips whose licence verdict is `yes` or `yes-with-credit`. |
| `free` | query | boolean | Only free clips. |
| `downloadable` | query | boolean | Only clips with direct file links. |
| `strict` | query | boolean | Drop clips whose orientation, resolution, length, fps or audio is unknown when that filter is set. |
| `providers` | query | string | Comma-separated source ids (see /v1/providers). |
| `limit` | query | integer | Max results (default 24). |
| `offset` | query | integer | Per-source offset for paging (e.g. 24 for page 2). |

Responses: `200` Ranked results, the filters in force and a per-source report. (SearchResponse); `400` Invalid parameters or unknown source id. (Error); `401` API key required (self-hosted servers only). (Error); `429` Rate limit exceeded. Wait `Retry-After` seconds. (Error)

```bash
curl "https://video.shep.bot/v1/search?category=nature.ocean&style=timelapse&orientation=portrait&min_resolution=1080&providers=nasa%2Cwikimediacommons"
```

## GET /v1/clips/{id}

Clip details, renditions and watch URL (`getClip`)

Full metadata, the licence with its verdict and credit line, every file (master, renditions, preview, poster, captions) and the file a browser player should stream.

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `id` (required) | path | string | Clip id `<provider>:<nativeId>` (URL-encode it: ids can contain spaces and slashes). |

Responses: `200` The clip and its files. (ClipDetails); `400` Malformed id or unknown source. (Error); `404` Unknown clip. (Error); `429` Rate limit exceeded. Wait `Retry-After` seconds. (Error); `501` The source has no detail pages here; open `url` on the source site. (Error); `502` The source site failed. (Error)

```bash
curl "https://video.shep.bot/v1/clips/wikimediacommons:Ocean_in_Sommaroy.webm"
```

## GET /v1/clips/{id}/files

Pick the right file (`selectFiles`)

The best file for a resolution and container (the master by default), or every file with `all=true`, with sizes and the licence.

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `id` (required) | path | string | Clip id `<provider>:<nativeId>` (URL-encode it: ids can contain spaces and slashes). |
| `height` | query | integer | Wanted resolution as the short side in pixels (720, 1080, 2160): the smallest file at or above it, else the biggest below. |
| `format` | query | string | Preferred container: mp4, webm, mov, ogv. |
| `role` | query | "original" \| "rendition" \| "preview" \| "poster" \| "captions" | Only files with this role: original, rendition, preview, poster, captions. |
| `all` | query | boolean | Every file, including posters and captions. |

Responses: `200` Selected files and total size. (FileSelection); `404` Unknown clip. (Error); `429` Rate limit exceeded. Wait `Retry-After` seconds. (Error)

```bash
curl "https://video.shep.bot/v1/clips/wikimediacommons:Ocean_in_Sommaroy.webm/files"
```

## GET /v1/clips/{id}/download

Download (redirect to the source) (`downloadClip`)

Answers 302 to the chosen file on the source's CDN: the video never passes through this server. `height` picks a rendition (the smallest at or above it), `format` a container. The licence and credit line come back as `X-License` and `X-Attribution` headers; get the credits as files from `/v1/clips/{id}/credits`.

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `id` (required) | path | string | Clip id `<provider>:<nativeId>` (URL-encode it: ids can contain spaces and slashes). |
| `height` | query | integer | Wanted resolution as the short side in pixels (720, 1080, 2160): the smallest file at or above it, else the biggest below. |
| `format` | query | string | Preferred container: mp4, webm, mov, ogv. |
| `role` | query | "original" \| "rendition" \| "preview" \| "poster" \| "captions" | Only files with this role: original, rendition, preview, poster, captions. |

Responses: `302` Redirect to the file.; `404` Unknown clip, or no file matches. (Error); `409` No direct download: get it from the source page. (Error); `429` Rate limit exceeded. Wait `Retry-After` seconds. (Error)

```bash
curl -L -O "https://video.shep.bot/v1/clips/wikimediacommons:Ocean_in_Sommaroy.webm/download"
```

## GET /v1/clips/{id}/credits

Credits for a clip (`clipCredits`)

ATTRIBUTION.md (default), credits.json, or a zip holding both. No video inside.

| Parameter | In | Type | Description |
| --- | --- | --- | --- |
| `id` (required) | path | string | Clip id `<provider>:<nativeId>` (URL-encode it: ids can contain spaces and slashes). |
| `format` | query | "md" \| "json" \| "zip" |  |

Responses: `200` The credits. (string); `404` Unknown clip. (Error); `429` Rate limit exceeded. Wait `Retry-After` seconds. (Error)

```bash
curl "https://video.shep.bot/v1/clips/wikimediacommons:Ocean_in_Sommaroy.webm/credits"
```

## POST /v1/sequences

Plan a b-roll sequence from a shot list (`planSequence`)

One clip per shot, matching the target orientation, at least 1080p where possible, long enough for its shot, commercial-safe by default and directly downloadable; alternatives per shot. Returns the plan and the files to save: an OpenTimelineIO timeline, an ffmpeg script that renders the sequence, a Remotion clip list and the credits.

Responses: `200` The plan and its exports. (SequenceResponse); `400` Invalid body. (Error); `429` Rate limit exceeded. Wait `Retry-After` seconds. (Error)

```bash
curl -X POST "https://video.shep.bot/v1/sequences" \
  -H "content-type: application/json" -H "accept: application/json, text/event-stream" \
  -d '{}'
```

## GET /v1/providers

List sources (`listProviders`)

Every clip site with the categories it carries, pricing, licence, the filters it applies itself and whether files can be downloaded directly.

Responses: `200` Sources. (object); `429` Rate limit exceeded. Wait `Retry-After` seconds. (Error)

```bash
curl "https://video.shep.bot/v1/providers"
```

## GET /v1/catalog

Catalog census (`getCatalog`)

How many clips every source holds, counted once a day: listings per source, by top-level category, licence and the source's own categories, free counts, listings added in the last 30 days, and highlights such as the most downloaded clip. `atLeast: true` marks lower bounds (sources that cap their counts). Sources whose count failed today keep their last good numbers with `stale`. The same file is at `/catalog.json`; one point per day is in `/catalog-history.json`.

Responses: `200` Catalog census. (Catalog); `404` The census has not been built on this server. (Error); `429` Rate limit exceeded. Wait `Retry-After` seconds. (Error)

```bash
curl "https://video.shep.bot/v1/catalog"
```

## GET /v1/stats

Usage statistics (`getStats`)

Aggregate usage of this server: searches by surface (web, API, MCP), downloads, MCP tool calls, the client families and categories searched most, and per-source health (success rate, p50/p95 latency). Counts come from Prometheus (`source: prometheus`, last 24 hours and 7 days) or, when it is unavailable, from this process since it started (`source: process`). No queries, IPs or user agents are exposed. Cached for 60 seconds.

Responses: `200` Usage statistics. (Stats); `429` Rate limit exceeded. Wait `Retry-After` seconds. (Error)

```bash
curl "https://video.shep.bot/v1/stats"
```

## POST /mcp

MCP endpoint (Streamable HTTP) (`mcp`)

Stateless Model Context Protocol endpoint for AI agents. Tools: `search_videos`, `get_video`, `build_sequence`, `list_sources` (and `download_video` on local installs, which saves files with their credits). Point any MCP client at this URL; see /docs/mcp for per-client setup.

Responses: `200` JSON-RPC 2.0 response. (object); `429` Rate limit exceeded. Wait `Retry-After` seconds. (Error)

```bash
curl -X POST "https://video.shep.bot/mcp" \
  -H "content-type: application/json" -H "accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"search_videos","arguments":{"query":"ocean waves at sunset","orientation":"portrait","min_resolution":1080,"commercial_only":true}}}'
```

## GET /health

Health check (`health`)

Responses: `200` OK (object)

```bash
curl "https://video.shep.bot/health"
```

## GET /openapi.json

This OpenAPI document (`openapi`)

Responses: `200` OpenAPI 3.1 (object)

```bash
curl "https://video.shep.bot/openapi.json"
```

Schemas: Category, VideoStyle, Orientation, CommercialVerdict, NativeFilter, License, Price, Clip, ClipFile, ClipDetails, ClipFilters, ProviderSearchReport, SearchResponse, Provider, FileSelection, SequenceRequest, SequenceShot, SequenceResponse, CountWithBound, SourceCensus, Catalog, UsageWindow, Ranked, ProviderHealth, Stats, Error. See https://video.shep.bot/openapi.json.

---
Source: https://video.shep.bot/docs/api/reference
