# API de banco de dados de filmes para o seu catálogo

> Use o amodb como fonte do seu banco de dados de filmes. Filmes, pessoas, produtoras, coleções, palavras-chave e gêneros compartilham ids numéricos, então as linhas se unem direto. Faça a carga inicial com o discover em janelas de datas, atualize por idade e relacione seus ids pelo id externo. JSON TMDB v3, 20 a 120 requisições por minuto.

## Crie seu próprio banco de dados de filmes a partir de uma API

O amodb é uma API independente que fala o protocolo TMDB v3. Filmes, pessoas, produtoras, coleções, palavras-chave e gêneros têm ids numéricos e apontam uns para os outros, então você pode preencher tabelas SQL com eles e mantê-las atualizadas. Faça a carga inicial das tabelas com a paginação do discover, atualize-as por idade e relacione seus próprios identificadores com `find`. O amodb não tem feed de alterações, então atualizar é só buscar de novo as linhas que você mantém.

O que você recebe:

- Seis tipos de entidades ligadas, com ids numéricos estáveis.
- Paginação do discover para a primeira carga: até 20 resultados por página, 500 páginas por consulta.
- Janelas de datas de lançamento no discover, para fatiar a primeira carga e listar lançamentos novos.
- Buscas por id externo para `imdb_id`, `tvdb_id`, `wikidata_id` e `kinopoisk_id`.

## Quais dados você recebe

Este é o modelo de dados. Cada linha é uma tabela em uma cópia relacional.

| Entidade      | Leia com                            | Chave           | Liga a                                                                                               |
| ------------- | ----------------------------------- | --------------- | ---------------------------------------------------------------------------------------------------- |
| Filme         | `GET /3/movie/{movie_id}`           | `id`, `imdb_id` | `genres[].id`, `production_companies[].id`, `belongs_to_collection.id`                               |
| Pessoa        | `GET /3/person/{person_id}`         | `id`, `imdb_id` | Filmes por `/3/movie/{movie_id}/credits`                                                             |
| Produtora     | `GET /3/company/{company_id}`       | `id`            | Filmes por `with_companies` no discover. `parent_company` é sempre `null` e `description` fica vazio |
| Coleção       | `GET /3/collection/{collection_id}` | `id`            | `parts[]`, uma lista de filmes                                                                       |
| Palavra-chave | `GET /3/keyword/{keyword_id}`       | `id`            | Filmes por `/3/keyword/{keyword_id}/movies` ou `with_keywords`                                       |
| Gênero        | `GET /3/genre/movie/list`           | `id`            | `genres[].id` nos filmes                                                                             |

