# 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.

## Endpoint

`GET /3/search/movie`

```bash
curl "https://api.amodb.dev/3/search/movie?query=inception&year=2010" \
  -H "Authorization: Bearer $AMODB_KEY"
```

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 offered a chance to regain his old life as payment for a task considered to be impossible: \"inception\", the implantation of another per...",
      "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
}
```

## 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](https://amodb.dev/movies/) with that id.

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

```bash
curl -sSf --get "https://api.amodb.dev/3/search/movie" \
  --data-urlencode "query=inception" \
  --data-urlencode "year=2010" \
  -H "Authorization: Bearer $AMODB_KEY"
```

```js
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);
```

```python
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
<?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;
}
```

```go
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](https://amodb.dev/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

```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 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](https://amodb.dev/tv-series/), [people](https://amodb.dev/people/), [collections](https://amodb.dev/collections/), [companies and networks](https://amodb.dev/companies-networks/) and [keywords](https://amodb.dev/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`.

```js
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](https://amodb.dev/errors/) for the full list and [rate limits](https://amodb.dev/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](https://amodb.dev/find-by-external-id/).
- A keyword id from `/search/keyword` feeds the `with_keywords` filter on [discover](https://amodb.dev/discover/), and a company id feeds `with_companies`.

## Questions and answers

### How many results does one search page return?

Each page holds 20 results, and the page parameter runs from 1 to 500. Read total_pages and total_results from the reply, and narrow vague queries with year or primary_release_year.

### Do cached searches still count against my rate limit?

Yes. The edge caches a search for 10 minutes and shares that copy across keys, but the key check and the rate limit run before the cache lookup, so every call counts once.

### Can I search by IMDb id with these endpoints?

No. Use GET /3/find/{external_id} with external_source=imdb_id instead. It returns movie_results, tv_results and person_results for that id, and it is described on the find by external id page.

### What language are the results in?

The language parameter sets titles and overviews, default en-US. Tags outside the 14 base languages fall back to English. Original titles stay available in original_title and original_name.

## Related pages

- [Movie details API](https://amodb.dev/movies/): Movie details API with the same paths and JSON as TMDB v3. Get one movie by id, add credits, ratings and moods with append_to_response, in 14 languages.
- [TV series API](https://amodb.dev/tv-series/): TV series API with the same paths and JSON as TMDB v3. Get a show by id with seasons, networks and the next episode, plus content ratings and watch providers.
- [Person details API](https://amodb.dev/people/): Person details API with the same paths and JSON as TMDB v3. Get an actor or crew member by id, with biography, filmography, external ids and the popular list.
- [Discover API](https://amodb.dev/discover/): Discover API with the same filters as TMDB v3. List movies and TV shows by genre, cast, company, keyword, year, rating, runtime and provider, with sorting.
- [Find by external id](https://amodb.dev/find-by-external-id/): Look up a movie, series or person by IMDb, TVDB, Wikidata or Kinopoisk id with the TMDB find endpoint, and read external ids and Wikidata facts for a title.
- [Rate limits](https://amodb.dev/rate-limits/): amodb limits each key by requests per minute in a sliding 60 second window: 20, 40 or 120 by plan. Read the rate limit headers and handle 429 with Retry-After.

Updated: 2026-10-18. Source: https://amodb.dev/search/
