Pagination & sync
Walk large lists and sync only what changed.
Titles: cursor or page
GET /v1/titles supports two modes.
Cursor mode (default) returns titles most recently updated first, limit at a time (default 20, max 200),
with a nextCursor to continue. When nextCursor is null, you've reached the end.
curl "https://dev.app.ingenee.ai/api/v1/titles?limit=200" -H "Authorization: Bearer $INGENEE_API_KEY"
curl "https://dev.app.ingenee.ai/api/v1/titles?limit=200&cursor=eyJ1cGRhdGVk…" -H "Authorization: Bearer $INGENEE_API_KEY"Page mode starts when you pass page. It returns total, page, pageSize and totalPages, and allows
sort=title|year|runtime|updated|added with dir=asc|desc.
Incremental sync
Cursor mode is ordered by updatedAt, newest first, so an incremental sync is one loop:
async function syncTitles(since: Date, apply: (row: Title) => Promise<void>) {
let cursor: string | null = null;
do {
const url = new URL('https://dev.app.ingenee.ai/api/v1/titles');
url.searchParams.set('limit', '200');
if (cursor) url.searchParams.set('cursor', cursor);
const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.INGENEE_API_KEY}` } });
const page = await res.json();
for (const row of page.rows) {
if (new Date(row.updatedAt) <= since) return; // everything after this is older
await apply(row);
}
cursor = page.nextCursor;
} while (cursor);
}Save the time you started each run and use it as since next time.
Episodes and seasons are listed only when you ask for their type: ?type=episode or ?type=season. Without a type
filter, a series appears once and its episodes are in GET /v1/titles/{id}.
Other lists
Other lists take page and pageSize where the reference shows them, and return total. Lists without paging
parameters return the whole set.
Page-level data
For storefront sync, start at GET /v1/pages.json. It lists every published page and the URL
of each rail, and supports If-None-Match, so an unchanged index costs you a 304.