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
| Parameter | In | Required | Description |
|---|---|---|---|
query | query | yes | Text to search. URL-encode it: spaces become %20 or +. |
api_key | query | one of two | Your key. Use this or the Authorization: Bearer header. |
year | query | no | Four digit year. Keeps movies with any release date in that year, in any country. |
primary_release_year | query | no | Four digit year. Matches the primary release date only, so it can return fewer titles than year. |
region | query | no | Uppercase 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_adult | query | no | Accepted and ignored. Adult titles are never returned. |
language | query | no | TMDB tag such as en-US or it-IT. 14 base languages are served, anything else falls back to English. Default en-US. |
page | query | no | Page number from 1 to 500. Default 1. |
Response fields
| Field | Type | Notes |
|---|---|---|
page | integer | The page you asked for. |
results | array | Up to 20 entries, best match first. |
total_pages, total_results | integer | Size of the result set for this query. Capped at 500 pages and 10000 results. |
id | integer | Movie id for the details endpoint. |
title, original_title | string | Localized and original title. |
original_language | string | Two letter code of the language the movie was made in. |
overview | string | Localized text, empty when no translation exists. |
release_date | string | YYYY-MM-DD, empty for titles without a date. |
genre_ids | array of integers | Genre ids, not names. Map them with genres. |
poster_path, backdrop_path | string or null | Append to https://img.amodb.dev/t/p/{size}. |
popularity, vote_average, vote_count | number | Ranking and score values. |
adult, video | boolean | adult is always false. video is true for entries flagged as video content. |
Example response
{
"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 path | Finds | Extra parameters | Entry fields |
|---|---|---|---|
GET /search/tv | TV shows | first_air_date_year, year, language | name, original_name, first_air_date, origin_country |
GET /search/person | People | language | name, original_name, known_for_department, gender, profile_path, known_for |
GET /search/multi | Movies, shows and people together | language | media_type plus the fields of that type |
GET /search/collection | Movie collections | language | name, original_name, overview, poster_path, backdrop_path |
GET /search/company | Production companies | none | name, logo_path, origin_country |
GET /search/keyword | Keywords | none | id, 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.
Multi search
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.
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.
| HTTP | status_code | When |
|---|---|---|
| 401 | 7 | The key is missing or wrong. |
| 402 | 36 | The plan period has ended. |
| 405 | 37 | You called a write method. |
| 429 | 25 | Over your requests per minute. Wait for the Retry-After seconds. |
| 500 | 11 | A movie, multi, keyword, company or collection query that matches nothing, or a page outside 1 to 500. |
| 504 | 24 | The 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/keywordfeeds thewith_keywordsfilter on discover, and a company id feedswith_companies.