Skip to content
Video Assets Server

Video Assets Server API reference

One search API for free stock video: b-roll, backgrounds, nature, cities, space and archive films, with licence verdicts. Version 0.1.0, base URL https://video.shep.bot. Machine-readable:OpenAPI 3.1 JSON. Want to send requests from the browser? Open theinteractive API playground.

  • Authentication: none on the public server. Self-hosted servers may require Authorization: Bearer <key> or x-api-key.
  • Rate limits: 120 requests per minute per client, announced in RateLimit-Policy / RateLimit headers; 429 comes with Retry-After. See versioning & rate limits.
  • Errors: JSON { "error": "message" } with a 4xx/5xx status.

Find clips across every source in one call.

GET/v1/searchSearch every source

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.

Parameters

NameInTypeDescription
qquerystringShort query, written like an editor would.
categoryquerystringComma-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.
stylequerystringComma-separated styles (ranked first; filtered only with strict=true): timelapse, slow-motion, loop, animation, visualization, black-white.
orientationquerystringComma-separated: landscape, portrait, square.
min_resolutionquerystringShort side at least: 720, 1080, 1440, 2160, or hd / fhd / 4k.
min_durationquerynumberMinimum length in seconds.
max_durationquerynumberMaximum length in seconds.
min_fpsquerynumberMinimum frame rate.
audioquerybooleanOnly clips with (true) or without (false) a sound track.
commercialquerybooleanOnly clips whose licence verdict is yes or yes-with-credit.
freequerybooleanOnly free clips.
downloadablequerybooleanOnly clips with direct file links.
strictquerybooleanDrop clips whose orientation, resolution, length, fps or audio is unknown when that filter is set.
providersquerystringComma-separated source ids (see /v1/providers).
limitqueryintegerMax results (default 24).
offsetqueryintegerPer-source offset for paging (e.g. 24 for page 2).

Responses

  • 200Ranked results, the filters in force and a per-source report.SearchResponseheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
  • 400Invalid parameters or unknown source id.Errorheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
  • 401API key required (self-hosted servers only).Errorheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
  • 429Rate limit exceeded. Wait Retry-After seconds.Errorheaders: Retry-After, RateLimit, RateLimit-Policy

Example

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

Clips

Details, renditions, downloads and credits for one clip.

GET/v1/clips/{id}Clip details, renditions and watch URL

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.

Parameters

NameInTypeDescription
id *pathstringClip id <provider>:<nativeId> (URL-encode it: ids can contain spaces and slashes).

Responses

  • 200The clip and its files.ClipDetailsheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
  • 400Malformed id or unknown source.Errorheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
  • 404Unknown clip.Errorheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
  • 429Rate limit exceeded. Wait Retry-After seconds.Errorheaders: Retry-After, RateLimit, RateLimit-Policy
  • 501The source has no detail pages here; open url on the source site.Errorheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
  • 502The source site failed.Errorheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset

Example

curl "https://video.shep.bot/v1/clips/wikimediacommons:Ocean_in_Sommaroy.webm"
GET/v1/clips/{id}/filesPick the right file

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

Parameters

NameInTypeDescription
id *pathstringClip id <provider>:<nativeId> (URL-encode it: ids can contain spaces and slashes).
heightqueryintegerWanted resolution as the short side in pixels (720, 1080, 2160): the smallest file at or above it, else the biggest below.
formatquerystringPreferred container: mp4, webm, mov, ogv.
rolequery"original" | "rendition" | "preview" | "poster" | "captions"Only files with this role: original, rendition, preview, poster, captions.
allquerybooleanEvery file, including posters and captions.

Responses

  • 200Selected files and total size.FileSelectionheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
  • 404Unknown clip.Errorheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
  • 429Rate limit exceeded. Wait Retry-After seconds.Errorheaders: Retry-After, RateLimit, RateLimit-Policy

Example

curl "https://video.shep.bot/v1/clips/wikimediacommons:Ocean_in_Sommaroy.webm/files"
GET/v1/clips/{id}/downloadDownload (redirect to the source)

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.

Parameters

NameInTypeDescription
id *pathstringClip id <provider>:<nativeId> (URL-encode it: ids can contain spaces and slashes).
heightqueryintegerWanted resolution as the short side in pixels (720, 1080, 2160): the smallest file at or above it, else the biggest below.
formatquerystringPreferred container: mp4, webm, mov, ogv.
rolequery"original" | "rendition" | "preview" | "poster" | "captions"Only files with this role: original, rendition, preview, poster, captions.

Responses

  • 302Redirect to the file.headers: Location, X-License, X-Attribution, RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
  • 404Unknown clip, or no file matches.Errorheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
  • 409No direct download: get it from the source page.Errorheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
  • 429Rate limit exceeded. Wait Retry-After seconds.Errorheaders: Retry-After, RateLimit, RateLimit-Policy

