Overview
Everything is JSON over HTTPS, no key needed for reading. Base URL: https://www.prerolls.me. There are two ways in:
- Static catalog files: the whole library in one file, rebuilt every time we publish. Served from Cloudflare's cache, so fetch it as often as you like.
- Live endpoints: search and single-item lookups straight from the database. Rate-limited per IP.
Full catalog (recommended)
| Endpoint | Returns |
|---|---|
GET /api/v1/catalog.json | Every published preroll, plus platforms, categories and tags |
GET /api/v1/platforms/{plex|jellyfin|emby}.json | Prerolls made for one server |
GET /api/v1/categories/{slug}.json | Prerolls in one category |
curl https://www.prerolls.me/api/v1/catalog.json
{
"version": 1,
"generatedAt": "2026-11-06T10:00:00.000Z",
"count": 140,
"platforms": [...], "categories": [...], "tags": [...],
"prerolls": [ { ...preroll object... } ]
}Use generatedAt or each item's updatedAt to tell when something changed.
Live search API
GET /api/v1/prerolls with any of these query parameters:
| Param | Example | Notes |
|---|---|---|
q | netflix | Matches title, category, tags |
platform | plex | plex, jellyfin or emby |
category | studio-logos | Category slug |
tag | christmas | Tag slug |
duration | lt10 | lt10, 10-20, 20-30, 30plus |
sort | popular | newest (default), popular, loved, shortest, az |
page, limit | 1, 24 | limit is capped at 100 |
GET /api/v1/prerolls?platform=jellyfin&sort=popular&limit=10
{ "data": [ ... ], "page": 1, "limit": 10, "total": 30, "totalPages": 3 }GET /api/v1/prerolls/{slug} returns one preroll, or 404.
The preroll object
{
"id": "kYJ9gXbEky7O",
"slug": "x-logo-emby-pre-roll",
"title": "X Logo",
"description": "Two metallic lines cross to form a letter in this sleek industrial video. The minimal design offers a clean and professional look for the screen.",
"url": "https://www.prerolls.me/preroll/x-logo-emby-pre-roll",
"platforms": [
"emby"
],
"category": {
"slug": "glitch-tech",
"name": "Glitch & Tech"
},
"tags": [],
"source": "r2",
"durationSeconds": 5.4,
"width": 1920,
"height": 1080,
"fileSize": 3273811,
"mime": "video/mp4",
"thumbnail": {
"small": "https://videos.prerolls.me/thumbs/kYJ9gXbEky7O-480.webp",
"large": "https://videos.prerolls.me/thumbs/kYJ9gXbEky7O-960.webp"
},
"video": {
"directUrl": "https://videos.prerolls.me/X%20Logo%20Emby%20Pre-roll.mp4",
"embedUrl": null,
"watchUrl": null,
"youtubeId": null,
"vimeoId": null
},
"download": {
"url": "https://www.prerolls.me/download/x-logo-emby-pre-roll",
"isDirectFile": true
},
"credit": null,
"customizeUrl": "https://priyansh.net/store",
"stats": {
"downloads": 0,
"likes": 0
},
"publishedAt": "2026-01-16T01:24:00Z",
"updatedAt": "2026-01-16T01:24:00Z"
}sourceisr2(we host the MP4),youtubeorvimeo.video.directUrlis a plain MP4 URL forr2items, andnullotherwise.creditis who made it. Please show it if you display the preroll in your app.
Downloading files
Use download.url (/download/{slug}). It counts the download, which keeps our "most downloaded" list honest, then redirects. When download.isDirectFile is true, it ends at the MP4 itself. Otherwise it goes to the creator's link or a third-party page, so check the response type before saving it as a video.
Example: sync a folder
// Node 20+: download every Jellyfin preroll we host into ./prerolls
import fs from 'node:fs';
const res = await fetch('https://www.prerolls.me/api/v1/platforms/jellyfin.json');
const { prerolls } = await res.json();
fs.mkdirSync('prerolls', { recursive: true });
for (const p of prerolls.filter((p) => p.download.isDirectFile)) {
const file = `prerolls/${p.slug}.mp4`;
if (fs.existsSync(file)) continue;
const mp4 = await fetch(p.download.url);
fs.writeFileSync(file, Buffer.from(await mp4.arrayBuffer()));
}Admin API
Writing to the library (adding prerolls, bulk uploads, approvals) goes through /api/v1/admin/* and needs an API key created in the admin panel, sent as Authorization: Bearer <key>. Keys have scopes (read, write, upload, delete). This part isn't public.
Fair use
- Prefer the static catalog for syncing. Poll it at most once an hour.
- Live endpoints are limited to about 120 requests a minute per IP. You'll get
429past that. - Link back to the preroll page (
url) and show the credit where you can. - Prerolls are meant for personal media servers.
