# API за ключови думи

> Ендпойнтите за ключови думи връщат таговете на сюжета, прикачени към филм или сериал, всеки като id и име. Можете да потърсите една ключова дума, да изброите филмите с нея или да подадете id на discover с with_keywords, за да построите тематични страници. Филмите отговарят под keywords, сериалите под results.

## Ендпойнт

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

```bash
curl "https://api.amodb.dev/3/movie/550/keywords" \
  -H "Authorization: Bearer $AMODB_KEY"
```

Отговор:

```json
{
  "id": 550,
  "keywords": [
    {
      "id": 818,
      "name": "based on novel or book"
    },
    {
      "id": 825,
      "name": "support group"
    },
    {
      "id": 851,
      "name": "dual identity"
    }
  ]
}
```

## Вземане на ключовите думи на филм

`GET /3/movie/{movie_id}/keywords` връща таговете на сюжета на един филм. Ключовата дума е кратка фраза, например тема, място на действие или вид първоизточник, и има числово id, което можете да ползвате в [откриване по филтри](https://amodb.dev/bg/discover/).

Примерът зарежда ключовите думи на филм и после иска от discover най-популярните филми, които споделят първата му ключова дума.

```bash
curl -s "https://api.amodb.dev/3/movie/550/keywords" \
  -H "Authorization: Bearer $AMODB_KEY"

curl -s "https://api.amodb.dev/3/discover/movie?with_keywords=818&sort_by=popularity.desc" \
  -H "Authorization: Bearer $AMODB_KEY"
```

```js
const base = 'https://api.amodb.dev/3';
const headers = { Authorization: `Bearer ${process.env.AMODB_KEY}` };

const kw = await fetch(`${base}/movie/550/keywords`, { headers });
if (!kw.ok) throw new Error(`keywords failed with ${kw.status}`);
const { keywords } = await kw.json();
console.log(keywords.map((k) => `${k.id}:${k.name}`).join(', '));

if (keywords.length > 0) {
  const first = keywords[0];
  const found = await fetch(`${base}/discover/movie?with_keywords=${first.id}&sort_by=popularity.desc`, { headers });
  if (!found.ok) throw new Error(`discover failed with ${found.status}`);
  const page = await found.json();
  console.log(first.name, page.results.slice(0, 5).map((m) => m.title));
}
```

```python
import os
import requests

base = "https://api.amodb.dev/3"
headers = {"Authorization": f"Bearer {os.environ['AMODB_KEY']}"}

r = requests.get(f"{base}/movie/550/keywords", headers=headers, timeout=10)
r.raise_for_status()
keywords = r.json()["keywords"]
print(", ".join(f"{k['id']}:{k['name']}" for k in keywords))

if keywords:
    first = keywords[0]
    d = requests.get(
        f"{base}/discover/movie",
        params={"with_keywords": first["id"], "sort_by": "popularity.desc"},
        headers=headers,
        timeout=10,
    )
    d.raise_for_status()
    print(first["name"], [m["title"] for m in d.json()["results"][:5]])
```

```php
<?php
function amodb_get(string $url): array {
    $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");
    }
    return json_decode($body, true);
}

$base = 'https://api.amodb.dev/3';
$keywords = amodb_get("$base/movie/550/keywords")['keywords'];
if ($keywords) {
    $first = $keywords[0];
    $found = amodb_get("$base/discover/movie?with_keywords={$first['id']}&sort_by=popularity.desc");
    $titles = array_column(array_slice($found['results'], 0, 5), 'title');
    echo $first['name'], ': ', implode(', ', $titles), PHP_EOL;
}
```

```go
package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"time"
)

var client = &http.Client{Timeout: 10 * time.Second}

func get(path string, out any) error {
	req, _ := http.NewRequest("GET", "https://api.amodb.dev/3"+path, nil)
	req.Header.Set("Authorization", "Bearer "+os.Getenv("AMODB_KEY"))
	res, err := client.Do(req)
	if err != nil {
		return err
	}
	defer res.Body.Close()
	if res.StatusCode != http.StatusOK {
		return fmt.Errorf("amodb returned %s", res.Status)
	}
	return json.NewDecoder(res.Body).Decode(out)
}

type Keywords struct {
	Keywords []struct {
		ID   int    `json:"id"`
		Name string `json:"name"`
	} `json:"keywords"`
}

type Page struct {
	Results []struct {
		Title string `json:"title"`
	} `json:"results"`
}

func main() {
	var kw Keywords
	if err := get("/movie/550/keywords", &kw); err != nil {
		panic(err)
	}
	if len(kw.Keywords) == 0 {
		return
	}
	first := kw.Keywords[0]
	var page Page
	if err := get(fmt.Sprintf("/discover/movie?with_keywords=%d&sort_by=popularity.desc", first.ID), &page); err != nil {
		panic(err)
	}
	fmt.Println(first.Name)
	for i, m := range page.Results {
		if i == 5 {
			break
		}
		fmt.Println(" ", m.Title)
	}
}
```

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

| Параметър  | Къде   | Задължителен  | Описание                                                            |
| ---------- | ------ | ------------- | ------------------------------------------------------------------- |
| `movie_id` | път    | да            | Числов id на филма, например `550`.                                 |
| `api_key`  | заявка | един от двата | Вашият ключ. Ползвайте него или заглавката `Authorization: Bearer`. |

### Полета на отговора

| Поле              | Тип        | Бележки                                                                                    |
| ----------------- | ---------- | ------------------------------------------------------------------------------------------ |
| `id`              | цяло число | Id на филма.                                                                               |
| `keywords`        | масив      | Обекти с `id` и `name`. Празен, когато филмът няма такива.                                 |
| `keywords[].id`   | цяло число | Id на ключовата дума. Ползвайте го в `with_keywords` и в пътищата за ключови думи по-долу. |
| `keywords[].name` | низ        | Текстът на ключовата дума.                                                                 |

### Примерен отговор

```json
{
  "id": 550,
  "keywords": [
    { "id": 818, "name": "based on novel or book" },
    { "id": 825, "name": "support group" },
    { "id": 851, "name": "dual identity" }
  ]
}
```

Истинският отговор съдържа 14 ключови думи. Този е съкратен до първите 3. Имената на ключовите думи не се превеждат, затова `language` тук няма ефект.

## Ключови думи на сериал

`GET /3/tv/{series_id}/keywords` приема същия ключ и връща същите обекти, но масивът се казва `results`. Id в пътя е id на сериала, например `1396`.

```json
{
  "id": 1396,
  "results": [
    { "id": 1508, "name": "new mexico" },
    { "id": 2231, "name": "drug dealer" }
  ]
}
```

Истинският отговор съдържа 29 записа, а този е съкратен до първите 2. Клиент, който обслужва двата вида медия, може да чете `data.keywords ?? data.results` и да третира двата по един и същи начин.

## Записи за ключови думи и техните филми

| Метод и път                        | Какво връща                                                                          | Параметри          |
| ---------------------------------- | ------------------------------------------------------------------------------------ | ------------------ |
| `GET /keyword/{keyword_id}`        | `{ id, name }`                                                                       | няма               |
| `GET /keyword/{keyword_id}/movies` | Странициран списък с филми с `id`, `page`, `results`, `total_pages`, `total_results` | `language`, `page` |

И двата пътя ползват числовото id от масив с ключови думи. Списъкът с филми дава същата форма на елемент като другите [списъци с филми](https://amodb.dev/bg/trending-lists/), включително `genre_ids` и `poster_path`, плюс `id` на ключовата дума най-отгоре. `include_adult` се приема и се игнорира. Страница след `total_pages` връща празен масив `results`. Няма списък със сериали за ключова дума, затова за сериали ползвайте `/discover/tv?with_keywords=`.

## Комбиниране на ключови думи с discover

За всичко отвъд обикновен списък филтрирайте в [откриване по филтри](https://amodb.dev/bg/discover/). Той сортира, странира и комбинира ключови думи с други филтри, а покрива и сериали, и филми.

| Цел                                    | Низ на заявката                                    |
| -------------------------------------- | -------------------------------------------------- |
| Филми с една ключова дума              | `/discover/movie?with_keywords=818`                |
| Филми с двете от две ключови думи      | `/discover/movie?with_keywords=818,4565`           |
| Филми без ключова дума                 | `/discover/movie?without_keywords=818`             |
| Сериали с ключова дума                 | `/discover/tv?with_keywords=9712`                  |
| Сериали с коя да е от две ключови думи | `/discover/tv?with_keywords=818%7C9712`            |
| Една ключова дума в рамките на жанр    | `/discover/movie?with_keywords=818&with_genres=18` |

Запетая между id означава всички от тях. Запишете вертикална черта между id, както в `with_keywords=818|4565`, за да съвпадне коя да е. Резултатите от discover се кешират на edge за 30 минути.

## Намиране на id на ключова дума

За да превърнете текст в id, извикайте `GET /3/search/keyword?query=heist`. Връща странициран списък с двойки `id` и `name`, по 20 на страница. Вижте [търсене](https://amodb.dev/bg/search/) за пълния набор от пътища за търсене. Търсене на ключови думи, което не намира нищо, в момента отговаря с 500 и `status_code` 11 вместо с празен списък. Отговорите на търсенето се кешират за 10 минути, но всяко извикване пак се брои към заявките ви в минута, затова забавяйте извикванията в поле с подсказки.

## Грешки

| HTTP | status_code | Кога                                                                        |
| ---- | ----------- | --------------------------------------------------------------------------- |
| 401  | 7           | Ключът липсва или е грешен.                                                 |
| 402  | 36          | Периодът на плана е изтекъл.                                                |
| 404  | 34          | Няма ключова дума с това id на `/keyword/{keyword_id}` и списъка ѝ с филми. |
| 405  | 37          | Ползвали сте метод за запис на път за ключови думи.                         |
| 429  | 25          | Надхвърлили сте лимита на заявки в минута. Изчакайте `Retry-After` секунди. |
| 500  | 11          | Заявка към `/search/keyword`, която не намира нищо.                         |

Непознато id на филм или сериал на пътищата за ключови думи не дава 404. Получавате HTTP 200 с id и празен масив.

Вижте [грешки](https://amodb.dev/bg/errors/) за всеки код и [лимити на заявките](https://amodb.dev/bg/rate-limits/) за лимитите на плановете.

## Практически бележки

- Пазете `id` на ключовата дума, а не името. Името може да бъде преформулирано, id не се променя.
- Списъците с ключови думи се кешират заедно с детайлите на заглавието, за 6 часа. За страници с тагове стига седмично обновяване.
- Едно заглавие има кратък списък с тагове. За тематични страници започвайте от id на ключова дума и изброявайте заглавията ѝ в discover, а не обратното.
- Ползвайте `without_keywords`, за да махнете шума, например таг, който никога не искате на семейна страница.
- Празен масив е валиден отговор за малко познати заглавия. Скривайте реда с тагове, вместо да показвате грешка.

## Въпроси и отговори

### Защо отговорът за сериали ползва results, а за филми keywords?

Така TMDB v3 оформя отговорите и amodb го запазва, за да работят съществуващите клиенти. Филмите връщат масив keywords. Сериалите връщат същите обекти под results. Четете data.keywords ?? data.results.

### Как да намеря id на ключова дума по нейното име?

Извикайте пътя за търсене на ключови думи със заявка, например /3/search/keyword?query=heist. Той връща странициран списък с двойки id и name. Изберете точното съвпадение и запазете id.

### Мога ли да ползвам едно id на ключова дума и за филми, и за сериали?

Да. Id на ключова дума е същата стойност в discover за филми и в discover за сериали, така че with_keywords работи на двата пътя. Пазете по едно id на тема и го ползвайте за двата вида медия.

### Как да комбинирам няколко ключови думи в една заявка?

Свързвайте id в with_keywords със запетая, за да изисквате всички, или с вертикална черта, за да приемете коя да е. За изключване на id ползвайте without_keywords. Дръжте URL адреса в границите на ограничението за дължина на вашия HTTP клиент.

## Свързани страници

- [Discover API](https://amodb.dev/bg/discover/): Discover API със същите филтри като TMDB v3. Списък с филми и сериали по жанр, актьори, компания, ключова дума, година, рейтинг и продължителност със сортиране.
- [API за търсене](https://amodb.dev/bg/search/): API за търсене със същите пътища и JSON като TMDB v3. Намира филми, сериали, личности, колекции, компании и ключови думи по текст, с филтър по година.
- [API за детайли на филм](https://amodb.dev/bg/movies/): API за детайли на филм със същите пътища и JSON като TMDB v3. Един филм по id, а актьори, рейтинги и настроения през append_to_response, на 14 езика.
- [API за сериали](https://amodb.dev/bg/tv-series/): API за сериали със същите пътища и JSON като TMDB v3. Сериал по id със сезони, мрежи и следващ епизод, плюс възрастови рейтинги и доставчици за гледане.
- [Жанрове и справочни списъци](https://amodb.dev/bg/genres/): API за списък с жанрове с пътища на TMDB v3: id на жанрове за филми и сериали с преведени имена, списъци с държави, езици, длъжности, рейтинги и доставчици.
- [Бърз старт](https://amodb.dev/bg/quickstart/): Първата ви заявка към amodb: вземете ключ, поискайте детайли за филм с curl, JavaScript, Python, PHP или Go и заредете постера от img.amodb.dev. До 2 минути.

Обновено: 2026-10-18. Source: https://amodb.dev/bg/keywords/
