Search API

The search endpoints turn a text query into ids. GET /3/search/movie finds movies, and sibling paths find TV shows, people, collections, companies and keywords, or all media at once with multi. The JSON matches TMDB v3, results are paged at 20 per page, and the edge caches a query for 10 minutes.

Search movies

GET /3/search/movie takes a text query and returns a paged list of matching movies, best match first. Use it to turn what a user typed into a movie id, then call movie details with that id.

The example looks for Inception, restricted to 2010, and prints id, title and release date.

curl -sSf --get "https://api.amodb.dev/3/search/movie" \
  --data-urlencode "query=inception" \
  --data-urlencode "year=2010" \
  -H "Authorization: Bearer $AMODB_KEY"
const params = new URLSearchParams({ query: 'inception', year: '2010', language: 'en-US' });
const res = await fetch(`https://api.amodb.dev/3/search/movie?${params}`, {
  headers: { Authorization: `Bearer ${process.env.AMODB_KEY}` },
});
if (!res.ok) throw new Error(`amodb returned ${res.status}`);
const { results, total_results } = await res.json();
console.log(`${total_results} matches`);
for (const m of results.slice(0, 5)) console.log(m.id, m.title, m.release_date);
import os
import requests

r = requests.get(
    "https://api.amodb.dev/3/search/movie",
    params={"query": "inception", "year": 2010, "language": "en-US"},
    headers={"Authorization": f"Bearer {os.environ['AMODB_KEY']}"},
    timeout=10,
)
r.raise_for_status()
data = r.json()
print(data["total_results"], "matches")
for m in data["results"][:5]:
    print(m["id"], m["title"], m["release_date"])
<?php
$url = 'https://api.amodb.dev/3/search/movie?' . http_build_query([
    'query' => 'inception',
    'year' => 2010,
    'language' => 'en-US',
]);
$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");
}
$data = json_decode($body, true);
foreach (array_slice($data['results'], 0, 5) as $m) {
    echo $m['id'], ' ', $m['title'], ' ', $m['release_date'], PHP_EOL;
}
package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"os"
	"time"
)

type SearchPage struct {
	TotalResults int `json:"total_results"`
	Results      []struct {
		ID          int    `json:"id"`
		Title       string `json:"title"`
		ReleaseDate string `json:"release_date"`
	} `json:"results"`
}

