A plain JSON API over everything you track — history, watchlist, lists, ratings, progress. Call a URL, get JSON back. Your data stays yours; now your scripts get it too.
Tokens, not OAuth
Personal access tokens, minted in Settings, shown once, hashed at rest. Revoke any of them the moment an app misbehaves.
Scoped by default
read for GETs, write for check-ins and watchlist edits. A read-only token can never touch your data.
Honest limits
300 requests per 5 minutes per token, with X-RateLimit headers on every response so you never have to guess.
The API lives at:
https://reelease.tv/api/v1Create a token in Settings → Developer — name it after the app, tick the scopes it needs. The full token (it starts with rls_) appears exactly once. We keep a sha256 hash, so nobody — including us — can read it back. Send it as a bearer token:
curl https://reelease.tv/api/v1/me \
-H "Authorization: Bearer rls_your_token_here"Missing or revoked tokens get a 401. A token without the needed scope gets a 403. Treat tokens like passwords: environment variables, not source code.
Success responses wrap the payload in data; paginated endpoints add pagination. Errors are machine-readable and human-explained:
// 200 / 201
{ "data": …, "pagination": { "page": 1, "limit": 25, "total": 3120, "totalPages": 125, "hasMore": true } }
// 4xx / 5xx
{ "error": { "code": "insufficient_scope", "message": "This endpoint requires the \"write\" scope; …" } }Codes you’ll meet: unauthorized · insufficient_scope · invalid_request · not_found · rate_limited · internal_error
Each token gets a sliding window of 300 requests per 5 minutes. Every rate-limited response carries the full picture; go over and you get a 429 with Retry-After.
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 287
X-RateLimit-Reset: 1783532460 // epoch secondsThe token’s account identity — id, username, display name, timezone, member-since. No email, ever: your apps get a display identity, not a contact channel.
curl https://reelease.tv/api/v1/me \
-H "Authorization: Bearer $REELEASE_TOKEN"{
"data": {
"id": 1,
"username": "josh",
"name": "Josh",
"timezone": "Europe/London",
"memberSince": "2026-01-04T18:02:11.000Z",
"tokenScopes": ["read"]
}
}The watch history (append-only plays, rewatches included), newest first. Paginated — limit caps at 100.
curl "https://reelease.tv/api/v1/history?page=1&limit=2" \
-H "Authorization: Bearer $REELEASE_TOKEN"{
"data": [
{
"id": 9214, "type": "episode",
"watchedAt": "2026-07-09T21:14:00.000Z", "source": "manual",
"show": { "id": 12, "tmdbId": 95396, "title": "Severance" },
"episode": { "id": 481, "tmdbId": 5361044, "season": 2, "number": 5, "title": "Trojan's Horse" }
},
{
"id": 9209, "type": "movie",
"watchedAt": "2026-07-08T20:00:00.000Z", "source": "manual",
"movie": { "id": 77, "tmdbId": 693134, "title": "Dune: Part Two", "year": "2024" }
}
],
"pagination": { "page": 1, "limit": 2, "total": 3120, "totalPages": 1560, "hasMore": true }
}Record a watch. Address it precisely ({ "type": "episode", "tmdbId": … }) or by exact title ({ "title": "Severance", "season": 2, "number": 5 } — case-insensitive; near-misses 404 with the closest candidates rather than guess). Optional ISO "watchedAt" backdates it. Same-day repeats dedupe — safe to retry. The response echoes what was recorded, so verify the match.
curl -X POST https://reelease.tv/api/v1/history \
-H "Authorization: Bearer $REELEASE_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "title": "Severance", "season": 2, "number": 5 }'{
"data": {
"status": "inserted", "watchEventId": 9215, "type": "episode",
"show": { "id": 12, "tmdbId": 95396, "title": "Severance" },
"episode": { "id": 481, "tmdbId": 5361044, "season": 2, "number": 5, "title": "Trojan's Horse" }
}
}Everything queued to watch, newest-added first.
Add a title: { "type": "show" | "movie", "tmdbId" } (or internal "id"). 201 on add, 200 if it was already there.
curl -X POST https://reelease.tv/api/v1/watchlist \
-H "Authorization: Bearer $REELEASE_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "type": "show", "tmdbId": 95396 }'Remove a title — same body as the POST. 404 if it wasn’t on the list.
All of your lists (private ones included — the token acts as you).
The titles on one of your lists, in list order (ranked lists include a rank).
Your current star ratings (0.5–5.0), newest first, paginated.
Per-show progress: episodes watched, your status (watching, on-hold, …) and the next aired, unwatched episode.
Fuzzy title search over the catalog. Returns Reelease ids for the other endpoints plus TMDB ids for stable external identity.
curl "https://reelease.tv/api/v1/search?q=severance" \
-H "Authorization: Bearer $REELEASE_TOKEN"The privacy part — because it’s Reelease
A token only ever sees the account that minted it — there is no endpoint for other people’s data, and /me deliberately omits your email. Tokens are hashed at rest, revocation is instant, and the Settings page shows when each token was last used. If a token leaks, revoke it and the app it powered goes dark mid-request.
A menu-bar up-next, a shell one-liner that checks you in, a Sunday digest — tracking, made reel easy, now programmable.
Create your first token