Pagination & Caching
Pagination
The pagination object is identical on all three list endpoints and is always present, even when the page is empty.
json
1{
2 "total": 42,
3 "limit": 20,
4 "offset": 0,
5 "total_pages": 3,
6 "current_page": 1,
7 "has_next": true,
8 "has_prev": false
9}| Field | Meaning |
total | Distinct rows matching every filter |
limit | Page size actually applied |
offset | Rows skipped |
total_pages | Pages at the current limit |
current_page | Derived from offset / limit, 1-based |
has_next / has_prev | Whether another page exists in that direction |
limitabove 100 is silently clamped to 100. A zero, negative, or non-numeric value falls back to 10.- A negative or non-numeric
offsetfalls back to 0. totalcounts distinct rows, so it is safe to drive an infinite scroll from it.
Walking every page:
javascript
1async function fetchAllExercises(params = {}) {
2 const items = [];
3 let offset = 0;
4 const limit = 50;
5
6 for (;;) {
7 const query = new URLSearchParams({ ...params, limit, offset });
8 const res = await fetch(
9 `https://data.kinestex.com/api/exercises/client?` + query,
10 { headers: { "x-api-key": process.env.KINESTEX_API_KEY, Language: "en" } }
11 );
12 if (!res.ok) throw new Error(`Content API ` + res.status);
13
14 const page = await res.json();
15 items.push(...page.exercises);
16 if (!page.pagination.has_next) return items;
17 offset += limit;
18 }
19}Caching
List responses are cached for up to 5 minutes, keyed per company, per language, and per exact query string, so two different filter combinations never serve each other's results. Single-item responses are cached for up to 15 minutes. Both caches are invalidated when the underlying content is edited, so in normal use you see changes quickly; allow for the window when you write tests that create content and immediately list it.
Performance tips
- Keep
include_exercisesandinclude_weeksat theirfalsedefault for browsing lists. Turn them on only for the screen that actually plays the content. - Prefer server-side filters over fetching everything and filtering client-side. Every filter listed here runs in SQL.
- Keep page sizes moderate (10 to 20 for a UI, up to 100 for a sync job).
- Use
translation_languagesas a filter when you need a fully localized catalog, rather than fetching everything and discarding items with a nulltranslation.