Translations API
The translations endpoints return every language version of a record in one response: title or name, overview, tagline and homepage for movies and series, name and overview for episodes. Each row carries iso_639_1, iso_3166_1 and english_name. Use it to read languages that the language parameter does not serve or to build a fallback chain.
Get translations for a movie
GET /3/movie/{movie_id}/translations returns one row per language that has text for the movie. Each row holds a data object with the translated fields. The call takes no language parameter, because the whole point is to see all languages at once.
The example finds the Russian row and prints its title and the start of its overview.
curl -s "https://api.amodb.dev/3/movie/550/translations" \
-H "Authorization: Bearer $AMODB_KEY"const url = 'https://api.amodb.dev/3/movie/550/translations';
const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.AMODB_KEY}` } });
if (!res.ok) throw new Error(`amodb returned ${res.status}`);
const { translations } = await res.json();
const ru = translations.find((t) => t.iso_639_1 === 'ru');
console.log(ru ? `${ru.data.title}: ${ru.data.overview.slice(0, 80)}` : 'no Russian row');import os
import requests
r = requests.get(
"https://api.amodb.dev/3/movie/550/translations",
headers={"Authorization": f"Bearer {os.environ['AMODB_KEY']}"},
timeout=10,
)
r.raise_for_status()
ru = next((t for t in r.json()["translations"] if t["iso_639_1"] == "ru"), None)
print(f"{ru['data']['title']}: {ru['data']['overview'][:80]}" if ru else "no Russian row")<?php
$ch = curl_init('https://api.amodb.dev/3/movie/550/translations');
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");
}
foreach (json_decode($body, true)['translations'] as $t) {
if ($t['iso_639_1'] === 'ru') {
echo $t['data']['title'], ': ', mb_substr($t['data']['overview'], 0, 80), PHP_EOL;
exit;
}
}
echo 'no Russian row', PHP_EOL;package main
import (
"encoding/json"
"fmt"
"net/http"
"os"
"time"
)
type Translations struct {
Translations []struct {
ISO6391 string `json:"iso_639_1"`
Data struct {
Title string `json:"title"`
Overview string `json:"overview"`
} `json:"data"`
} `json:"translations"`
}
func main() {
req, _ := http.NewRequest("GET", "https://api.amodb.dev/3/movie/550/translations", 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 t Translations
if err := json.NewDecoder(res.Body).Decode(&t); err != nil {
panic(err)
}
for _, row := range t.Translations {
if row.ISO6391 == "ru" {
text := []rune(row.Data.Overview)
if len(text) > 80 {
text = text[:80]
}
fmt.Printf("%s: %s\n", row.Data.Title, string(text))
return
}
}
fmt.Println("no Russian row")
}Parameters
| Parameter | In | Required | Description |
|---|---|---|---|
movie_id | path | yes | Numeric movie id, for example 550. |
api_key | query | one of two | Your key. Use this or the Authorization: Bearer header. |
Response fields
| Field | Type | Notes |
|---|---|---|
id | integer | The movie id. |
translations | array | One row per language that has text, sorted by language code. Movie 550 returns 50 rows. |
translations[].iso_3166_1 | string | Country code that goes with the language, such as US for en or BR for pt. For languages outside the 14 served ones it repeats the language code in capitals. |
translations[].iso_639_1 | string | Language code such as ru or pt. Unique in the array. |
translations[].name | string | The language written in that language. |
translations[].english_name | string | The language name in English. |
translations[].data | object | The translated fields. Keys depend on the resource, see the table below. |
Example response
Two of the 50 rows are shown, and the overviews are cut.
{
"id": 550,
"translations": [
{
"iso_3166_1": "US",
"iso_639_1": "en",
"name": "English",
"english_name": "English",
"data": {
"title": "Fight Club",
"overview": "A ticking-time-bomb insomniac and a slippery soap salesman channel primal male aggression into a shocking new form of therapy....",
"homepage": "https://www.20thcenturystudios.com/movies/fight-club",
"tagline": "Mischief. Mayhem. Soap.",
"runtime": 0
}
},
{
"iso_3166_1": "RU",
"iso_639_1": "ru",
"name": "Русский",
"english_name": "Russian",
"data": {
"title": "Бойцовский клуб",
"overview": "Сотрудник страховой компании страдает хронической бессонницей и отчаянно пытается вырваться из мучительно скучной жизни. Однажд...",
"homepage": "https://www.20thcenturystudios.com/movies/fight-club",
"tagline": "«Интриги. Хаос. Мыло»",
"runtime": 0
}
}
]
}In amodb runtime is always 0 in a translation row. Read the runtime from the movie details record.
Translation endpoints and their data keys
All paths share the base https://api.amodb.dev/3. Every one returns id and a translations array of the row shape above. Only the keys inside data change.
| Method and path | data keys |
|---|---|
GET /movie/{movie_id}/translations | title, overview, homepage, tagline, runtime (always 0) |
GET /tv/{series_id}/translations | name, overview, homepage, tagline |
GET /tv/{series_id}/season/{season_number}/translations | none, the array is always empty |
GET /tv/{series_id}/season/{season_number}/episode/{episode_number}/translations | name, overview |
Series records list about as many languages as movies. Episode rows cover only the served languages that have text for that episode, from 2 to 14 in the samples checked. Treat a missing key like an empty value, and ignore keys you do not know. See TV series for the parent records.
amodb does not offer translations for people or collections. A person biography follows the language parameter of the person details call, and a collection overview comes as stored.
Fall back when text is missing
A title can exist in 14 languages and still have an empty overview in the one your user picked. Walk a chain of languages, take the first non-empty value and remember which language it came from.
function pickText(translations, wanted, field) {
for (const code of [...wanted, 'en']) {
const row = translations.find((t) => t.iso_639_1 === code);
const value = row?.data?.[field];
if (value) return { code, value };
}
return null;
}
// Prefer Ukrainian, then Russian, then English.
// const hit = pickText(translations, ['uk', 'ru'], 'overview');For a series, pass 'name' as the field instead of 'title'. Mark text from a fallback language in your interface, so the user knows why a Ukrainian page shows an English synopsis.
Translations or the language parameter
| Need | Use |
|---|---|
| Show one language to one user | language on the details call |
| List all languages of a title in an editor | This endpoint |
Read a language that language does not serve, such as ja | This endpoint, pick the row by iso_639_1 |
| Check which of the 14 served languages have text | This endpoint, compare iso_639_1 |
| Build alternate language links for a page | This endpoint, read the codes present |
For the tags language accepts, see languages. Any other tag falls back to English on a details call.
Errors
| HTTP | status_code | When |
|---|---|---|
| 401 | 7 | The key is missing or wrong. |
| 402 | 36 | The plan period has ended. |
| 404 | 34 | No season or episode with that id, or an id that is not a number. |
| 405 | 37 | You used a write method on a translations path. |
| 429 | 25 | You went over your requests per minute. Wait for the Retry-After seconds. |
A movie or series id that does not exist is not an error on this path: it answers 200 with "translations": [], while the details path answers 404. More on errors and rate limits.
Practical notes
- One call replaces up to 14 details calls. Use it when you need more than two languages of the same title.
- The rows are sorted by language code, which is not a priority order. Pick rows by
iso_639_1, never by array position. - Details-type calls are cached at the edge for 6 hours, so a client cache of the same length costs nothing in freshness.
- Original titles in other scripts, such as Japanese or Korean, are always available in
original_titleandoriginal_nameon the details record. - To add translations to a details call, pass
append_to_response=translationsand read the same array from the reply. It works for movies, series and episodes. The appended block has noid.