Lists and pagination
Every list in the API has the same shape: the catalog and search, charts, collections, cast, media, filmographies. Learn it once and you can read any list.
The shape of a list
curl -G -H "X-API-Key: $KINODATA_KEY" \
--data-urlencode "q=matrix" \
--data-urlencode "limit=3" \
--data-urlencode "fields=title,year,rating_imdb" \
--data-urlencode "lang=en" \
"https://api.kinodata.space/v1.3/titles"{
"has_more": true,
"items": [
{
"imdb_id": "tt0133093",
"kp_id": "301",
"tmdb_id": "603",
"tmdb_tv_id": null,
"kinorium_id": "116780",
"title_en": "The Matrix",
"year": 1999,
"rating_imdb": 8.7
},
{
"imdb_id": "tt0234215",
"kp_id": "299",
"tmdb_id": "604",
"tmdb_tv_id": null,
"kinorium_id": "190315",
"title_en": "The Matrix Reloaded",
"year": 2003,
"rating_imdb": 7.2
},
{
"imdb_id": "tt0242653",
"kp_id": "316",
"tmdb_id": "605",
"tmdb_tv_id": null,
"kinorium_id": "196883",
"title_en": "The Matrix Revolutions",
"year": 2003,
"rating_imdb": 6.7
}
],
"limit": 3,
"offset": 0,
"total": null
}
| field | what it is |
|---|---|
items | The items of the list. |
total | How many items there are in total. null when the API doesn't count them; see below. |
limit | Items per page. If you asked for more than allowed, this is the real number. |
offset | How many items were skipped from the start. |
has_more | Whether there is a next page. |
next_cursor | The cursor for the next page. Only when you page with a cursor. |
The resource's own fields come alongside: roles on cast and filmographies, counts on relations and texts, collection on a collection.
When total is null
There are two kinds of lists.
- The set is defined by the URL: a title's cast, its relations and media, a person's filmography, a collection. Such a set is finite, and
totalis a number. - The set is defined by the query: the catalog and search, the top chart, hidden gems, people search. Here
totalisnull: an exact count of a filtered set would mean a second pass over the whole database on every page. Usehas_moreto tell whether there's more. Rating divergence and the release calendar do counttotal, filters included.
Items per page
| list | default | maximum |
|---|---|---|
| Catalog and search, charts, discovery feeds, release calendar, collections, people search | 50 | 50 |
| Cast, media, texts, relations, episodes, filmography, shared titles | 1000 | 1000 |
| Sections, when a list is split into them | 10 per section | 50 per section |
A set defined by the URL comes back whole: it is the answer. A set defined by the query is sorted, and a page holds its top.
limit is a whole number from 1, offset from 0. A number above the maximum isn't an error: the API lowers it and returns the real value in limit. limit=5000 on the catalog gives "limit": 50. Zero, a negative number or a non-number returns 400.
Pages: offset
?limit=50&offset=100offset is how many items to skip. The next page is offset plus limit, for as long as has_more is true.
Deep paging: cursor
For long runs through the catalog, /titles, use a cursor: it doesn't drift when the database changes while you page. Send an empty cursor= and the response gets a next_cursor:
curl -G -H "X-API-Key: $KINODATA_KEY" \
--data-urlencode "sort=-rating_imdb" \
--data-urlencode "votes_imdb.gte=100000" \
--data-urlencode "limit=2" \
--data-urlencode "fields=title,rating_imdb" \
--data-urlencode "cursor=" \
"https://api.kinodata.space/v1.3/titles"{
"has_more": true,
"items": [
{
"imdb_id": "tt0903747",
"kp_id": "404900",
"tmdb_id": null,
"tmdb_tv_id": "1396",
"kinorium_id": "400796",
"title_ru": "Во все тяжкие",
"title_en": "Breaking Bad",
"rating_imdb": 9.5
},
{
"imdb_id": "tt5491994",
"kp_id": "1007472",
"tmdb_id": null,
"tmdb_tv_id": "68595",
"kinorium_id": "1605088",
"title_ru": "Планета Земля 2",
"title_en": "Planet Earth II",
"rating_imdb": 9.4
}
],
"limit": 2,
"next_cursor": "eyJzIjoicmF0aW5nX2ltZGIiLCJkIjp0cnVlLCJ2IjoiOS40MCIsImlkIjoyMjA4MDF9",
"total": null
}
Pass next_cursor to the next request with the same parameters until it comes back null. The cursor works in the /titles catalog and in the feeds built on it, the top chart and hidden gems. Other lists page with offset and answer cursor with 400.
sort=random can't be paged: a random order has no next page. cursor and offset with it return 400; just repeat the request for a fresh draw.
Sections
Lists whose items differ by one property come split into sections. Each section is a list itself, with the same fields and a label in both languages:
curl -G -H "X-API-Key: $KINODATA_KEY" \
--data-urlencode "limit=1" \
--data-urlencode "fields=title" \
"https://api.kinodata.space/v1.3/titles/kp/301/relations"{
"counts": {
"reference": 86,
"referenced_in": 672,
"related": 9,
"similar": 74
},
"has_more": false,
"items": [
{
"has_more": true,
"items": [
{
"imdb_id": "tt1375666",
"kp_id": "447301",
"tmdb_id": "27205",
"tmdb_tv_id": null,
"kinorium_id": "472809",
"title_ru": "Начало",
"title_en": "Inception"
}
],
"label_en": "Similar",
"label_ru": "Похожие",
"relation": "similar",
"total": 74
},
{
"has_more": true,
"items": [
{
"imdb_id": "tt0366179",
"kp_id": "63744",
"tmdb_id": "24358",
"tmdb_tv_id": null,
"kinorium_id": null,
"title_ru": "Аниматрица: Второе возрождение – Часть 1",
"title_en": "The Second Renaissance Part I"
}
],
"label_en": "Related",
"label_ru": "Связанные",
"relation": "related",
"total": 9
},
{
"has_more": true,
"items": [
{
"imdb_id": "tt1431045",
"kp_id": "462360",
"tmdb_id": "293660",
"tmdb_tv_id": null,
"kinorium_id": "485426",
"title_ru": "Дэдпул",
"title_en": "Deadpool"
}
],
"label_en": "Referenced in",
"label_ru": "Упоминается в",
"relation": "referenced_in",
"total": 672
},
{
"has_more": true,
"items": [
{
"imdb_id": "tt0060196",
"kp_id": "349",
"tmdb_id": "429",
"tmdb_tv_id": null,
"kinorium_id": "56474",
"title_ru": "Хороший, плохой, злой",
"title_en": "The Good, the Bad and the Ugly"
}
],
"label_en": "References",
"label_ru": "Отсылки к",
"relation": "reference",
"total": 86
}
],
"limit": 1,
"offset": 0,
"total": 4
}
| list | default sections | other group values |
|---|---|---|
Cast, /titles/{type}/{id}/cast | by role: role | none |
Texts, /titles/{type}/{id}/texts | by kind: kind | none |
Relations, /titles/{type}/{id}/relations | by relation: relation | none |
Media, /titles/{type}/{id}/media | no sections | type, class, language |
Filmography, /persons/{type}/{id}/filmography | no sections | role |
Episodes, /titles/{type}/{id}/episodes | no sections | season: a per-season summary |
In a sectioned list limit applies to each section, and a section's total is its real size. For a flat list pass group=none. To page through one section, narrow the list to it: role=actor, kind=fact, relation=similar.
A sectioned list can't be paged: the sections share no single sequence. offset without narrowing returns 400:
curl -G -H "X-API-Key: $KINODATA_KEY" \
--data-urlencode "limit=2" \
--data-urlencode "offset=2" \
"https://api.kinodata.space/v1.3/titles/kp/447301/cast"{
"error": {
"code": "invalid_request",
"message": "grouped lists have no single sequence to page through — narrow to one value to page inside it, or ask for group=none",
"field": "offset"
}
}
Only the fields you need
The fields parameter keeps only what you list.
- On a title card the names are card blocks:
fields=title,ratings. You can also drop what you don't need:fields=-akas,-tags. The two can't be mixed in one parameter:fields=title,-akasreturns400. - In lists the names are list item fields:
fields=title,year,rating_imdborfields=-genres,-countries.titlekeepstitle_ruandtitle_en,poster_urlkeepsposter_url_ruandposter_url_en.
A title's IDs always come back, even if you didn't list them: without them there's nothing to link the item to. Fields keep the same order as without fields. An unknown name returns 400 with the list of allowed names.
fields works on the title card, in every list of titles (the catalog, collections, relations, filmographies, shared titles, discovery feeds and the release calendar) and in people search. Cast, media, texts and episodes don’t take it: there fields returns 400.
Next
- Filters and sorting: how to pick and order items.
- Catalog and search: the main list in the API.