# API מילות מפתח

> נקודות הקצה של מילות מפתח מחזירות את תגיות העלילה שמצורפות לסרט או לסדרה, כל אחת כמזהה ושם. אפשר לחפש מילת מפתח אחת, להציג את הסרטים שנושאים אותה, או להעביר את המזהים ל-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` מחזיר את תגיות העלילה של סרט אחד. מילת מפתח היא ביטוי קצר כמו נושא, התרחשות או סוג מקור, ויש לה מזהה מספרי שאפשר להשתמש בו שוב בעמוד [גילוי](https://amodb.dev/he/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` | נתיב   | כן         | מזהה סרט מספרי, למשל `550`.                              |
| `api_key`  | שאילתה | אחד משניים | המפתח שלכם. השתמשו בו או בכותרת `Authorization: Bearer`. |

### שדות התגובה

| שדה               | סוג     | הערות                                                                   |
| ----------------- | ------- | ----------------------------------------------------------------------- |
| `id`              | integer | מזהה הסרט.                                                              |
| `keywords`        | array   | אובייקטים עם `id` ו-`name`. ריק כשלסרט אין מילות מפתח.                  |
| `keywords[].id`   | integer | מזהה מילת המפתח. השתמשו בו ב-`with_keywords` ובנתיבי מילות המפתח שלמטה. |
| `keywords[].name` | string  | הטקסט של מילת המפתח.                                                    |

### תגובה לדוגמה

```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`. המזהה בנתיב הוא מזהה הסדרה, למשל `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` |

