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

ParameterInRequiredDescription
series_idpathyesNumeric TV id, for example 1396.
api_keyqueryone of twoYour key. Use this or the Authorization: Bearer header.
languagequerynoTMDB tag such as en-US, uk-UA or es-ES. 14 base languages are served. Default en-US.
append_to_responsequerynoComma separated list of sub-resources to merge into the reply, up to 20 values.

Response fields

FieldTypeNotes
idintegerTV id.
name, original_namestringLocalized and original title. Original names in Japanese or Korean stay in original_name.
overview, taglinestringLocalized text, empty when no translation exists.
first_air_date, last_air_datestring or nullYYYY-MM-DD.
statusstringLifecycle, see the table below.
in_productionbooleantrue while the show is still being made.
number_of_seasons, number_of_episodesintegerTotals, as stored for the show.
episode_run_timearrayTypical episode lengths in minutes, may be empty.
seasonsarrayOne summary per season with id, season_number, name, overview, episode_count, air_date, poster_path, vote_average.
last_episode_to_air, next_episode_to_airobject or nullEpisode summaries, shaped like the objects on seasons and episodes.
networks, production_companiesarrayid, name, logo_path, origin_country.
production_countries, spoken_languagesarrayCountries with iso_3166_1 and name. Languages with english_name, iso_639_1 and name.
created_byarrayCreators with id, name, profile_path and credit_id. Empty for most series.
genresarrayObjects with id and name. TV genre ids differ from movie ids.
origin_country, original_language, languagesarray, stringCountry codes and language codes.
homepagestringOfficial site, empty when unknown.
poster_path, backdrop_pathstring or nullAppend to https://img.amodb.dev/t/p/{size}. See images.
popularitynumberRelative score used by the popular list.
vote_average, vote_countnumber, integerAggregate user score.
adultbooleanAlways 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:

JSON
{
  "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 valueMeaningnext_episode_to_air
Returning SeriesAiring now or between seasons.Set when a date is known, otherwise null.
Planned, In ProductionNot yet a regular series.Usually null.
EndedFinished its run.Null.
CanceledStopped 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.

All paths share the base https://api.amodb.dev/3, and endpoints with localized text also take language.

Method and pathReturnsExtra parameters
GET /tv/{series_id}/alternative_titles{id, results} with iso_3166_1, title, type, often emptynone
GET /tv/{series_id}/content_ratingsAge rating per countrynone
GET /tv/{series_id}/episode_groupsList of alternative episode orderings such as DVD or story arcnone
GET /tv/{series_id}/recommendationsA list of 20 recommended showsnone
GET /tv/{series_id}/similarA list of 20 similar showsnone
GET /tv/{series_id}/reviewsresults is empty for most seriesnone
GET /tv/{series_id}/listsPublic lists that contain the showpage
GET /tv/{series_id}/watch/providersStreaming, rental and purchase providers per countrynone
GET /tv/latestThe newest series record addednone

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:

ValueAddsDetails
creditsCast and crewCredits
external_idsIds such as imdb_id, tvdb_id and wikidata_idFind by external id
images, videosPosters, backdrops, trailersImages, Videos
keywords, translationsTags and translated textsKeywords, Translations
content_ratings, alternative_titles, episode_groups, lists, watch/providers, similar, recommendations, reviewsThe sub-resources in the table aboveThis page
ratings, moods, soundtracks, wikidata, showtimesamodb extrasRatings, 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."

HTTPstatus_codeWhen
4017The key is missing or wrong.
40236The plan period has ended.
40434No series with that id, an adult title, or a path that is not offered.
40537You called a write method such as rating a show.
42925Over 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_air no more than a few times a day.
  • Request the language you display. An empty overview means no translation exists, so re-request with en-US for a fallback.
  • Use number_of_seasons as 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.