Skip to content
DikoAPI
API keys

Pagination

Open as Markdown

How to read long lists: limit, cursor, has_more and stable ordering.

One model

Every list is paged the same way: you send limit and cursor and you get next_cursor back.

JSON
{
  "object": "list",
  "data": [],
  "has_more": true,
  "next_cursor": "eyJ2IjoxLCJrIjoiMjAyNi0xMC0xMSJ9.k3J9mQ"
}
Field Meaning
data the items of this page
has_more whether more items follow
next_cursor cursor for the next page. In lists it is null when has_more is false; in the event stream it is always returned

limit

List Default Range
most lists 20 1 to 100
transcript segments (format=json) 200 1 to 1000
events 20 1 to 100

An invalid value returns 400 invalid_parameter with error.param: "limit".

cursor

  • A cursor is opaque: do not try to parse or build one. Send exactly what you got from next_cursor.
  • List cursors are tied to the user, the route, the sort order and the filters. If you change the filters or the sort order between pages, the API returns 400 invalid_cursor. Then start again without a cursor.
  • List cursors are meant for one paging run. Do not store them for long.
  • The event stream cursor is a position in the stream, so you can store it and continue later. cursor=latest starts from now: an empty page with the current next_cursor is returned.

Ordering

Ordering is stable: by the chosen key and then id, so items neither repeat nor go missing between pages.

List Sort key
GET /meetings created_at (default) or updated_at (sort); direction order=desc (default) or asc
GET /library/transcripts added_at; direction order
GET /library/imports created_at, newest first; lists the imports of the last 90 days
GET /events the order in which events were committed

Filter rules:

  • Repeated filters are repeated: status=ready&status=failed.
  • Dates are an RFC 3339 date or date-time. A date-time needs a time zone (2026-10-11T09:30:00Z or +03:00); a bare date such as 2026-10-11 means 00:00 UTC. Bounds are exclusive: _after means “later than”, _before means “earlier than”.
  • Bounds are compared in milliseconds, the resolution of the timestamps in responses. So you can pass back a timestamp you received (updated_after=<updated_at of the last item>) and you never get that same item again; an item that shares the millisecond of your bound is not returned either. Rows changed by one operation (archiving several meetings at once, for example) often share a single timestamp, so never rely on updated_after alone to move from one page to the next.
  • updated_after and updated_at only filter; the order of the list still follows sort and order.
  • Incremental sync. Inside one run, read the pages in order (sort=updated_at&order=asc) by following next_cursor until has_more is false: the order is the key and then id, so items that share a timestamp are neither repeated nor skipped. Use updated_after only to start the next run: send the largest updated_at you saw, moved back by a safety margin (a minute is plenty), and skip the items you have already processed by id. A page that comes back empty is not a reliable end of the run. If you must not miss any change, read GET /events instead.

Reading every item

Python
import os

import requests

BASE = "https://api.diko.app/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['DIKO_API_KEY']}"}


def paginate(path, params=None):
    params = {"limit": 100, **(params or {})}
    while True:
        response = requests.get(f"{BASE}{path}", headers=HEADERS, params=params, timeout=30)
        response.raise_for_status()
        page = response.json()
        yield from page["data"]
        if not page["has_more"]:
            return
        params["cursor"] = page["next_cursor"]


for meeting in paginate("/meetings", {"status": ["ready"]}):
    print(meeting["id"], meeting["title"])

Transcripts and revision

Pages of transcript segments carry a revision field in the list envelope. The cursor is tied to it: if the transcript changes while you page (for example because grammar corrections were approved), the API returns 409 transcript_changed. Then read the transcript again without a cursor. If you need the whole text in one call, use format=text, srt or vtt.

The event stream

GET /events uses the same model but always returns next_cursor: even when has_more is false, store it and start from it next time. Only committed events are shown, in commit order, so none is skipped.

  • Events are kept for 30 days. Without a cursor the stream starts at the oldest event still kept.
  • Diko records events only while the account has a key that is not revoked or an enabled webhook endpoint. Meetings and imports that finished earlier produce no events, so the stream does not back-fill history. Read history with the list endpoints.
  • When the page has events, next_cursor points at the last of them.
  • When the page is empty, next_cursor is the current position of the stream (never behind the cursor you sent), so a poller that stores it does not scan the same range again.
  • A cursor that is not an event cursor (not latest and not one this API gave you) returns 400 invalid_cursor.

More: Events and webhooks.

Search for a topic, an endpoint or an error code.

Search across all documentation pagesesc close