Search 4M+ subtitles matched to a TMDB-clean database, download season packs and single episodes, and translate any subtitle with AI in under 60 seconds.
Every title resolves to clean TMDB/IMDb ids — no fuzzy guessing.
Half a million titles indexed and ready to search.
One of the largest subtitle catalogs, across dozens of languages.
Cached, edge-fast search responses for snappy autocomplete.
The complete Subscene back-catalog, preserved and searchable.
Match titles by their localized and alternative names worldwide.
Pull a whole season in one call, or a single episode.
Look up titles and subtitles directly by IMDb id or URL.
Strong anime coverage with release-aware matching and tone presets.
Translate a full subtitle file into any language in under a minute.
Drop a messy release filename and get the right match.
Search and download work on a free key. AI translation, AI transcription, AI filename search, 30,000 requests/day and 2,000 downloads/day require SubDL Pro.
Upgrade to SubDL Pro
Authenticate every request with your API key in an
Authorization: Bearer
header (or X-API-Key).
The legacy ?api_key=
query is still accepted for download links. Base URL:
https://api.subdl.com
# Your first request
curl "https://api.subdl.com/api/v2/movies/search?q=dune" \
-H "Authorization: Bearer $SUBDL_API_KEY" /api/v2/movies/search Title search for autocomplete or a search page. Returns posters and matched ids (sd_id, imdb_id, tmdb_id).
q * Search query (min 2 chars). Accepts an IMDb id/url too. type Filter: movie or tv. limit Max results, 1–30 (default 10). Small values behave like autocomplete. curl "https://api.subdl.com/api/v2/movies/search?q=dune&type=movie&limit=5" \
-H "Authorization: Bearer $SUBDL_API_KEY" import requests
r = requests.get(
"https://api.subdl.com/api/v2/movies/search?q=dune&type=movie&limit=5",
headers={"Authorization": f"Bearer {SUBDL_API_KEY}"},
)
print(r.json()) const res = await fetch("https://api.subdl.com/api/v2/movies/search?q=dune&type=movie&limit=5", {
headers: { Authorization: `Bearer ${SUBDL_API_KEY}` },
});
const data = await res.json(); <?php
$ch = curl_init("https://api.subdl.com/api/v2/movies/search?q=dune&type=movie&limit=5");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . $SUBDL_API_KEY,
]);
$data = json_decode(curl_exec($ch), true); {
"results": [
{
"sd_id": "sd123456",
"type": "movie",
"name": "Dune: Part Two",
"original_name": "Dune: Part Two",
"year": 2024,
"imdb_id": "tt15239678",
"tmdb_id": 693134,
"poster_url": "https://.../poster.jpg",
"subtitles_count": 412,
"url": "https://subdl.com/subtitle/sd123456/dune-part-two"
}
]
} /api/v2/files/search Pass a release filename and get the matched title plus the subtitles that belong to that exact release — the right episode, ranked by how closely each subtitle's release name resembles your file. Ideal for media managers scanning a library. TV filenames are scoped to the parsed season and episode; pass episode_scope=title for the whole catalogue instead. Every subtitle carries a match_score from 0 to 1, so an auto-downloader can threshold on it (≥0.8 is a confident release match).
filename * The release filename, e.g. Dune.Part.Two.2024.2160p.BluRay.x265-GROUP.mkv engine auto (default), local, or ai. auto uses the AI parser when your plan includes it and falls back silently otherwise; ai returns 402 if you are not entitled. AI handles anime numbering, 1x05, and names with no year. episode_scope exact (default) scopes TV results to the parsed episode; title returns the whole title's subtitles. languages Comma-separated language codes, e.g. en,fa,ar. type movie or tv, to narrow title resolution. hi 1 for hearing-impaired only, 0 to exclude. subs_per_page Subtitles per page (max 30). curl "https://api.subdl.com/api/v2/files/search?filename=Breaking.Bad.S05E14.1080p.BluRay.x264-DEMAND.mkv&languages=en,fa" \
-H "Authorization: Bearer $SUBDL_API_KEY" import requests
r = requests.get(
"https://api.subdl.com/api/v2/files/search?filename=Breaking.Bad.S05E14.1080p.BluRay.x264-DEMAND.mkv&languages=en,fa",
headers={"Authorization": f"Bearer {SUBDL_API_KEY}"},
)
print(r.json()) const res = await fetch("https://api.subdl.com/api/v2/files/search?filename=Breaking.Bad.S05E14.1080p.BluRay.x264-DEMAND.mkv&languages=en,fa", {
headers: { Authorization: `Bearer ${SUBDL_API_KEY}` },
});
const data = await res.json(); <?php
$ch = curl_init("https://api.subdl.com/api/v2/files/search?filename=Breaking.Bad.S05E14.1080p.BluRay.x264-DEMAND.mkv&languages=en,fa");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . $SUBDL_API_KEY,
]);
$data = json_decode(curl_exec($ch), true); {
"status": true,
"results": [{ "sd_id": 1234, "type": "tv", "name": "Breaking Bad", "year": 2008, "imdb_id": "tt0903747" }],
"match": {
"engine": "local", "confidence": "high", "degraded": false,
"type": "tv", "title": "Breaking Bad", "year": 2008,
"season": 5, "episode": 14, "full_season": false,
"sd_id": 1234, "link": "/subtitle/sd1234/breaking-bad"
},
"alternates": [],
"subtitles": [
{ "release_name": "Breaking.Bad.S05E14.1080p.BluRay.x264-DEMAND", "lang": "english", "match_score": 0.92, "url": "..." }
]
} /api/v2/files/search Match up to 50 filenames in one round trip: the natural call for a library scan or a whole season folder. Filenames go in the body rather than the query string so they stay out of access logs, history and Referer headers. `files` always has one entry per input, in input order — a file that matched nothing gets match: null and an empty subtitle list, never a dropped entry — so results can be zipped by index. Each filename costs one unit against your daily search quota (50 filenames = 50 units).
filenames * JSON array of release filenames, 1-50 entries. engine auto (default), local, or ai — same semantics as the GET form. episode_scope exact (default) or title. languages Comma-separated language codes. subs_per_page Subtitles per page, per file (max 30). curl -X POST "https://api.subdl.comcurl -X POST https://api.subdl.com/api/v2/files/search \
-H "Authorization: Bearer YOUR_KEY" -H "Content-Type: application/json" \
-d '{"filenames":["Show.S01E01.1080p.WEB.mkv","Show.S01E02.1080p.WEB.mkv"],"languages":"en"}'" \
-H "Authorization: Bearer $SUBDL_API_KEY" \
-H "Content-Type: application/json" \
-d '' import requests
r = requests.post(
"https://api.subdl.comcurl -X POST https://api.subdl.com/api/v2/files/search \
-H "Authorization: Bearer YOUR_KEY" -H "Content-Type: application/json" \
-d '{"filenames":["Show.S01E01.1080p.WEB.mkv","Show.S01E02.1080p.WEB.mkv"],"languages":"en"}'",
headers={"Authorization": f"Bearer {SUBDL_API_KEY}"},
json=,
)
print(r.json()) const res = await fetch("https://api.subdl.comcurl -X POST https://api.subdl.com/api/v2/files/search \
-H "Authorization: Bearer YOUR_KEY" -H "Content-Type: application/json" \
-d '{"filenames":["Show.S01E01.1080p.WEB.mkv","Show.S01E02.1080p.WEB.mkv"],"languages":"en"}'", {
method: "POST",
headers: {
Authorization: `Bearer ${SUBDL_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify(),
});
const data = await res.json(); <?php
$ch = curl_init("https://api.subdl.comcurl -X POST https://api.subdl.com/api/v2/files/search \
-H "Authorization: Bearer YOUR_KEY" -H "Content-Type: application/json" \
-d '{"filenames":["Show.S01E01.1080p.WEB.mkv","Show.S01E02.1080p.WEB.mkv"],"languages":"en"}'");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, '');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . $SUBDL_API_KEY,
"Content-Type: application/json",
]);
$data = json_decode(curl_exec($ch), true); {
"status": true,
"engine": "ai",
"files": [
{ "file_name": "Show.S01E01.1080p.WEB.mkv", "match": { "...": "..." }, "alternates": [], "subtitles": [] },
{ "file_name": "Show.S01E02.1080p.WEB.mkv", "match": null, "alternates": [], "subtitles": [] }
]
} /api/v2/subtitles/search Fast exact subtitle search by id or title. Provide one of sd_id, imdb_id, tmdb_id, film_name, or file_name. Add unpack=1 to receive per-file (non-zip) download urls.
sd_id | imdb_id | tmdb_id * One title key. (Or film_name / file_name.) type movie or tv. Required when using tmdb_id — a TMDB id is only unique together with the media type. languages Comma-separated language codes. season / episode For TV. Use full_season=1 for a season pack. unpack 1 to expand archives into exact single-file download urls. curl "https://api.subdl.com/api/v2/subtitles/search?imdb_id=tt15239678&languages=en,fa" \
-H "Authorization: Bearer $SUBDL_API_KEY" import requests
r = requests.get(
"https://api.subdl.com/api/v2/subtitles/search?imdb_id=tt15239678&languages=en,fa",
headers={"Authorization": f"Bearer {SUBDL_API_KEY}"},
)
print(r.json()) const res = await fetch("https://api.subdl.com/api/v2/subtitles/search?imdb_id=tt15239678&languages=en,fa", {
headers: { Authorization: `Bearer ${SUBDL_API_KEY}` },
});
const data = await res.json(); <?php
$ch = curl_init("https://api.subdl.com/api/v2/subtitles/search?imdb_id=tt15239678&languages=en,fa");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . $SUBDL_API_KEY,
]);
$data = json_decode(curl_exec($ch), true); /api/v2/subtitles/{nId}/download Address a subtitle by its nId. format=zip (default) returns the archive; format=file returns the exact single (non-zip) file when the archive has one obvious file.
nId * Subtitle nId (from a search result). format zip (default) or file (exact non-zip file). curl "https://api.subdl.com/api/v2/subtitles/abcdef/download?format=file" \
-H "Authorization: Bearer $SUBDL_API_KEY" import requests
r = requests.get(
"https://api.subdl.com/api/v2/subtitles/abcdef/download?format=file",
headers={"Authorization": f"Bearer {SUBDL_API_KEY}"},
)
print(r.json()) const res = await fetch("https://api.subdl.com/api/v2/subtitles/abcdef/download?format=file", {
headers: { Authorization: `Bearer ${SUBDL_API_KEY}` },
});
const data = await res.json(); <?php
$ch = curl_init("https://api.subdl.com/api/v2/subtitles/abcdef/download?format=file");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . $SUBDL_API_KEY,
]);
$data = json_decode(curl_exec($ch), true); Translate an existing subtitle into any language with AI, typically in under 60 seconds. Returns a request_id; poll the job until download_ready.
n_id * Subtitle nId to translate. target_language * Target language code, e.g. FA. tone Optional: faithful, formal, casual, cinematic_action, comedic_fun, anime. curl -X POST "https://api.subdl.com/api/v2/ai/translations" \
-H "Authorization: Bearer $SUBDL_API_KEY" \
-H "Content-Type: application/json" \
-d '{"n_id":"abcdef","target_language":"FA","tone":"faithful"}' import requests
r = requests.post(
"https://api.subdl.com/api/v2/ai/translations",
headers={"Authorization": f"Bearer {SUBDL_API_KEY}"},
json={
"n_id": "abcdef",
"target_language": "FA",
"tone": "faithful"
},
)
print(r.json()) const res = await fetch("https://api.subdl.com/api/v2/ai/translations", {
method: "POST",
headers: {
Authorization: `Bearer ${SUBDL_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"n_id":"abcdef","target_language":"FA","tone":"faithful"}),
});
const data = await res.json(); <?php
$ch = curl_init("https://api.subdl.com/api/v2/ai/translations");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{"n_id":"abcdef","target_language":"FA","tone":"faithful"}');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . $SUBDL_API_KEY,
"Content-Type: application/json",
]);
$data = json_decode(curl_exec($ch), true); List your translation jobs with their status and progress.
curl "https://api.subdl.com/api/v2/ai/translations?page=1" \
-H "Authorization: Bearer $SUBDL_API_KEY" import requests
r = requests.get(
"https://api.subdl.com/api/v2/ai/translations?page=1",
headers={"Authorization": f"Bearer {SUBDL_API_KEY}"},
)
print(r.json()) const res = await fetch("https://api.subdl.com/api/v2/ai/translations?page=1", {
headers: { Authorization: `Bearer ${SUBDL_API_KEY}` },
});
const data = await res.json(); <?php
$ch = curl_init("https://api.subdl.com/api/v2/ai/translations?page=1");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . $SUBDL_API_KEY,
]);
$data = json_decode(curl_exec($ch), true); Poll a single job for progress, ETA, and download_ready.
curl "https://api.subdl.com/api/v2/ai/translations/req_123" \
-H "Authorization: Bearer $SUBDL_API_KEY" import requests
r = requests.get(
"https://api.subdl.com/api/v2/ai/translations/req_123",
headers={"Authorization": f"Bearer {SUBDL_API_KEY}"},
)
print(r.json()) const res = await fetch("https://api.subdl.com/api/v2/ai/translations/req_123", {
headers: { Authorization: `Bearer ${SUBDL_API_KEY}` },
});
const data = await res.json(); <?php
$ch = curl_init("https://api.subdl.com/api/v2/ai/translations/req_123");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . $SUBDL_API_KEY,
]);
$data = json_decode(curl_exec($ch), true); Generate subtitles from a media file with speech-to-text. In beta — shape may change.
curl -X POST "https://api.subdl.com/api/v2/ai/transcriptions" \
-H "Authorization: Bearer $SUBDL_API_KEY" \
-H "Content-Type: application/json" \
-d '{"media_url":"https://.../episode.mp3","language":"en"}' import requests
r = requests.post(
"https://api.subdl.com/api/v2/ai/transcriptions",
headers={"Authorization": f"Bearer {SUBDL_API_KEY}"},
json={
"media_url": "https://.../episode.mp3",
"language": "en"
},
)
print(r.json()) const res = await fetch("https://api.subdl.com/api/v2/ai/transcriptions", {
method: "POST",
headers: {
Authorization: `Bearer ${SUBDL_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"media_url":"https://.../episode.mp3","language":"en"}),
});
const data = await res.json(); <?php
$ch = curl_init("https://api.subdl.com/api/v2/ai/transcriptions");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{"media_url":"https://.../episode.mp3","language":"en"}');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . $SUBDL_API_KEY,
"Content-Type: application/json",
]);
$data = json_decode(curl_exec($ch), true); Use AI to resolve a messy or ambiguous release filename to the best TMDB match. In beta.
curl "https://api.subdl.com/api/v2/ai/filename-search?filename=that.movie.2021.WEBRip.mkv" \
-H "Authorization: Bearer $SUBDL_API_KEY" import requests
r = requests.get(
"https://api.subdl.com/api/v2/ai/filename-search?filename=that.movie.2021.WEBRip.mkv",
headers={"Authorization": f"Bearer {SUBDL_API_KEY}"},
)
print(r.json()) const res = await fetch("https://api.subdl.com/api/v2/ai/filename-search?filename=that.movie.2021.WEBRip.mkv", {
headers: { Authorization: `Bearer ${SUBDL_API_KEY}` },
});
const data = await res.json(); <?php
$ch = curl_init("https://api.subdl.com/api/v2/ai/filename-search?filename=that.movie.2021.WEBRip.mkv");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . $SUBDL_API_KEY,
]);
$data = json_decode(curl_exec($ch), true); /api/v2/me Your plan plus separated counters (search/day, downloads/day, AI/month) with reset times. Does not count against your search quota.
curl "https://api.subdl.com/api/v2/me" \
-H "Authorization: Bearer $SUBDL_API_KEY" import requests
r = requests.get(
"https://api.subdl.com/api/v2/me",
headers={"Authorization": f"Bearer {SUBDL_API_KEY}"},
)
print(r.json()) const res = await fetch("https://api.subdl.com/api/v2/me", {
headers: { Authorization: `Bearer ${SUBDL_API_KEY}` },
});
const data = await res.json(); <?php
$ch = curl_init("https://api.subdl.com/api/v2/me");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . $SUBDL_API_KEY,
]);
$data = json_decode(curl_exec($ch), true); {
"plan": { "is_pro": false, "name": "Free" },
"usage": {
"search": { "used": 12, "limit": 2000, "remaining": 1988, "period": "day" },
"downloads": { "used": 3, "limit": 50, "remaining": 47, "period": "day" },
"ai": {
"translations": { "eligible": false, "free_trial_per_month": 1, "period": "month" }
}
},
"upgrade_url": "https://subdl.com/pro"
}
Every response includes X-RateLimit-Limit,
X-RateLimit-Remaining, and
X-RateLimit-Reset. Errors share one shape:
{
"error": {
"code": "quota_exceeded",
"message": "Daily request quota exceeded.",
"docs_url": "https://subdl.com/developers#errors"
}
} | Tier | Search / day | Downloads / day | AI |
|---|---|---|---|
| Free | 2,000 | 50 | 1 free trial / feature / month |
| SubDL Pro | 30,000 | 2,000 | 60 translations / month |
Create a free SubDL account, open your panel, and generate an API key from the API section. The free tier includes 2,000 searches and 50 downloads per day.
Yes. The free tier allows 2,000 searches and 50 downloads per day. SubDL Pro raises this to 30,000 searches and 2,000 downloads per day, plus AI subtitle translation.
Search 4M+ subtitles across 500K+ TMDB-matched movies and TV shows, download SRT files, and use AI subtitle translation — ideal for media players, Bazarr-style tools, and apps.