Example

curl -L -O "https://video.shep.bot/v1/clips/wikimediacommons:Ocean_in_Sommaroy.webm/download"
GET/v1/clips/{id}/creditsCredits for a clip

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

Parameters

NameInTypeDescription
id *pathstringClip id <provider>:<nativeId> (URL-encode it: ids can contain spaces and slashes).
formatquery"md" | "json" | "zip"

Responses

  • 200The credits.stringheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
  • 404Unknown clip.Errorheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
  • 429Rate limit exceeded. Wait Retry-After seconds.Errorheaders: Retry-After, RateLimit, RateLimit-Policy

Example

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

Sequences

Turn a shot list into a b-roll sequence in one call.

POST/v1/sequencesPlan a b-roll sequence from a shot list

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

  • 200The plan and its exports.SequenceResponseheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
  • 400Invalid body.Errorheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
  • 429Rate limit exceeded. Wait Retry-After seconds.Errorheaders: Retry-After, RateLimit, RateLimit-Policy

Example

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

Sources

The video sites this server searches, what they hold, and how the server is used.

GET/v1/providersList sources

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

Responses

  • 200Sources.objectheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
  • 429Rate limit exceeded. Wait Retry-After seconds.Errorheaders: Retry-After, RateLimit, RateLimit-Policy

Example

curl "https://video.shep.bot/v1/providers"
GET/v1/catalogCatalog census

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

  • 200Catalog census.Catalogheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
  • 404The census has not been built on this server.Errorheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
  • 429Rate limit exceeded. Wait Retry-After seconds.Errorheaders: Retry-After, RateLimit, RateLimit-Policy

Example

curl "https://video.shep.bot/v1/catalog"
GET/v1/statsUsage statistics

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

  • 200Usage statistics.Statsheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
  • 429Rate limit exceeded. Wait Retry-After seconds.Errorheaders: Retry-After, RateLimit, RateLimit-Policy

Example

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

MCP

Model Context Protocol endpoint for AI agents.

POST/mcpMCP endpoint (Streamable HTTP)

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

  • 200JSON-RPC 2.0 response.objectheaders: RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset
  • 429Rate limit exceeded. Wait Retry-After seconds.Errorheaders: Retry-After, RateLimit, RateLimit-Policy

Example

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}}}'

System

Health and machine-readable descriptions.

GET/healthHealth check

Responses

  • 200OKobject

Example

curl "https://video.shep.bot/health"
GET/openapi.jsonThis OpenAPI document

Responses

  • 200OpenAPI 3.1object

Example

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

Schemas

Category

One of: nature, nature.ocean, nature.water, nature.sky, nature.forest, nature.mountain, nature.animals, city, city.street, city.skyline, people, people.work, people.lifestyle, people.sport, aerial, space, space.earth, space.launch, space.planets, science, tech, transport, food, background, background.abstract, overlay, overlay.light, overlay.particles, overlay.film, greenscreen, archive, archive.newsreel, archive.film, other

VideoStyle

One of: timelapse, slow-motion, loop, animation, visualization, black-white

Orientation

One of: landscape, portrait, square

CommercialVerdict

One of: yes, yes-with-credit, restricted, clearance-required, check-terms, no

NativeFilter

One of: categories, styles, orientation, resolution, duration, fps, audio, commercialOnly, freeOnly

License

id *stringSPDX id where one exists (CC0-1.0, CC-BY-4.0…), else LicenseRef-*.
name *string
urlstring (uri)
commercialUseboolean
attributionRequiredboolean
shareAlikeboolean
redistributionbooleanMay the clip itself be re-uploaded or passed on?
editorialbooleanPeople, insignia or brands without releases: fine for news and documentary, not for ads.
assertedBy *"source" | "site" | "uploader"uploader = an unverified claim (verdict capped at check-terms).
verdict *CommercialVerdict
notestring

Price

free *boolean
amountnumber
currencystring

Clip

id *string<provider>:<nativeId>
provider *string
nativeId *string
title *string
descriptionstring
url *string (uri)The clip's page on the source site.
authorstring
authorUrlstring (uri)
tags *string[]
category *Category
categoryEvidenceobject
stylesVideoStyle[]
orientationOrientation
widthintegerFrame width of the best version.
heightinteger
fpsnumber
durationSecnumber
hasAudioboolean
yearintegerYear the footage was made (archive films).
posterUrlstring (uri)Still frame, on the source's CDN.
previewUrlstring (uri)Small playable version (mp4/webm) on the source's CDN.
previewTypestring
formatsstring[]
licenseLicense
attributionstringReady-to-paste credit line when the licence asks for one.
pricePrice
requiresAccountboolean
downloadable *boolean
createdAtstring (date-time)
popularitynumber
sameAsstring[]
scorenumber

