# API изображений и хост изображений

> Эндпоинты изображений возвращают пути к постерам, фонам, логотипам, портретам и кадрам проекта. Каждый файл вы загружаете с img.amodb.dev в фиксированном размере, без ключа и с кэшированием на edge-серверах на 30 дней. Пути и JSON совпадают с TMDB v3, поэтому код для изображений работает после смены базового URL.

## Эндпоинт

`GET /3/movie/{movie_id}/images`

```bash
curl "https://api.amodb.dev/3/movie/550/images?include_image_language=en,null" \
  -H "Authorization: Bearer $AMODB_KEY"
```

Ответ:

```json
{
  "id": 550,
  "backdrops": [
    {
      "aspect_ratio": 1.778,
      "height": 1440,
      "iso_639_1": null,
      "file_path": "/c6OLXfKAk5BKeR6broC8pYiCquX.jpg",
      "vote_average": 0,
      "vote_count": 0,
      "width": 2560
    },
    {
      "aspect_ratio": 1.778,
      "height": 1080,
      "iso_639_1": "en",
      "file_path": "/b9HyPoxwxjxkWEUL5ErZdhApQe2.jpg",
      "vote_average": 0,
      "vote_count": 0,
      "width": 1920
    },
    {
      "aspect_ratio": 1.778,
      "height": 2160,
      "iso_639_1": "en",
      "file_path": "/ewMhHVyXQKMAviVWM7InPjZqpSr.jpg",
      "vote_average": 0,
      "vote_count": 0,
      "width": 3840
    }
  ],
  "logos": [
    {
      "aspect_ratio": 4.638,
      "height": 389,
      "iso_639_1": "en",
      "file_path": "/7Uqhv24pGJs4Ns31NoOPWFJGWNG.png",
      "vote_average": 0,
      "vote_count": 0,
      "width": 1804
    },
    {
      "aspect_ratio": 0.848,
      "height": 1295,
      "iso_639_1": "en",
      "file_path": "/4XkF0Rf7gvSfea8fYLFbU5tmuJw.png",
      "vote_average": 0,
      "vote_count": 0,
      "width": 1098
    },
    {
      "aspect_ratio": 1.457,
      "height": 1299,
      "iso_639_1": "en",
      "file_path": "/lm0VCzO1ZFhyx81k5Fzkex4u6C8.png",
      "vote_average": 0,
      "vote_count": 0,
      "width": 1893
    }
  ],
  "posters": [
    {
      "aspect_ratio": 0.667,
      "height": 3000,
      "iso_639_1": "en",
      "file_path": "/jSziioSwPVrOy9Yow3XhWIBDjq1.jpg",
      "vote_average": 0,
      "vote_count": 0,
      "width": 2000
    },
    {
      "aspect_ratio": 0,
      "height": 0,
      "iso_639_1": null,
      "file_path": "/qkrH7rjYKU4KOwwIl6wF6H3ISvm.jpg",
      "vote_average": 0,
      "vote_count": 0,
      "width": 0
    },
    {
      "aspect_ratio": 0,
      "height": 0,
      "iso_639_1": null,
      "file_path": "/efBb4gjjKneUoBVgfFOUu2OwihS.jpg",
      "vote_average": 0,
      "vote_count": 0,
      "width": 0
    }
  ]
}
```

## Получение изображений фильма

`GET /3/movie/{movie_id}/images` перечисляет все известные изображения одного фильма в трех массивах: `backdrops`, `logos` и `posters`. Каждая запись содержит `file_path`, размер в пикселях и языковой тег. Самого файла в JSON нет. Вы загружаете его с хоста изображений вторым шагом.

Пример запрашивает английские изображения и изображения без текста, выбирает первый английский постер и затем загружает этот файл шириной 500 пикселей.

```bash
curl -s "https://api.amodb.dev/3/movie/550/images?include_image_language=en,null" \
  -H "Authorization: Bearer $AMODB_KEY"

curl -s -o poster.jpg -w "%{http_code}\n" \
  "https://img.amodb.dev/t/p/w500/jSziioSwPVrOy9Yow3XhWIBDjq1.jpg"
```