Relações muitos para muitos precisam de tabelas de junção: `movie_genre`, `movie_company`, `movie_keyword` e `movie_credit`. Use `credit_id` de [créditos](https://amodb.dev/pt/credits/) como chave da última. As listas de campos estão em [filmes](https://amodb.dev/pt/movies/), [pessoas](https://amodb.dev/pt/people/) e [coleções](https://amodb.dev/pt/collections/).

## Comece em 3 passos

1. Compare as três taxas de requisição em [preços](https://amodb.dev/pt/pricing/). Uma taxa maior encurta a primeira carga, e nada mais muda.
2. Crie uma chave no painel da sua conta e guarde-a em uma variável de ambiente.
3. Chame `/3/discover/movie` para uma janela de um dia de datas de lançamento e depois busque cada id da lista.

## Exemplo de requisição

O script PHP lista os filmes lançados ontem e hoje pelo discover e grava cada registro em uma tabela SQLite com upsert. Ele espera 3 segundos entre as leituras de detalhes para ficar abaixo de 20 requisições por minuto, repete um 429 depois de `Retry-After` e apaga as linhas cujo id agora retorna 404.

```bash
curl -s "https://api.amodb.dev/3/discover/movie?primary_release_date.gte=2026-10-17&primary_release_date.lte=2026-10-18&sort_by=primary_release_date.asc&page=1" \
  -H "Authorization: Bearer $AMODB_KEY"
```

```php
<?php
const BASE = 'https://api.amodb.dev/3';

function amodb(string $path, array $query = []): ?array
{
    $url = BASE . $path . '?' . http_build_query($query);
    for ($attempt = 0; $attempt < 3; $attempt++) {
        $retryAfter = 1;
        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT => 10,
            CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('AMODB_KEY')],
            CURLOPT_HEADERFUNCTION => function ($handle, $line) use (&$retryAfter) {
                if (stripos($line, 'Retry-After:') === 0) {
                    $retryAfter = max(1, (int) trim(substr($line, 12)));
                }
                return strlen($line);
            },
        ]);
        $body = curl_exec($ch);
        $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        if ($status === 429) {
            sleep($retryAfter);
            continue;
        }
        if ($status === 404) {
            return null;
        }
        if ($status !== 200) {
            throw new RuntimeException("amodb returned $status for $path");
        }
        return json_decode($body, true);
    }
    throw new RuntimeException("Still rate limited on $path");
}

$db = new PDO('sqlite:movies.sqlite');
$db->exec('CREATE TABLE IF NOT EXISTS movie (id INTEGER PRIMARY KEY, imdb_id TEXT, title TEXT, release_date TEXT, raw TEXT)');
$save = $db->prepare('INSERT OR REPLACE INTO movie (id, imdb_id, title, release_date, raw) VALUES (?, ?, ?, ?, ?)');
$drop = $db->prepare('DELETE FROM movie WHERE id = ?');

$from = date('Y-m-d', strtotime('-1 day'));
$to = date('Y-m-d');
$page = 1;
do {
    $list = amodb('/discover/movie', [
        'primary_release_date.gte' => $from,
        'primary_release_date.lte' => $to,
        'sort_by' => 'primary_release_date.asc',
        'page' => $page,
    ]);
    foreach ($list['results'] as $row) {
        $movie = amodb('/movie/' . $row['id'], ['language' => 'en-US']);
        if ($movie === null) {
            $drop->execute([$row['id']]);
            continue;
        }
        $save->execute([$movie['id'], $movie['imdb_id'] ?? null, $movie['title'], $movie['release_date'] ?? null, json_encode($movie)]);
        sleep(3);
    }
    $page++;
} while ($page <= min($list['total_pages'], 500));
```

O discover retorna linhas de lista, não registros completos. Estes são 2 dos 20 resultados da página 1. Leia `/3/movie/{id}` para o restante dos campos.

```json
{
  "page": 1,
  "results": [
    {
      "adult": false,
      "backdrop_path": "/siepLRGVjM8yLKppApkD3uSh8Y0.jpg",
      "genre_ids": [
        35
      ],
      "id": 1800227,
      "original_language": "en",
      "original_title": "Sly's Pack",
      "overview": "Nesmith, Gary, & Tony are smoking weed on the roof of a parking garage, but a...",
      "popularity": 0.0071,
      "poster_path": "/3HpIWZUI7jmpKZkfZNdchS2WsvN.jpg",
      "release_date": "2026-10-17",
      "title": "Sly's Pack",
      "video": false,
      "vote_average": 0,
      "vote_count": 0
    },
    {
      "adult": false,
      "backdrop_path": null,
      "genre_ids": [
        99
      ],
      "id": 1800168,
      "original_language": "en",
      "original_title": "The Good Life",
      "overview": "The Good LIfe is based on the best-selling book by Drs. Robert Waldinger and...",
      "popularity": 0.0143,
      "poster_path": null,
      "release_date": "2026-10-17",
      "title": "The Good Life",
      "video": false,
      "vote_average": 0,
      "vote_count": 0
    }
  ],
  "total_pages": 15,
  "total_results": 299
}
```

## Preencha e atualize as tabelas

| Tarefa                    | Chamada                                                                                                               | Limites                                                                                                                                    |
| ------------------------- | --------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| Primeira carga            | `GET /3/discover/movie` com `sort_by` e uma janela de datas                                                           | `page` de 1 a 500, até 20 resultados por página, ou seja, 10,000 por consulta. Fatie por `primary_release_date.gte` e `.lte` para ir além. |
| Lançamentos novos         | `GET /3/discover/movie` com `primary_release_date.gte` igual à data da sua última execução, e `GET /3/movie/upcoming` | Em cache por 30 minutos.                                                                                                                   |
| Atualizar linhas          | `GET /3/movie/{movie_id}` para linhas com mais de 6 horas                                                             | Não há feed de alterações. Atualize os títulos que os usuários abrem e o restante com menos frequência.                                    |
| Relacionar seus ids       | `GET /3/find/{external_id}`                                                                                           | Um id por chamada, com a fonte escolhida em `external_source`.                                                                             |
| Preenchimento sob demanda | `GET /3/movie/{movie_id}` quando um usuário abre um título                                                            | Guarde a resposta com um carimbo de data e hora.                                                                                           |

A janela de paginação é a principal decisão de projeto. Quando `total_pages` em uma resposta passa de 500, a janela tem mais de 10,000 linhas, então divida-a ao meio até caber. Um ano recente precisa ser cortado em meses, e um dia de lançamentos tem algumas centenas de títulos. Guarde a fatia que você terminou para que uma execução interrompida possa continuar. As regras de correspondência para a junção estão em [buscar por id externo](https://amodb.dev/pt/find-by-external-id/).

## Dimensionando a sincronização

Cada linha que você atualiza custa uma leitura de detalhes. Um plano de 20 requisições por minuto dá 1,200 chamadas por hora, o de 40 dá 2,400 e o de 120 dá 7,200. Uma página do discover lista 20 ids com uma chamada. Rode a atualização fora do horário de pico se seu app compartilha a chave, porque o limite vale por chave, não por script. Veja [limites de requisições](https://amodb.dev/pt/rate-limits/) para os headers que informam o que resta na janela.

## Cache em duas camadas

| Camada         | Guarda                                  | TTL                                                                  |
| -------------- | --------------------------------------- | -------------------------------------------------------------------- |
| Cache de borda | Detalhes e créditos                     | 6 horas                                                              |
| Cache de borda | Listas de discover, em alta e populares | 30 minutos                                                           |
| Cache de borda | Busca                                   | 10 minutos                                                           |
| Cache de borda | Configuração                            | 24 horas                                                             |
| Cache de borda | Imagens                                 | 30 dias                                                              |
| Suas tabelas   | Linhas que você mantém                  | Até sua regra de idade mandar buscar de novo, nunca antes de 6 horas |

O cache de borda é compartilhado entre chaves, mas o limite de requisições age antes dele, então um acerto de cache ainda usa uma requisição do seu minuto. Reler uma linha com mais frequência que a cada 6 horas retorna a mesma cópia e desperdiça cota. Deixe uma regra de idade decidir quando buscar de novo.

## Como se compara

| Recurso                   | Fazer scraping das páginas               | Arquivos de dataset estáticos               | amodb                                                              |
| ------------------------- | ---------------------------------------- | ------------------------------------------- | ------------------------------------------------------------------ |
| Atualidade                | Tão atual quanto seu último rastreamento | Tão atual quanto o último arquivo publicado | Detalhes em cache por 6 horas, nova busca por idade                |
| Atualizações incrementais | Rastrear de novo e comparar              | Baixar um arquivo novo                      | Discover com janela de datas de lançamento, sem feed de alterações |
| Ids entre entidades       | URLs das páginas                         | Definidos pelo publicador                   | Ids numéricos, `imdb_id` e `/3/find`                               |
| O que você mantém         | Crawlers e armazenamento                 | Armazenamento e um job de importação        | Armazenamento e um script de sincronização                         |
| Limite de requisições     | Definido pelos sites que você rastreia   | Não se aplica                               | 20, 40 ou 120 requisições por minuto, contadas por chave           |
| Idiomas por registro      | O que cada página oferecer               | Depende dos arquivos                        | 14, escolhidos com `language`                                      |

## Preços

A primeira carga é a parte cara, e ela é limitada pelas suas requisições por minuto. Escolha 20, 40 ou 120 por minuto em [preços](https://amodb.dev/pt/pricing/). Pague por 1, 3, 6, 12 ou 24 meses, com 0, 10, 20, 30 ou 40 por cento de desconto. Nada renova automaticamente, não há plano gratuito e todo plano lê os mesmos dados.

## Perguntas e respostas

### Como manter uma cópia local atualizada?

O amodb não tem feed de alterações, então atualize por idade. Os detalhes ficam em cache de borda por 6 horas, portanto não busque uma linha de novo antes disso. Pegue os lançamentos novos com discover e primary_release_date.gte igual à data da sua última execução.

### Como carrego a primeira cópia?

Percorra /3/discover/movie com page de 1 a 500 (até 20 resultados cada, ou seja, 10,000 por consulta) e divida por janelas de primary_release_date para ir além. Só março de 2025 tem cerca de 4,400 títulos. Depois leia /3/movie/{id} para cada id que você mantiver.

### Quanto tempo leva a primeira carga no meu limite de requisições?

Com 20 requisições por minuto você faz 1,200 chamadas por hora, com 40 são 2,400 e com 120 são 7,200. Divida o número de leituras de detalhes de que você precisa por esse valor para planejar a execução.

### Posso unir os ids do amodb com os ids que já guardo?

Sim. /3/find/{external_id} aceita imdb_id, tvdb_id, wikidata_id e kinopoisk_id e retorna o registro correspondente do amodb. Os registros de filmes também trazem imdb_id, então a junção funciona nos dois sentidos.

### Existe plano gratuito para montar um banco de dados?

Não. O acesso é pré-pago por 1, 3, 6, 12 ou 24 meses e não renova sozinho. Todo plano lê os mesmos dados, então um plano maior só deixa a primeira carga e as atualizações mais rápidas.

## Páginas relacionadas

- [API de detalhes de filmes](https://amodb.dev/pt/movies/): API de detalhes de filmes com caminhos e JSON do TMDB v3. Busque um filme por id e junte créditos, avaliações e moods com append_to_response, em 14 idiomas.
- [API de detalhes de pessoas](https://amodb.dev/pt/people/): API de detalhes de pessoas com os caminhos e o JSON do TMDB v3. Busque um ator ou membro da equipe por id, com biografia, filmografia e ids externos.
- [API de coleções](https://amodb.dev/pt/collections/): API de coleções de filmes com caminhos do TMDB v3: busque uma franquia por id com todas as partes, leia belongs_to_collection de um filme e pesquise por nome.
- [Produtoras e emissoras](https://amodb.dev/pt/companies-networks/): Consulte produtoras e emissoras de TV com caminhos do TMDB v3. Leia nome, país e logo por id e depois filtre o discover por id de produtora ou emissora.
- [Buscar por ID externo](https://amodb.dev/pt/find-by-external-id/): Busque um filme, série ou pessoa por id do IMDb, TVDB, Wikidata ou Kinopoisk com o endpoint find do TMDB e leia ids externos e dados do Wikidata de um título.
- [Limites de requisições](https://amodb.dev/pt/rate-limits/): O amodb limita cada chave por requisições por minuto em uma janela de 60 segundos: 20, 40 ou 120 por plano. Leia os cabeçalhos e trate o 429 com Retry-After.

Atualizado: 2026-10-18. Source: https://amodb.dev/pt/movie-database-api/
