# API słów kluczowych

> Endpointy słów kluczowych zwracają tagi fabularne przypisane do filmu lub serialu, każdy jako ID i nazwę. Możesz sprawdzić jedno słowo kluczowe, wypisać filmy, które je mają, albo przekazać ID do discover przez with_keywords, by budować strony tematyczne. Filmy odpowiadają pod keywords, seriale pod results.

## Endpoint

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

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

Odpowiedź:

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

## Pobieranie słów kluczowych filmu

`GET /3/movie/{movie_id}/keywords` zwraca tagi fabularne jednego filmu. Słowo kluczowe to krótka fraza, na przykład temat, miejsce akcji lub rodzaj pierwowzoru, i ma numeryczne ID, które możesz ponownie użyć w [discover](https://amodb.dev/pl/discover/).

Przykład pobiera słowa kluczowe filmu, a potem prosi discover o najpopularniejsze filmy z jego pierwszym słowem kluczowym.

```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)
	}
}
```

### Parametry

| Parametr   | Gdzie | Wymagany      | Opis                                                       |
| ---------- | ----- | ------------- | ---------------------------------------------------------- |
| `movie_id` | path  | tak           | Numeryczne ID filmu, na przykład `550`.                    |
| `api_key`  | query | jeden z dwóch | Twój klucz. Użyj go albo nagłówka `Authorization: Bearer`. |

### Pola odpowiedzi

| Pole              | Typ     | Uwagi                                                                                    |
| ----------------- | ------- | ---------------------------------------------------------------------------------------- |
| `id`              | integer | ID filmu.                                                                                |
| `keywords`        | array   | Obiekty z `id` i `name`. Puste, gdy film nie ma żadnych.                                 |
| `keywords[].id`   | integer | ID słowa kluczowego. Użyj go w `with_keywords` i w poniższych ścieżkach słów kluczowych. |
| `keywords[].name` | string  | Tekst słowa kluczowego.                                                                  |

### Przykładowa odpowiedź

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

Prawdziwa odpowiedź zawiera 14 słów kluczowych. Ta jest przycięta do pierwszych 3. Nazwy słów kluczowych nie są tłumaczone, więc `language` nie ma tu wpływu.

## Słowa kluczowe serialu

`GET /3/tv/{series_id}/keywords` przyjmuje ten sam klucz i zwraca te same obiekty, ale tablica nazywa się `results`. ID w ścieżce to ID serialu, na przykład `1396`.

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

Prawdziwa odpowiedź zawiera 29 pozycji, a ta jest przycięta do pierwszych 2. Klient obsługujący oba typy mediów może czytać `data.keywords ?? data.results` i traktować je tak samo.

## Rekordy słów kluczowych i ich filmy

| Metoda i ścieżka                   | Zwraca                                                                             | Parametry          |
| ---------------------------------- | ---------------------------------------------------------------------------------- | ------------------ |
| `GET /keyword/{keyword_id}`        | `{ id, name }`                                                                     | brak               |
| `GET /keyword/{keyword_id}/movies` | Lista filmów z paginacją z `id`, `page`, `results`, `total_pages`, `total_results` | `language`, `page` |

Obie ścieżki używają numerycznego ID z tablicy słów kluczowych. Lista filmów ma ten sam kształt pozycji co inne [listy filmów](https://amodb.dev/pl/trending-lists/), w tym `genre_ids` i `poster_path`, plus `id` słowa kluczowego na górze. `include_adult` jest przyjmowane i ignorowane. Strona za `total_pages` zwraca pustą tablicę `results`. Nie ma listy seriali dla słowa kluczowego, więc dla seriali użyj `/discover/tv?with_keywords=`.

## Łączenie słów kluczowych z discover

Do wszystkiego poza zwykłą listą filtruj w [discover](https://amodb.dev/pl/discover/). Sortuje, dzieli na strony i łączy słowa kluczowe z innymi filtrami, a obejmuje seriale tak samo jak filmy.

| Cel                                             | Ciąg zapytania                                     |
| ----------------------------------------------- | -------------------------------------------------- |
| Filmy z jednym słowem kluczowym                 | `/discover/movie?with_keywords=818`                |
| Filmy z oboma z dwóch słów kluczowych           | `/discover/movie?with_keywords=818,4565`           |
| Filmy bez słowa kluczowego                      | `/discover/movie?without_keywords=818`             |
| Seriale ze słowem kluczowym                     | `/discover/tv?with_keywords=9712`                  |
| Seriale z którymkolwiek z dwóch słów kluczowych | `/discover/tv?with_keywords=818%7C9712`            |
| Jedno słowo kluczowe w obrębie gatunku          | `/discover/movie?with_keywords=818&with_genres=18` |

Przecinek między ID oznacza wszystkie. Wpisz kreskę pionową między ID, jak w `with_keywords=818|4565`, by dopasować dowolne. Wyniki discover są w cache na edge przez 30 minut.

## Wyszukiwanie ID słowa kluczowego

Aby zamienić tekst na ID, wywołaj `GET /3/search/keyword?query=heist`. Zwraca listę z paginacją par `id` i `name`, po 20 na stronę. Pełny zestaw ścieżek wyszukiwania zobacz w [wyszukiwanie](https://amodb.dev/pl/search/). Wyszukiwanie słowa kluczowego, które nic nie znajduje, obecnie odpowiada 500 z `status_code` 11 zamiast pustej listy. Odpowiedzi wyszukiwania są w cache przez 10 minut, ale każde wywołanie nadal liczy się do twoich żądań na minutę, więc w polu z podpowiedziami stosuj debounce.

## Błędy

| HTTP | status_code | Kiedy                                                                               |
| ---- | ----------- | ----------------------------------------------------------------------------------- |
| 401  | 7           | Brakuje klucza lub jest błędny.                                                     |
| 402  | 36          | Okres planu dobiegł końca.                                                          |
| 404  | 34          | Brak słowa kluczowego o tym ID w `/keyword/{keyword_id}` i jego liście filmów.      |
| 405  | 37          | Użyto metody zapisu na ścieżce słowa kluczowego.                                    |
| 429  | 25          | Przekroczono limit żądań na minutę. Poczekaj tyle sekund, ile podaje `Retry-After`. |
| 500  | 11          | Zapytanie `/search/keyword`, które nic nie znajduje.                                |

Nieznane ID filmu lub serialu w ścieżkach słów kluczowych to nie 404. Dostajesz HTTP 200 z ID i pustą tablicą.

Wszystkie kody zobacz w [błędy](https://amodb.dev/pl/errors/), a limity planów w [limity żądań](https://amodb.dev/pl/rate-limits/).

## Praktyczne uwagi

- Zapisuj `id` słowa kluczowego, a nie nazwę. Nazwę można przeformułować, ID się nie zmienia.
- Listy słów kluczowych są w cache razem ze szczegółami tytułu, przez 6 godzin. Cotygodniowe odświeżanie stron z tagami w zupełności wystarcza.
- Pojedynczy tytuł ma krótką listę tagów. Dla stron tematycznych zacznij od ID słowa kluczowego i wypisz jego tytuły w discover, a nie odwrotnie.
- Użyj `without_keywords`, by usunąć szum, na przykład tag, którego nigdy nie chcesz na stronie rodzinnej.
- Pusta tablica to poprawna odpowiedź dla mało znanych tytułów. Ukryj wiersz tagów zamiast pokazywać błąd.

## Pytania i odpowiedzi

### Dlaczego odpowiedź dla seriali używa results, a filmy keywords?

Tak TMDB v3 kształtuje odpowiedzi, a amodb to zachowuje, by istniejące klienty działały. Filmy zwracają tablicę keywords. Seriale zwracają te same obiekty pod results. Odczytaj data.keywords ?? data.results.

### Jak znaleźć ID słowa kluczowego po jego nazwie?

Wywołaj ścieżkę wyszukiwania słów kluczowych z zapytaniem, na przykład /3/search/keyword?query=heist. Zwraca listę z paginacją par id i name. Wybierz dokładne dopasowanie i zapisz id.

### Czy mogę użyć jednego ID słowa kluczowego dla filmów i seriali?

Tak. ID słowa kluczowego to ta sama wartość w discover dla filmów i w discover dla seriali, więc with_keywords działa na obu ścieżkach. Zapisz jedno ID na temat i używaj go dla obu typów mediów.

### Jak połączyć kilka słów kluczowych w jednym zapytaniu?

Połącz ID w with_keywords przecinkiem, by wymagać wszystkich, albo kreską pionową, by zaakceptować dowolne. Do wykluczania ID użyj without_keywords. Trzymaj URL w limicie długości, który dopuszcza twój klient HTTP.

## Powiązane strony

- [Discover API](https://amodb.dev/pl/discover/): Discover API z tymi samymi filtrami co TMDB v3. Wypisuj filmy i seriale według gatunku, obsady, firmy, słowa kluczowego, roku, oceny, czasu trwania i dostawcy.
- [API wyszukiwania](https://amodb.dev/pl/search/): API wyszukiwania z tymi samymi ścieżkami i JSON co TMDB v3. Znajdź filmy, seriale, osoby, kolekcje, firmy i słowa kluczowe po tekście, z filtrem roku.
- [API szczegółów filmu](https://amodb.dev/pl/movies/): API szczegółów filmu z tymi samymi ścieżkami i JSON co TMDB v3. Pobierz film po ID, dołącz obsadę, oceny i nastroje przez append_to_response, 14 języków.
- [API szczegółów serialu](https://amodb.dev/pl/tv-series/): API szczegółów serialu z tymi samymi ścieżkami i JSON co TMDB v3. Serial po ID z sezonami, sieciami, klasyfikacją wiekową i dostawcami streamingu.
- [Gatunki i słowniki](https://amodb.dev/pl/genres/): Lista gatunków API ze ścieżkami TMDB v3: ID gatunków filmów i seriali z nazwami w 14 językach oraz słowniki krajów, języków, stanowisk i dostawców streamingu.
- [Szybki start](https://amodb.dev/pl/quickstart/): Pierwsze wywołanie amodb: zdobądź klucz, pobierz szczegóły filmu w curl, JavaScript, Python, PHP lub Go, potem załaduj plakat z img.amodb.dev. Poniżej 2 minut.

Zaktualizowano: 2026-10-18. Source: https://amodb.dev/pl/keywords/