```js
const url = 'https://api.amodb.dev/3/movie/550/images?include_image_language=en,null';
const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.AMODB_KEY}` } });
if (!res.ok) throw new Error(`amodb returned ${res.status}`);
const { posters } = await res.json();
if (posters.length === 0) throw new Error('no posters');
const poster = posters.find((p) => p.iso_639_1 === 'en') ?? posters[0];
const posterUrl = `https://img.amodb.dev/t/p/w500${poster.file_path}`;
const img = await fetch(posterUrl);
console.log(img.status, img.headers.get('content-type'), posterUrl);
```

```python
import os
import requests

r = requests.get(
    "https://api.amodb.dev/3/movie/550/images",
    params={"include_image_language": "en,null"},
    headers={"Authorization": f"Bearer {os.environ['AMODB_KEY']}"},
    timeout=10,
)
r.raise_for_status()
posters = r.json()["posters"]
if not posters:
    raise SystemExit("no posters")
poster = next((p for p in posters if p["iso_639_1"] == "en"), posters[0])
poster_url = "https://img.amodb.dev/t/p/w500" + poster["file_path"]
img = requests.get(poster_url, timeout=10)
print(img.status_code, img.headers.get("content-type"), poster_url)
```

```php
<?php
$url = 'https://api.amodb.dev/3/movie/550/images?include_image_language=en,null';
$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");
}
$posters = json_decode($body, true)['posters'];
if (!$posters) {
    throw new RuntimeException('no posters');
}
$poster = $posters[0];
foreach ($posters as $p) {
    if ($p['iso_639_1'] === 'en') {
        $poster = $p;
        break;
    }
}
$posterUrl = 'https://img.amodb.dev/t/p/w500' . $poster['file_path'];
$img = curl_init($posterUrl);
curl_setopt_array($img, [CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 10]);
curl_exec($img);
echo curl_getinfo($img, CURLINFO_HTTP_CODE), ' ', curl_getinfo($img, CURLINFO_CONTENT_TYPE), ' ', $posterUrl, PHP_EOL;
curl_close($img);
```

```go
package main

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

type Images struct {
	Posters []struct {
		FilePath string `json:"file_path"`
		Language string `json:"iso_639_1"`
	} `json:"posters"`
}

