Meetso API

Pagination

Cursor-based, stable under inserts. The same model used by Stripe and GitHub.

List endpoints (currently just GET /public/v1/meetings) use cursor pagination. You get back a page of results plus an opaque cursor that points at the next page; pass it back as the cursor query param to advance.

The contract

Every list response has this shape:

{
  "data": [ /* page of items */ ],
  "pagination": {
    "next_cursor": "eyJzIjoi…",
    "has_more": true
  }
}
  • next_cursor — opaque base64url string. Pass it as ?cursor=… on the next request. null when there are no more pages.
  • has_moretrue when more rows exist past this page; false on the last page.

Iterating

async function* iterMeetings(apiKey: string) {
  let cursor: string | undefined;
  while (true) {
    const url = new URL('https://api.meetso.ai/public/v1/meetings');
    url.searchParams.set('limit', '50');
    if (cursor) url.searchParams.set('cursor', cursor);

    const res = await fetch(url, {
      headers: { Authorization: `Bearer ${apiKey}` },
    });
    if (!res.ok) {
      const { error } = await res.json();
      throw new Error(`${error.code}: ${error.message}`);
    }
    const body = await res.json();

    yield* body.data;

    if (!body.pagination.has_more) break;
    cursor = body.pagination.next_cursor;
  }
}

Why cursors, not offsets

Offset pagination (?page=2) is unstable when the underlying data changes between requests — if a new row is inserted at position 7 between fetching page 1 and page 2, you'd see the same row twice. The cursor encodes the last seen (start_time, id) pair, so the next page resumes from exactly where the previous one ended regardless of inserts.

This matches how Stripe, GitHub, and Linear paginate.

Cursor opacity

Don't try to parse, decode, or generate cursors yourself. The encoding is part of the public contract but the contents are not — we may extend it (e.g., to encode filter parameters) without warning. Round-trip the value as-is.

Page size

Pass limit to control page size. Defaults are documented per endpoint, max is 100.

Edge cases

The filter changes mid-pagination. If you're paginating with time_range=past and a meeting transitions from upcoming to past between requests (i.e., its endTime crosses now), it can appear in a later page even though it would have been past the cursor under the old filter. Cursors don't snapshot the filter; they snapshot the sort key. For most ingestion use cases this is fine — you'll just see the meeting in a subsequent run.

A row is created during pagination. If you're walking from newest to oldest and a brand-new meeting is created mid-iteration, you won't see it in this run (its start_time is past the cursor). Run the iteration again from the beginning to pick it up.

A row is deleted during pagination. If a row is deleted between your fetch of a cursor and your next request, the next request silently skips it — no error. Cursor pagination is naturally tolerant to deletes.

On this page