ClipFile

url *string (uri)
filename *string
format *stringContainer: mp4, webm, mov, ogv, mpeg… (Commons originals are WebM/Ogg, never MP4).
mimestring
role *"original" | "rendition" | "preview" | "poster" | "captions"
widthinteger
heightinteger
fpsnumber
codecstring
sizeBytesinteger
bitrateinteger
requiresAuthboolean

ClipDetails

Clip & object

ClipFilters

categoriesCategory[]
stylesVideoStyle[]
orientationsOrientation[]
minResolutionintegerShort side in pixels.
durationobject
minFpsnumber
hasAudioboolean
commercialOnlyboolean
freeOnlyboolean

ProviderSearchReport

provider *string
name *string
status *"ok" | "error" | "timeout" | "skipped" | "link"link = the source can only be searched on its own site: open searchUrl.
count *integer
totalinteger
searchUrlstring (uri)
errorstring
filteredLocallyNativeFilter[]
tookMs *integer

SearchResponse

query *stringThe words searched after the filters were parsed out.
filters *ClipFilters
results *Clip[]
providers *ProviderSearchReport[]

Provider

id *string
name *string
homepage *string (uri)
description *string
categories *Category[]Top-level categories the source carries.
access *"api" | "static" | "scrape" | "link"api official API; static a curated manifest filtered locally; scrape public pages; link deep links only (paid/partner API, no key yet, or terms that forbid aggregation).
pricing *"free" | "freemium" | "paid"
licenseLicense
apiKeyEnvstringEnvironment variable holding the source's API key on a self-hosted server.
supportsDownload *boolean
nativeFiltersNativeFilter[]Filters the source applies itself; the rest are applied locally.
enabledboolean

FileSelection

id *string
licenseLicense
attributionstring
totalBytesinteger
files *ClipFile[]

SequenceRequest

shots *object
orientationOrientation
widthinteger
heightinteger
fpsnumber
totalDurationnumberSeconds, split over shots without their own length (default 4 s each).
commercialOnlyboolean
providersstring[]
alternativesinteger
namestring

SequenceShot

index *integer
description *string
durationSec *number
inSec *numberIn-point in the source clip (skips title cards on long films).
clipClip
fileClipFile
alternatives *Clip[]
notestring

SequenceResponse

plan *object
exports *objectFile contents, ready to save: an OpenTimelineIO timeline, an ffmpeg render script, a Remotion clip list and the credits. Media URLs point at the sources.

CountWithBound

count *integer
atLeastbooleanThe count is a lower bound.

SourceCensus

id *string
name *string
homepage *string (uri)
licensestringThe source's single licence id, when uniform.
pricing"free" | "freemium" | "paid"
supportsDownloadboolean
total *integerListings on the source (free and paid).
atLeastboolean
freeinteger
byCategory *objectListings per top-level category; each listing counts once.
byLicenseobject
categoriesobjectThe source's own categories or tags (may overlap).
unit"clips" | "packs"
addedLast30Daysinteger
downloadsintegerTotal downloads, when the source publishes them.
highlightsobject[]
method *stringHow the source was counted.
countedAt *string (date-time)
staleobject

Catalog

countedAt *string (date-time)
totals *object
byCategory *objectListings per top-level category across sources.
byLicense *object
sources *SourceCensus[]
linkedobject[]

UsageWindow

key *string24h, 7d, or process (since the last restart).
label *string
searches *integer
searchesWithResults *integer
bySurface *object
clipViews *integer
downloads *integer
toolCalls *integerMCP tool calls.
pageViews *integerWebsite pages served.

Ranked

name *string
count *integer

ProviderHealth

provider *string
requests *integerSearches that reached the source.
ok *integer
errors *integer
timeouts *integer
okRate *number | null
p50Ms *integer | null
p95Ms *integer | null

Stats

generatedAt *string (date-time)
source *"prometheus" | "process"
sincestring (date-time)Start of counting for source: process.
windows *UsageWindow[]
breakdownLabel *stringPeriod covered by clients, tools and assetTypes.
clients *Ranked[]Searches by client family (claude-code, cursor, browser, curl…).
tools *Ranked[]MCP tool calls by tool.
assetTypes *Ranked[]Searches by category filter (any = no filter).
providers *ProviderHealth[]Per-source health over the last 24 hours.
catalog *object

Error

error *string
urlstring (uri)The clip's page on the source, when the file must be fetched there.
requiresAccountboolean
retryAfterinteger

AI agent? This page is also available as markdown.