שני הנתיבים משתמשים במזהה המספרי ממערך מילות מפתח. רשימת הסרטים נותנת את אותו מבנה פריט כמו [רשימות סרטים](https://amodb.dev/he/trending-lists/) אחרות, כולל `genre_ids` ו-`poster_path`, בתוספת ה-`id` של מילת המפתח בראש. `include_adult` מתקבל ומתעלמים ממנו. עמוד אחרי `total_pages` מחזיר מערך `results` ריק. אין רשימת סדרות למילת מפתח, ולכן לסדרות השתמשו ב-`/discover/tv?with_keywords=`.

## שילוב מילות מפתח עם discover

לכל דבר מעבר לרשימה פשוטה, סננו בעמוד [גילוי](https://amodb.dev/he/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` |

פסיק בין מזהים פירושו את כולם. כתבו קו אנכי בין מזהים, כמו ב-`with_keywords=818|4565`, כדי להתאים לכל אחד מהם. תוצאות discover נשמרות בקצה במטמון 30 דקות.

## מציאת מזהה מילת מפתח

כדי להפוך טקסט למזהה, קראו ל-`GET /3/search/keyword?query=heist`. הוא מחזיר רשימה מדורגת של זוגות `id` ו-`name`, 20 בעמוד. את כל נתיבי החיפוש ראו בעמוד [חיפוש](https://amodb.dev/he/search/). חיפוש מילת מפתח שלא מתאים לשום דבר עונה כרגע 500 עם `status_code` 11 במקום רשימה ריקה. תשובות חיפוש נשמרות במטמון 10 דקות, אבל כל קריאה עדיין נספרת בבקשות שלכם לדקה, ולכן השהו את הקלט בתיבת הקלדה.

## שגיאות

| HTTP | status_code | מתי                                                                      |
| ---- | ----------- | ------------------------------------------------------------------------ |
| 401  | 7           | המפתח חסר או שגוי.                                                       |
| 402  | 36          | תקופת המסלול הסתיימה.                                                    |
| 404  | 34          | אין מילת מפתח עם המזהה הזה ב-`/keyword/{keyword_id}` וברשימת הסרטים שלה. |
| 405  | 37          | השתמשתם בשיטת כתיבה בנתיב של מילת מפתח.                                  |
| 429  | 25          | חרגתם מהבקשות שלכם לדקה. המתינו `Retry-After` שניות.                     |
| 500  | 11          | שאילתת `/search/keyword` שלא מתאימה לשום דבר.                            |

מזהה סרט או סדרה לא מוכר בנתיבי מילות המפתח אינו 404. מקבלים HTTP 200 עם המזהה ומערך ריק.

את כל הקודים ראו בעמוד [שגיאות](https://amodb.dev/he/errors/), ואת מגבלות המסלולים בעמוד [מגבלות קצב](https://amodb.dev/he/rate-limits/).

## הערות מעשיות

- שמרו את ה-`id` של מילת המפתח, לא את השם. שם יכול להיות מנוסח מחדש, מזהה לא משתנה.
- רשימות מילות מפתח נשמרות במטמון יחד עם פרטי הכותר, 6 שעות. רענון שבועי לעמודי תגיות מספיק בהחלט.
- לכותר בודד יש רשימת תגיות קצרה. בעמודי נושא התחילו ממזהה מילת מפתח והציגו את הכותרים שלה ב-discover, ולא להפך.
- השתמשו ב-`without_keywords` כדי להסיר רעש, למשל תגית שאתם לא רוצים לראות בעמוד משפחתי.
- מערך ריק הוא תשובה תקפה לכותרים לא מוכרים. הסתירו את שורת התגיות במקום להציג שגיאה.

## שאלות ותשובות

### למה תגובת סדרות משתמשת ב-results וסרטים ב-keywords?

כך TMDB v3 מעצב אותן, ו-amodb שומר על כך כדי שלקוחות קיימים יעבדו. סרטים מחזירים מערך keywords. סדרות מחזירות את אותם אובייקטים תחת results. קראו data.keywords ?? data.results.

### איך מוצאים מזהה של מילת מפתח לפי השם שלה?

קראו לנתיב החיפוש של מילות מפתח עם query, למשל /3/search/keyword?query=heist. הוא מחזיר רשימה מדורגת של זוגות id ו-name. בחרו את ההתאמה המדויקת ושמרו את ה-id.

### אפשר להשתמש באותו מזהה מילת מפתח לסרטים ולסדרות?

כן. מזהה מילת מפתח הוא אותו ערך ב-discover של סרטים וב-discover של סדרות, ולכן with_keywords עובד בשני הנתיבים. שמרו מזהה אחד לכל נושא והשתמשו בו שוב לשני סוגי המדיה.

### איך משלבים כמה מילות מפתח בשאילתה אחת?

חברו מזהים ב-with_keywords עם פסיק כדי לדרוש את כולם, או עם קו אנכי כדי לקבל כל אחד מהם. השתמשו ב-without_keywords כדי להחריג מזהים. שמרו על כתובת בתוך מגבלת האורך של לקוח ה-HTTP שלכם.

## עמודים קשורים

- [API גילוי](https://amodb.dev/he/discover/): Discover API עם אותם מסננים כמו TMDB v3. הציגו סרטים וסדרות לפי ז'אנר, שחקנים, חברה, מילת מפתח, שנה, דירוג, משך וספק סטרימינג, עם מיון ודפדוף בתוצאות.
- [API חיפוש](https://amodb.dev/he/search/): API חיפוש עם אותם נתיבים ו-JSON כמו TMDB v3. מצאו סרטים, סדרות, אנשים, אוספים, חברות ומילות מפתח לפי טקסט, עם סינון לפי שנה ועימוד של 20 תוצאות בעמוד.
- [API פרטי סרט](https://amodb.dev/he/movies/): API פרטי סרט עם אותם נתיבים ו-JSON כמו TMDB v3. קבלו סרט לפי מזהה, הוסיפו קרדיטים, דירוגים, מצבי רוח ופסקולים עם append_to_response, ב-14 שפות.
- [API סדרות טלוויזיה](https://amodb.dev/he/tv-series/): API סדרות טלוויזיה עם אותם נתיבים ו-JSON כמו TMDB v3. קבלו סדרה לפי מזהה ב-GET /3/tv/{series_id} עם עונות, רשתות והפרק הבא, וגם סיווגי גיל וספקי צפייה.
- [ז'אנרים ורשימות חיפוש](https://amodb.dev/he/genres/): API ז'אנרים עם נתיבי TMDB v3: מזהי ז'אנרים של סרטים וסדרות עם שמות מתורגמים, ובנוסף רשימות של מדינות, שפות, תפקידים, דירוגי גיל וספקי סטרימינג.
- [מדריך למתחילים](https://amodb.dev/he/quickstart/): בצעו את הקריאה הראשונה ל-amodb: קבלו מפתח, בקשו פרטי סרט ב-curl, JavaScript, Python, PHP או Go, ואז טענו את הפוסטר מ-img.amodb.dev. פחות מ-2 דקות.

עודכן: 2026-10-18. Source: https://amodb.dev/he/keywords/