func main() {
	url := "https://api.amodb.dev/3/movie/550/images?include_image_language=en,null"
	req, _ := http.NewRequest("GET", url, 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 images Images
	if err := json.NewDecoder(res.Body).Decode(&images); err != nil || len(images.Posters) == 0 {
		panic("no posters")
	}
	poster := images.Posters[0]
	for _, p := range images.Posters {
		if p.Language == "en" {
			poster = p
			break
		}
	}
	posterURL := "https://img.amodb.dev/t/p/w500" + poster.FilePath
	img, err := client.Get(posterURL)
	if err != nil {
		panic(err)
	}
	defer img.Body.Close()
	fmt.Println(img.StatusCode, img.Header.Get("Content-Type"), posterURL)
}
```

### Параметры

| Параметр                 | Где            | Обязателен   | Описание                                                                                                                                                                                |
| ------------------------ | -------------- | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `movie_id`               | путь           | да           | Числовой ID фильма, например `550`.                                                                                                                                                     |
| `api_key`                | строка запроса | один из двух | Ваш ключ. Используйте его или заголовок `Authorization: Bearer`.                                                                                                                        |
| `include_image_language` | строка запроса | нет          | Коды ISO 639-1 через запятую. Добавьте `null`, чтобы включить изображения без текста, например `en,null`. Возвращаются только перечисленные языки. Без параметра вы получите все языки. |
| `language`               | строка запроса | нет          | Принимается, но на этом эндпоинте игнорируется. Для выбора языков используйте `include_image_language`.                                                                                 |

### Поля ответа

| Поле                            | Тип                | Примечания                                                                                                                                     |
| ------------------------------- | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`                            | целое число        | ID фильма.                                                                                                                                     |
| `backdrops`, `logos`, `posters` | массив             | По одному массиву на каждый вид изображений, в таком порядке ключей. Каждый может быть пустым.                                                 |
| `file_path`                     | строка             | Начинается со слэша. Добавьте его к размеру на хосте изображений. Постеры и фоны имеют расширение `.jpg`, логотипы `.png` или `.svg`.          |
| `width`, `height`               | целое число        | Размер исходного файла в пикселях. `0`, если размер неизвестен.                                                                                |
| `aspect_ratio`                  | число              | Ширина, деленная на высоту. У постеров около 0.667, у фонов около 1.778. `0`, если размер неизвестен.                                          |
| `iso_639_1`                     | строка или null    | Язык текста на изображении. `null` означает, что текста нет.                                                                                   |
| `vote_average`, `vote_count`    | число, целое число | Для изображений фильмов и сериалов всегда `0`, поэтому ранжировать по ним изображения нельзя. Сохраняйте порядок, в котором их возвращает API. |

### Пример ответа

Показано по две записи в каждом массиве.

```json
{
  "id": 550,
  "backdrops": [
    {
      "aspect_ratio": 1.778,
      "height": 1440,
      "iso_639_1": null,
      "file_path": "/c6OLXfKAk5BKeR6broC8pYiCquX.jpg",
      "vote_average": 0,
      "vote_count": 0,
      "width": 2560
    },
    {
      "aspect_ratio": 1.778,
      "height": 1080,
      "iso_639_1": "en",
      "file_path": "/b9HyPoxwxjxkWEUL5ErZdhApQe2.jpg",
      "vote_average": 0,
      "vote_count": 0,
      "width": 1920
    }
  ],
  "logos": [
    {
      "aspect_ratio": 4.638,
      "height": 389,
      "iso_639_1": "en",
      "file_path": "/7Uqhv24pGJs4Ns31NoOPWFJGWNG.png",
      "vote_average": 0,
      "vote_count": 0,
      "width": 1804
    },
    {
      "aspect_ratio": 0.848,
      "height": 1295,
      "iso_639_1": "en",
      "file_path": "/4XkF0Rf7gvSfea8fYLFbU5tmuJw.png",
      "vote_average": 0,
      "vote_count": 0,
      "width": 1098
    }
  ],
  "posters": [
    {
      "aspect_ratio": 0.667,
      "height": 3000,
      "iso_639_1": "en",
      "file_path": "/jSziioSwPVrOy9Yow3XhWIBDjq1.jpg",
      "vote_average": 0,
      "vote_count": 0,
      "width": 2000
    },
    {
      "aspect_ratio": 0,
      "height": 0,
      "iso_639_1": null,
      "file_path": "/qkrH7rjYKU4KOwwIl6wF6H3ISvm.jpg",
      "vote_average": 0,
      "vote_count": 0,
      "width": 0
    }
  ]
}
```

Второй постер показывает запись с неизвестным размером. Файл при этом загружается.

## Сборка URL изображения

Соедините три части: `https://img.amodb.dev/t/p/`, сегмент размера и `file_path`. Путь уже начинается со слэша, поэтому `https://img.amodb.dev/t/p/w500` плюс `/jSziioSwPVrOy9Yow3XhWIBDjq1.jpg` дают полный URL.

Размер это `w` плюс ширина в пикселях, `h` плюс высота в пикселях или `original` для сохраненного файла. Хост отдает десять размеров: `w92`, `w154`, `w185`, `w300`, `w342`, `w500`, `w780`, `w1280`, `h632` и `original`. Любой другой размер, например `w400`, отвечает 404. Размеры, подходящие для каждого вида изображений, перечисляет `/3/configuration`.

| Вид            | Поле конфигурации | Размеры                                                   |
| -------------- | ----------------- | --------------------------------------------------------- |
| Постер         | `poster_sizes`    | `w92`, `w154`, `w185`, `w342`, `w500`, `w780`, `original` |
| Фон (backdrop) | `backdrop_sizes`  | `w300`, `w780`, `w1280`, `original`                       |
| Логотип        | `logo_sizes`      | `w92`, `w154`, `w185`, `w300`, `w500`, `original`         |
| Профиль        | `profile_sizes`   | `w185`, `h632`, `original`                                |
| Кадр           | `still_sizes`     | `w92`, `w185`, `w300`, `original`                         |

Хост не проверяет вид изображения, поэтому постер загружается и в размере `w1280`. Придерживайтесь размеров, указанных для вида, чтобы ваш код соответствовал конфигурации и любому клиенту TMDB.

Хосту изображений ключ не нужен, а edge-серверы хранят каждый файл 30 дней. Поскольку ключ не отправляется, загрузка изображений не расходует ваш лимит запросов в минуту. Ответы содержат `Access-Control-Allow-Origin: *`, поэтому браузер может загружать их с любой страницы. Неизвестный размер или неизвестный файл отвечает 404 с телом JSON.

## Адаптивные изображения с srcset

Выбирайте наименьший размер, который все еще покрывает отображаемую ширину, умноженную на плотность экрана. Постеру шириной 171 CSS-пиксель на экране 2x нужен `w342`. Этот помощник собирает `srcset` из сохраненного пути.

```js
const WIDTHS = [185, 342, 500, 780];

function posterSrcset(filePath) {
  return WIDTHS.map((w) => `https://img.amodb.dev/t/p/w${w}${filePath} ${w}w`).join(', ');
}

