TV series API
The TV series endpoint returns one show by id at GET /3/tv/{series_id}: names, overview, status, seasons, networks, genres and pointers to the last and next episode. The JSON matches TMDB v3, so existing clients only need a new base URL. Add append_to_response to merge content ratings, credits and ratings into one request.
Get TV series details
GET /3/tv/{series_id} returns the core record for one show: names, overview, status, genres, networks, the list of seasons and pointers to the last and next episode. The id is the numeric TMDB tv id, so a show you store as 1396 keeps that id here. Movie ids and TV ids are separate spaces, so always store the media type next to the number.
The example asks for Breaking Bad in English and appends its content ratings and external scores in the same call.
curl -sSf "https://api.amodb.dev/3/tv/1396?language=en-US&append_to_response=content_ratings,ratings" \
-H "Authorization: Bearer $AMODB_KEY"const params = new URLSearchParams({ language: 'en-US', append_to_response: 'content_ratings,ratings' });
const res = await fetch(`https://api.amodb.dev/3/tv/1396?${params}`, {
headers: { Authorization: `Bearer ${process.env.AMODB_KEY}` },
});
if (!res.ok) throw new Error(`amodb returned ${res.status}`);
const show = await res.json();
const us = show.content_ratings.results.find((r) => r.iso_3166_1 === 'US');
console.log(show.name, show.status, show.number_of_seasons, us?.rating);import os
import requests
r = requests.get(
"https://api.amodb.dev/3/tv/1396",
params={"language": "en-US", "append_to_response": "content_ratings,ratings"},
headers={"Authorization": f"Bearer {os.environ['AMODB_KEY']}"},
timeout=10,
)
r.raise_for_status()
show = r.json()
us = next((x for x in show["content_ratings"]["results"] if x["iso_3166_1"] == "US"), None)
print(show["name"], show["status"], show["number_of_seasons"], us and us["rating"])<?php
$url = 'https://api.amodb.dev/3/tv/1396?' . http_build_query([
'language' => 'en-US',
'append_to_response' => 'content_ratings,ratings',
]);
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('AMODB_KEY')],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($status !== 200) {
throw new RuntimeException("amodb returned $status");
}
$show = json_decode($body, true);
echo $show['name'], ' ', $show['status'], ' ', $show['number_of_seasons'], PHP_EOL;package main
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"os"
"time"
)
type Show struct {
Name string `json:"name"`
Status string `json:"status"`
NumberOfSeasons int `json:"number_of_seasons"`
NumberOfEpisodes int `json:"number_of_episodes"`
Next *struct {
AirDate string `json:"air_date"`
} `json:"next_episode_to_air"`
}
func main() {
q := url.Values{"language": {"en-US"}}
req, _ := http.NewRequest("GET", "https://api.amodb.dev/3/tv/1396?"+q.Encode(), nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("AMODB_KEY"))
client := &http.Client{Timeout: 10 * time.Second}
res, err := client.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
panic(res.Status)
}
var s Show
if err := json.NewDecoder(res.Body).Decode(&s); err != nil {
panic(err)
}
next := "none scheduled"
if s.Next != nil {
next = s.Next.AirDate
}
fmt.Println(s.Name, s.Status, s.NumberOfSeasons, s.NumberOfEpisodes, next)
}Parameters
| Parameter | In | Required | Description |
|---|---|---|---|
series_id | path | yes | Numeric TV id, for example 1396. |
api_key | query | one of two | Your key. Use this or the Authorization: Bearer header. |
language | query | no | TMDB tag such as en-US, uk-UA or es-ES. 14 base languages are served. Default en-US. |
append_to_response | query | no | Comma separated list of sub-resources to merge into the reply, up to 20 values. |
Response fields
| Field | Type | Notes |
|---|---|---|
id | integer | TV id. |
name, original_name | string | Localized and original title. Original names in Japanese or Korean stay in original_name. |
overview, tagline | string | Localized text, empty when no translation exists. |
first_air_date, last_air_date | string or null | YYYY-MM-DD. |
status | string | Lifecycle, see the table below. |
in_production | boolean | true while the show is still being made. |
number_of_seasons, number_of_episodes | integer | Totals, as stored for the show. |
episode_run_time | array | Typical episode lengths in minutes, may be empty. |
seasons | array | One summary per season with id, season_number, name, overview, episode_count, air_date, poster_path, vote_average. |
last_episode_to_air, next_episode_to_air | object or null | Episode summaries, shaped like the objects on seasons and episodes. |
networks, production_companies | array | id, name, logo_path, origin_country. |
production_countries, spoken_languages | array | Countries with iso_3166_1 and name. Languages with english_name, iso_639_1 and name. |
created_by | array | Creators with id, name, profile_path and credit_id. Empty for most series. |
genres | array | Objects with id and name. TV genre ids differ from movie ids. |
origin_country, original_language, languages | array, string | Country codes and language codes. |
homepage | string | Official site, empty when unknown. |
poster_path, backdrop_path | string or null | Append to https://img.amodb.dev/t/p/{size}. See images. |
popularity | number | Relative score used by the popular list. |
vote_average, vote_count | number, integer | Aggregate user score. |
adult | boolean | Always false. Adult titles are never served. |
Example response
GET /3/tv/1396?language=en-US&append_to_response=content_ratings,ratings, with long arrays and text shortened:
{
"adult": false,
"backdrop_path": "/ycFcYYnzVc8mWw41neszGPMyKc3.jpg",
"created_by": [],
"episode_run_time": [
48,
49
],
"first_air_date": "2008-01-20",
"genres": [
{
"id": 18,
"name": "Drama"
},
{
"id": 80,
"name": "Crime"
}
],
"homepage": "",
"id": 1396,
"in_production": false,
"languages": [
"en"
],
"last_air_date": "2013-09-29",
"last_episode_to_air": {
"air_date": "2013-09-29",
"episode_number": 16,
"episode_type": "standard",
"id": 62161,
"name": "פלינה",
"overview": "הסדרה זוכת הפרסים מגיעה לסיום דרמתי בפרק החותם אותה.",
"production_code": "",
"runtime": 56,
"season_number": 5,
"show_id": 1396,
"still_path": "/pA0YwyhvdDXP3BEGL2grrIhq8aM.jpg",
"vote_average": 0,
"vote_count": 0
},
"name": "Breaking Bad",
"next_episode_to_air": null,
"networks": [
{
"id": 174,
"logo_path": "/pmvRmATOCaDykE6JrVoeYxlFHw3.png",
"name": "AMC",
"origin_country": "US"
}
],
"number_of_episodes": 62,
"number_of_seasons": 5,
"origin_country": [
"US"
],
"original_language": "en",
"original_name": "Breaking Bad",
"overview": "Walter White, a New Mexico chemistry teacher, is diagnosed with Stage III cancer and given a prognosis of o...",
"popularity": 268.4968,
"poster_path": "/anFx9aTOOYqgS3v7x3R84Kz67ly.jpg",
"production_companies": [
{
"id": 2605,
"logo_path": null,
"name": "Gran Via Productions",
"origin_country": "US"
},
{
"id": 11073,
"logo_path": "/wHs44fktdoj6c378ZbSWfzKsM2Z.png",
"name": "Sony Pictures Television",
"origin_country": "US"
}
],
"production_countries": [
{
"iso_3166_1": "US",
"name": "United States of America"
}
],
"seasons": [
{
"air_date": "2009-02-17",
"episode_count": 9,
"id": 3577,
"name": "特别篇",
"overview": "",
"poster_path": "/ikBSCmgG5Z4jequUUAjKpf1QG3T.jpg",
"season_number": 0,
"vote_average": 0
},
{
"air_date": "2008-01-20",
"episode_count": 7,
"id": 3572,
"name": "Season 1",
"overview": "High school chemistry teacher Walter White's life is suddenly transformed by a dire medical diagnosis. Stre...",
"poster_path": "/91EIXdWxmp2mHNRsSuDW3WyDJLj.jpg",
"season_number": 1,
"vote_average": 0
}
],
"spoken_languages": [
{
"english_name": "English",
"iso_639_1": "en",
"name": "English"
},
{
"english_name": "Spanish",
"iso_639_1": "es",
"name": "Español"
}
],
"status": "Ended",
"tagline": "Change the equation.",
"vote_average": 9,
"vote_count": 18863,
"content_ratings": {
"results": [
{
"descriptors": [],
"iso_3166_1": "AT",
"rating": "16"
},
{
"descriptors": [],
"iso_3166_1": "AU",
"rating": "MA 15+"
}
]
},
"ratings": {
"imdb": {
"value": 9.5,
"votes": 2671962
},
"kinopoisk": {
"value": 8.9,
"votes": null
},
"metacritic": null,
"rotten_tomatoes": {
"value": 96,
"votes": null
},
"tmdb": {
"value": 9,
"votes": 18863
}
}
}The content_ratings and ratings blocks come from append_to_response. Names and overviews inside seasons, last_episode_to_air and next_episode_to_air are stored per record and may not follow language, as the Hebrew episode name above shows. Read localized season and episode text from the season endpoint.
Status and episode pointers
status tells you where a show is in its life, and next_episode_to_air tells you when to look again.
status value | Meaning | next_episode_to_air |
|---|---|---|
Returning Series | Airing now or between seasons. | Set when a date is known, otherwise null. |
Planned, In Production | Not yet a regular series. | Usually null. |
Ended | Finished its run. | Null. |
Canceled | Stopped before a planned end. | Null. |
A returning series between seasons has a null next_episode_to_air, so read null as "no date known" and not as "finished".
The seasons array lists one summary per season, and season 0 holds specials. To read the episodes of a season, call the endpoint on seasons and episodes.
Related series endpoints
All paths share the base https://api.amodb.dev/3, and endpoints with localized text also take language.
| Method and path | Returns | Extra parameters |
|---|---|---|
GET /tv/{series_id}/alternative_titles | {id, results} with iso_3166_1, title, type, often empty | none |
GET /tv/{series_id}/content_ratings | Age rating per country | none |
GET /tv/{series_id}/episode_groups | List of alternative episode orderings such as DVD or story arc | none |
GET /tv/{series_id}/recommendations | A list of 20 recommended shows | none |
GET /tv/{series_id}/similar | A list of 20 similar shows | none |
GET /tv/{series_id}/reviews | results is empty for most series | none |
GET /tv/{series_id}/lists | Public lists that contain the show | page |
GET /tv/{series_id}/watch/providers | Streaming, rental and purchase providers per country | none |
GET /tv/latest | The newest series record added | none |
The recommendations and similar lists always return page 1 with 20 items. The lists reply is paged with page, 20 lists per page. Paged lists elsewhere on the API take page from 1 to 500.
Content ratings come back as results entries with iso_3166_1, rating and descriptors, so pick the entry that matches the viewer's country. Watch providers are keyed by country code, and each country holds a link plus flatrate, rent and buy lists with provider_id, provider_name, logo_path and display_priority. Provider ids for filtering come from the lookup lists on genres and lookup lists.
The episode groups list returns id (a string), name, description, type, episode_count, group_count and network. amodb lists the groups but does not offer an endpoint that returns the episodes of one group. It also does not offer the TMDB changes paths.
Merge more data into one call
List sub-resources in append_to_response and each arrives under its own key. The whole call counts once against your 20, 40 or 120 requests per minute. Up to 20 values work, and unknown names are ignored without an error. These values work on a series:
| Value | Adds | Details |
|---|---|---|
credits | Cast and crew | Credits |
external_ids | Ids such as imdb_id, tvdb_id and wikidata_id | Find by external id |
images, videos | Posters, backdrops, trailers | Images, Videos |
keywords, translations | Tags and translated texts | Keywords, Translations |
content_ratings, alternative_titles, episode_groups, lists, watch/providers, similar, recommendations, reviews | The sub-resources in the table above | This page |
ratings, moods, soundtracks, wikidata, showtimes | amodb extras | Ratings, Moods, Soundtracks, Showtimes |
Errors
A failed call returns the TMDB error body. A wrong id gives status_code 34 with the message "The resource you requested could not be found."
| HTTP | status_code | When |
|---|---|---|
| 401 | 7 | The key is missing or wrong. |
| 402 | 36 | The plan period has ended. |
| 404 | 34 | No series with that id, an adult title, or a path that is not offered. |
| 405 | 37 | You called a write method such as rating a show. |
| 429 | 25 | Over your requests per minute. Wait for the Retry-After seconds. |
The full list is on errors, and limits per plan are on rate limits.
Practical notes
- Series details and every sub-resource above are cached for 6 hours. Poll
last_episode_to_airno more than a few times a day. - Request the language you display. An empty
overviewmeans no translation exists, so re-request withen-USfor a fallback. - Use
number_of_seasonsas the loop bound when you fetch every season, one call each. - To list shows instead of reading one, see search, discover and trending and lists.