# API зображень і хост зображень

> Ендпоінти зображень повертають шляхи до постерів, фонів, логотипів, фото персон і кадрів проєкту. Кожен файл ви завантажуєте з img.amodb.dev у фіксованому розмірі, без ключа і з кешем CDN на 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`                | query | одне з двох  | Ваш ключ. Використовуйте його або заголовок `Authorization: Bearer`.                                                                                                 |
| `include_image_language` | query | ні           | Коди ISO 639-1 через кому. Додайте `null`, щоб включити зображення без тексту, наприклад `en,null`. Повертаються лише вказані мови. Без нього ви отримаєте всі мови. |
| `language`               | query | ні           | Приймається, але на цьому ендпоінті ігнорується. Мови вибирайте через `include_image_language`.                                                                      |

### Поля відповіді

| Поле                            | Тип             | Примітки                                                                                                                                       |
| ------------------------------- | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`                            | integer         | id фільму.                                                                                                                                     |
| `backdrops`, `logos`, `posters` | array           | Один масив для кожного виду зображень, у такому порядку ключів. Кожен може бути порожнім.                                                      |
| `file_path`                     | string          | Починається зі скісної риски. Допишіть його до розміру на хості зображень. Постери й фони мають розширення `.jpg`, логотипи `.png` або `.svg`. |
| `width`, `height`               | integer         | Розмір оригінального файлу в пікселях. `0`, якщо розмір невідомий.                                                                             |
| `aspect_ratio`                  | number          | Ширина, поділена на висоту. Постери близькі до 0.667, фони до 1.778. `0`, якщо розмір невідомий.                                               |
| `iso_639_1`                     | string або null | Мова тексту на зображенні. `null` означає, що тексту немає.                                                                                    |
| `vote_average`, `vote_count`    | number, integer | Для зображень фільмів і серіалів завжди `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.

Хост зображень не потребує ключа, а CDN зберігає кожен файл 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">`);
```

## Інші ендпоінти зображень

Усі шляхи нижче використовують основу `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/uk/people/) та [серіали](https://amodb.dev/uk/tv-series/).

amodb не надає шляхів зображень для колекцій, компаній і мереж. Їхні записи вже містять один `poster_path`, `backdrop_path` або `logo_path`, описаний на сторінках [колекції](https://amodb.dev/uk/collections/) та [компанії та телемережі](https://amodb.dev/uk/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 з нього, а не зашивайте розміри в код. CDN кешує його на 24 години.

## Помилки

| HTTP | status_code | Коли                                                                                               |
| ---- | ----------- | -------------------------------------------------------------------------------------------------- |
| 401  | 7           | Ключ відсутній або неправильний у JSON-виклику.                                                    |
| 402  | 36          | Термін дії тарифу закінчився.                                                                      |
| 404  | 34          | Немає персони, сезону чи серії з таким id, або невідомий розмір чи файл на хості зображень.        |
| 405  | 37          | Ви використали метод запису на шляху зображень.                                                    |
| 429  | 25          | Ви перевищили ліміт запитів на хвилину. Зачекайте стільки секунд, скільки вказано в `Retry-After`. |

Неіснуючий id фільму чи серіалу тут не є помилкою: шлях зображень повертає 200 з порожніми масивами, а шлях деталей повертає 404. Повний список дивіться на сторінці [помилки](https://amodb.dev/uk/errors/). Запити файлів зображень це прості HTTP-завантаження, тому перевіряйте код статусу відповіді, а не розбирайте тіло JSON.

## Практичні поради

- Зберігайте `file_path` у базі даних і будуйте URL під час відображення. Тоді новий розмір чи хост коштуватиме однієї зміни коду.
- Передавайте `include_image_language` з мовою відображення плюс `null`, наприклад `ru,null`, щоб не з'являлися постери з іноземним текстом.
- Порожній масив це нормальна відповідь 200. Використайте запасний варіант: `poster_path` із запису [деталей фільму](https://amodb.dev/uk/movies/).
- Використовуйте `w1280` для фонів на всю ширину, а `w780` для карток. `original` це збережений файл у повній роздільній здатності, і він набагато більший за `w780`.
- Копії на CDN живуть 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/uk/movies/): API деталей фільму з тими самими шляхами та JSON, що в TMDB v3. Отримайте фільм за id, додайте акторів, рейтинги й настрої через append_to_response, 14 мовами.
- [API серіалів](https://amodb.dev/uk/tv-series/): API серіалів з тими самими шляхами та JSON, що в TMDB v3. Отримайте серіал за id із сезонами, телемережами й наступною серією, плюс вікові рейтинги.
- [API деталей персони](https://amodb.dev/uk/people/): API деталей персони з тими самими шляхами та JSON, що в TMDB v3. Отримайте актора чи режисера за id: біографія, фільмографія, зовнішні id і список популярних.
- [API колекцій](https://amodb.dev/uk/collections/): API колекцій фільмів зі шляхами TMDB v3: отримайте франшизу за id з усіма частинами, прочитайте belongs_to_collection у фільму та знайдіть колекцію за назвою.
- [API постерів фільмів і CDN зображень](https://amodb.dev/uk/movie-poster-api/): API постерів фільмів із хостом зображень без ключа. Розміри від w92 до original, списки srcset і вибір постерів за мовою через include_image_language.
- [Швидкий старт](https://amodb.dev/uk/quickstart/): Перший виклик amodb: отримайте ключ, запросіть деталі фільму в curl, JavaScript, Python, PHP чи Go і завантажте постер з img.amodb.dev. Менш ніж за 2 хвилини.

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