func main() {
	q := url.Values{"query": {"inception"}, "year": {"2010"}, "language": {"en-US"}}
	req, _ := http.NewRequest("GET", "https://api.amodb.dev/3/search/movie?"+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 p SearchPage
	if err := json.NewDecoder(res.Body).Decode(&p); err != nil {
		panic(err)
	}
	fmt.Println(p.TotalResults, "matches")
	for _, m := range p.Results {
		fmt.Println(m.ID, m.Title, m.ReleaseDate)
	}
}

Parameters

ParameterInRequiredDescription
queryqueryyesText to search. URL-encode it: spaces become %20 or +.
api_keyqueryone of twoYour key. Use this or the Authorization: Bearer header.
yearquerynoFour digit year. Keeps movies with any release date in that year, in any country.
primary_release_yearquerynoFour digit year. Matches the primary release date only, so it can return fewer titles than year.
regionquerynoUppercase 2 letter country code such as US. Replaces release_date with the date in that country when one is known. It does not remove titles.
include_adultquerynoAccepted and ignored. Adult titles are never returned.
languagequerynoTMDB tag such as en-US or it-IT. 14 base languages are served, anything else falls back to English. Default en-US.
pagequerynoPage number from 1 to 500. Default 1.

Response fields

FieldTypeNotes
pageintegerThe page you asked for.
resultsarrayUp to 20 entries, best match first.
total_pages, total_resultsintegerSize of the result set for this query. Capped at 500 pages and 10000 results.
idintegerMovie id for the details endpoint.
title, original_titlestringLocalized and original title.
original_languagestringTwo letter code of the language the movie was made in.
overviewstringLocalized text, empty when no translation exists.
release_datestringYYYY-MM-DD, empty for titles without a date.
genre_idsarray of integersGenre ids, not names. Map them with genres.
poster_path, backdrop_pathstring or nullAppend to https://img.amodb.dev/t/p/{size}.
popularity, vote_average, vote_countnumberRanking and score values.
adult, videobooleanadult is always false. video is true for entries flagged as video content.

Example response

JSON
{
  "page": 1,
  "results": [
    {
      "adult": false,
      "backdrop_path": "/zSBVQIvx4UIHoFf1oDvixHyIQrz.jpg",
      "genre_ids": [28, 878, 80],
      "id": 27205,
      "original_language": "en",
      "original_title": "Inception",
      "overview": "Cobb, a skilled thief who commits corporate espionage by infiltrating the subconscious of his targets is of...",
      "popularity": 60.9811,
      "poster_path": "/xlaY2zyzMfkhk0HSC5VUwzoZPU1.jpg",
      "release_date": "2010-07-15",
      "title": "Inception",
      "video": false,
      "vote_average": 8.373,
      "vote_count": 40459
    },
    {
      "adult": false,
      "backdrop_path": "/p8K8Z4yjaslJx5mTsIC5L6LJxQB.jpg",
      "genre_ids": [16, 28, 53],
      "id": 64956,
      "original_language": "en",
      "original_title": "Inception: The Cobol Job",
      "overview": "Cobb, Arthur and Nash are enlisted by Cobol Engineering.",
      "popularity": 1.9401,
      "poster_path": "/sNxqwtyHMNQwKWoFYDqcYTui5Ok.jpg",
      "release_date": "2010-12-07",
      "title": "Inception: The Cobol Job",
      "video": false,
      "vote_average": 7.2,
      "vote_count": 320
    },
    {
      "adult": false,
      "backdrop_path": null,
      "genre_ids": [10402],
      "id": 973484,
      "original_language": "en",
      "original_title": "Inception: Music from the Motion Picture",
      "overview": "The Special Features Blu-ray disc contains a lossless DTS-HD MA 5.1 surround mix of the Inception soundtrack.",
      "popularity": 0.4911,
      "poster_path": "/7uM4DyRVAcgagvhZoWrkrqMPbqV.jpg",
      "release_date": "2010-12-07",
      "title": "Inception: Music from the Motion Picture",
      "video": true,
      "vote_average": 7,
      "vote_count": 3
    }
  ],
  "total_pages": 1,
  "total_results": 3
}

The reply has all three matches. It was fetched from the live API and only long overview strings were shortened.

Other search endpoints

Every path below shares the base https://api.amodb.dev/3, needs query, and returns the same page, results, total_pages and total_results envelope. Each one also takes page from 1 to 500. include_adult is accepted on all of them and ignored.

Method and pathFindsExtra parametersEntry fields
GET /search/tvTV showsfirst_air_date_year, year, languagename, original_name, first_air_date, origin_country
GET /search/personPeoplelanguagename, original_name, known_for_department, gender, profile_path, known_for
GET /search/multiMovies, shows and people togetherlanguagemedia_type plus the fields of that type
GET /search/collectionMovie collectionslanguagename, original_name, overview, poster_path, backdrop_path
GET /search/companyProduction companiesnonename, logo_path, origin_country
GET /search/keywordKeywordsnoneid, name

For TV, first_air_date_year keeps shows whose first air date is in that year, while year also keeps older shows that aired in that year. A search for the with year=2010 returns The Simpsons, which first aired in 1989, and the same search with first_air_date_year=2010 does not. If you send both, both must match. Person entries carry up to 3 known_for titles, each with media_type. /search/multi ignores year.

Entities found here continue on TV series, people, collections, companies and networks and keywords.

media_type is movie, tv or person, and it tells you which fields to expect. Movie entries carry title and TV and person entries carry name.

JavaScript
const byType = { movie: [], tv: [], person: [] };
for (const r of results) byType[r.media_type]?.push(r.title || r.name);
console.log(byType);

Errors

/search/tv and /search/person answer a query with no match with HTTP 200, an empty results array and total_results of 0. At the moment /search/movie, /search/multi, /search/keyword, /search/company and /search/collection answer the same case with HTTP 500 and status_code 11. Treat a 500 on those paths as "no results" unless it repeats for queries that you know match.

HTTPstatus_codeWhen
4017The key is missing or wrong.
40236The plan period has ended.
40537You called a write method.
42925Over your requests per minute. Wait for the Retry-After seconds.
50011A movie, multi, keyword, company or collection query that matches nothing, or a page outside 1 to 500.
50424The backend did not answer in time. Retry once.

See errors for the full list and rate limits for the windows.

Practical notes

  • The edge caches a search for 10 minutes and shares the copy across keys. Each call still counts against your 20, 40 or 120 requests per minute, because the rate limit runs before the cache.
  • For a search box, wait 300 ms after the last keystroke and cancel the request in flight. A box that fires on every key can use a 20 requests per minute plan in seconds.
  • Lowercase and trim the query before you use it as a cache key on your side.
  • To look up a title by IMDb id, skip search and use find by external id.
  • A keyword id from /search/keyword feeds the with_keywords filter on discover, and a company id feeds with_companies.