const path = '/jSziioSwPVrOy9Yow3XhWIBDjq1.jpg';
console.log(`<img src="https://img.amodb.dev/t/p/w342${path}" srcset="${posterSrcset(path)}" sizes="(max-width: 600px) 50vw, 342px" alt="Fight Club poster">`);
```

## Другие эндпоинты изображений

Все пути ниже используют базовый URL `https://api.amodb.dev/3` и возвращают массивы, названные во втором столбце.

| Метод и путь                                                                 | Возвращаемые массивы                                  | Параметры                |
| ---------------------------------------------------------------------------- | ----------------------------------------------------- | ------------------------ |
| `GET /tv/{series_id}/images`                                                 | `backdrops`, `logos`, `posters`                       | `include_image_language` |
| `GET /tv/{series_id}/season/{season_number}/images`                          | `posters`, всегда пустой                              | нет                      |
| `GET /tv/{series_id}/season/{season_number}/episode/{episode_number}/images` | `stills`, одна запись с `width` и `height`, равными 0 | нет                      |
| `GET /person/{person_id}/images`                                             | `profiles`                                            | нет                      |

Для фильмов и сериалов можно также добавить `append_to_response=images` к запросу сведений. `include_image_language` работает и там. У добавленного блока нет собственного `id`.

Профили персон это единственное место, где `vote_average` содержит реальную оценку. `id` в ответе для сезона или серии это ID сезона или серии. Родительские записи описаны на страницах [люди](https://amodb.dev/ru/people/) и [сериалы](https://amodb.dev/ru/tv-series/).

amodb не предоставляет пути изображений для коллекций, компаний и телесетей. Их записи уже содержат по одному `poster_path`, `backdrop_path` или `logo_path`, это описано на страницах [коллекции](https://amodb.dev/ru/collections/) и [компании и телесети](https://amodb.dev/ru/companies-networks/).

## Эндпоинт конфигурации

`GET /3/configuration` возвращает блок `images` с `secure_base_url`, равным `https://img.amodb.dev/t/p/`, `base_url` (обычная форма http) и списками размеров `backdrop_sizes`, `logo_sizes`, `poster_sizes`, `profile_sizes` и `still_sizes`. Прочитайте его один раз при запуске, используйте защищенную форму и собирайте URL из него, а не прописывайте размеры в коде. Edge-серверы кэшируют его на 24 часа.

## Ошибки

| HTTP | status_code | Когда                                                                                            |
| ---- | ----------- | ------------------------------------------------------------------------------------------------ |
| 401  | 7           | Ключ отсутствует или неверен при вызове JSON.                                                    |
| 402  | 36          | Срок действия тарифа закончился.                                                                 |
| 404  | 34          | Нет персоны, сезона или серии с таким ID, либо неизвестный размер или файл на хосте изображений. |
| 405  | 37          | Вы использовали метод записи на пути изображений.                                                |
| 429  | 25          | Вы превысили лимит запросов в минуту. Подождите столько секунд, сколько указано в `Retry-After`. |

ID фильма или сериала, которого не существует, здесь не считается ошибкой: путь изображений отвечает 200 с пустыми массивами, а путь сведений отвечает 404. Полный список смотрите на странице [ошибки](https://amodb.dev/ru/errors/). Запросы файлов изображений это обычные загрузки по HTTP, поэтому проверяйте код статуса ответа, а не разбирайте тело JSON.

## Практические замечания

- Храните `file_path` в базе и собирайте URL при отрисовке. Тогда новый размер или хост потребует одного изменения в коде.
- Передавайте `include_image_language` с языком интерфейса плюс `null`, например `ru,null`, чтобы постеры с чужим текстом не попадали в выдачу.
- Пустой массив это обычный ответ 200. Используйте в качестве запасного варианта `poster_path` из записи [сведения о фильме](https://amodb.dev/ru/movies/).
- Используйте `w1280` для фонов на всю ширину и `w780` для карточек. `original` это сохраненный файл в полном разрешении, он намного больше, чем `w780`.
- Копии на edge-серверах живут 30 дней и общие для всех, поэтому файл, который запросил один клиент, следующему отдается из кэша.

## Вопросы и ответы

### Нужен ли ключ API для запросов изображений?

Нет. Файлы по адресу img.amodb.dev/t/p/{size}/{file} общедоступны, поэтому их можно использовать прямо в тегах img и в CSS. Ключ нужен только для JSON-эндпоинтов, которые перечисляют пути к файлам.

### Какие размеры изображений можно запрашивать?

w92, w154, w185, w300, w342, w500, w780, w1280, h632 и original. Любой другой размер отвечает 404. Какие из них подходят для каждого вида изображений, перечисляет /3/configuration, а таблица размеров на этой странице повторяет этот список.

### Как получить постеры только на одном языке?

Передайте include_image_language со списком через запятую, например en,null. Значение null добавляет изображения без текста. Возвращаются только перечисленные языки. Параметр language изображения не фильтрует.

### Почему путь к файлу начинается со слэша?

Пути в стиле TMDB включают начальный слэш, чтобы их можно было добавлять прямо к сегменту размера. Храните только путь, а полный URL собирайте при отрисовке.

## Связанные страницы

- [API деталей фильма](https://amodb.dev/ru/movies/): API деталей фильма с теми же путями и JSON, что в TMDB v3. Получите фильм по ID, добавьте актеров, рейтинги и настроения через append_to_response, на 14 языках.
- [API сериалов](https://amodb.dev/ru/tv-series/): API сериалов с теми же путями и JSON, что в TMDB v3. Сериал по id с сезонами, телесетями и следующей серией, а также возрастные рейтинги и сервисы просмотра.
- [API деталей человека](https://amodb.dev/ru/people/): API деталей человека с теми же путями и JSON, что в TMDB v3. Получайте актера или члена съемочной группы по ID: биография, фильмография, внешние ID, популярные.
- [API коллекций](https://amodb.dev/ru/collections/): API коллекций фильмов с путями TMDB v3: получите франшизу по ID со всеми частями, прочитайте belongs_to_collection у фильма и найдите коллекцию по названию.
- [API постеров фильмов и CDN изображений](https://amodb.dev/ru/movie-poster-api/): API постеров фильмов с хостом изображений без ключа. Размеры от w92 до original, списки srcset и выбор постеров по языку через include_image_language.
- [Быстрый старт](https://amodb.dev/ru/quickstart/): Первый вызов amodb: получите ключ, запросите детали фильма через curl, JavaScript, Python, PHP или Go и загрузите постер с img.amodb.dev. Меньше 2 минут.

Обновлено: 2026-10-18. Source: https://amodb.dev/ru/images-api/
