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.

On this page