# Puslapiavimas

> Kaip skaityti ilgus sąrašus: limit, cursor, has_more ir stabilus rūšiavimas.

Šaltinis: https://diko.app/api-docs/puslapiavimas

## Vienodas modelis

Visi sąrašai puslapiuojami vienodai. Siunčiate `limit` ir `cursor`, o atsakyme gaunate `next_cursor`.

```json
{
  "object": "list",
  "data": [],
  "has_more": true,
  "next_cursor": "eyJ2IjoxLCJrIjoiMjAyNi0xMC0xMSJ9.k3J9mQ"
}
```

| Laukas | Reikšmė |
|---|---|
| `data` | šio puslapio elementai |
| `has_more` | ar yra daugiau elementų |
| `next_cursor` | kito puslapio žymeklis. Sąrašuose jis yra `null`, kai `has_more` yra `false`; įvykių sraute grąžinamas visada |

> **Svarbu:**
> Remkitės `has_more`, o ne puslapio dydžiu. Puslapis gali būti trumpesnis už `limit`, o `has_more` vis tiek bus `true`.

## limit

| Sąrašas | Numatytasis | Intervalas |
|---|---|---|
| dauguma sąrašų | 20 | 1–100 |
| transkripto segmentai (`format=json`) | 200 | 1–1000 |
| įvykiai | 20 | 1–100 |

Netinkama reikšmė grąžina 400 [`invalid_parameter`](https://diko.app/api-docs/klaidos.md#invalid_parameter) su `error.param: "limit"`.

## cursor

- Žymeklis yra **neskaidrus**: nebandykite jo skaidyti ar kurti. Siųskite tiksliai tai, ką gavote iš `next_cursor`.
- Sąrašų žymekliai pririšti prie naudotojo, maršruto, rūšiavimo ir filtrų. Jei tarp puslapių pakeisite filtrus ar rūšiavimą, API grąžins 400 [`invalid_cursor`](https://diko.app/api-docs/klaidos.md#invalid_cursor). Tada pradėkite iš naujo be `cursor`.
- Sąrašų žymekliai skirti vienam puslapiavimo ciklui. Nesaugokite jų ilgam.
- **Įvykių srauto žymeklis** yra pozicija sraute, todėl jį galite saugoti ir pratęsti vėliau. `cursor=latest` pradeda nuo dabar: grąžinamas tuščias puslapis su dabartiniu `next_cursor`.

## Rūšiavimas

Rūšiavimas stabilus: pagal pasirinktą rūšiavimo lauką ir `id`. Todėl elementai nesikartoja ir nepraleidžiami tarp puslapių.

| Sąrašas | Rūšiavimo laukas |
|---|---|
| `GET /meetings` | `created_at` (numatyta) arba `updated_at` (`sort`); kryptis `order=desc` (numatyta) arba `asc` |
| `GET /library/transcripts` | `added_at`; kryptis `order` |
| `GET /library/imports` | `created_at`, naujausi pirma; rodomi pastarųjų 90 dienų importai |
| `GET /events` | įvykių užfiksavimo tvarka |

Filtrų taisyklės:

- **Kartotiniai filtrai** kartojami: `status=ready&status=failed`.
- **Datos** yra RFC 3339 data arba data ir laikas. Datai su laiku reikia laiko juostos (`2026-10-11T09:30:00Z` arba `+03:00`). Data be laiko, pavyzdžiui, `2026-10-11`, reiškia 00:00 UTC. Ribos išskirtinės: `_after` reiškia „vėliau nei“, `_before` – „anksčiau nei“.
- **Ribos lyginamos milisekundėmis**, tokia pat skiriamąja geba kaip ir atsakymų laiko žymos. Todėl gautą laiko žymą (`updated_after=<paskutinio elemento updated_at>`) galite perduoti atgal ir to paties elemento negausite dar kartą. Elementas, turintis tą pačią milisekundę kaip jūsų riba, taip pat negrąžinamas. Vienos operacijos pakeistos eilutės (pavyzdžiui, kelių susitikimų archyvavimas) dažnai turi vieną laiko žymą. Todėl pereidami nuo puslapio prie puslapio niekada nesiremkite vien `updated_after`.
- `updated_after` ir `updated_at` tik filtruoja; sąrašo tvarką vis tiek lemia `sort` ir `order`.
- **Inkrementinis sinchronizavimas.** Vieno ciklo metu skaitykite puslapius iš eilės (`sort=updated_at&order=asc`). Sekite `next_cursor`, kol `has_more` tampa `false`. Tvarką lemia rūšiavimo laukas, o tada `id`, todėl tą pačią laiko žymą turintys elementai nesikartoja ir nepraleidžiami. `updated_after` naudokite tik **kitam** ciklui pradėti. Siųskite didžiausią matytą `updated_at`, pastumtą atgal saugos atsarga (užtenka minutės). Jau apdorotus elementus praleiskite pagal `id`. Tuščias puslapis nėra patikima ciklo pabaiga. Jei negalite praleisti nė vieno pakeitimo, skaitykite [`GET /events`](https://diko.app/api-docs/webhooks.md#%C4%AFvyki%C5%B3-srautas-kaip-alternatyva).

## Visų elementų nuskaitymas

**Python**

```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"])
```

**TypeScript**

```typescript
const BASE = "https://api.diko.app/api/v1"
const headers = { Authorization: `Bearer ${process.env.DIKO_API_KEY}` }

async function* paginate<T>(path: string, params: Record<string, string> = {}): AsyncGenerator<T> {
  let cursor: string | null = null
  do {
    const query = new URLSearchParams({ limit: "100", ...params, ...(cursor ? { cursor } : {}) })
    const response = await fetch(`${BASE}${path}?${query}`, { headers })
    if (!response.ok) throw new Error(`${response.status} ${await response.text()}`)
    const page: { data: T[]; has_more: boolean; next_cursor: string | null } = await response.json()
    yield* page.data
    cursor = page.has_more ? page.next_cursor : null
  } while (cursor)
}

for await (const meeting of paginate<{ id: string; title: string }>("/meetings", { status: "ready" })) {
  console.log(meeting.id, meeting.title)
}
```

## Transkriptas ir `revision`

Transkripto segmentų puslapiai grąžina sąrašo voke lauką `revision`. Žymeklis pririštas prie jo. Jei transkriptas pasikeičia puslapiuojant (pavyzdžiui, patvirtinus gramatikos pataisas), API grąžina 409 [`transcript_changed`](https://diko.app/api-docs/klaidos.md#transcript_changed). Tada skaitykite transkriptą iš naujo be `cursor`. Jei reikia viso teksto vienu kreipiniu, naudokite `format=text`, `srt` arba `vtt`.

## Įvykių srautas

`GET /events` naudoja tą patį modelį, bet `next_cursor` grąžina visada. Net kai `has_more` yra `false`, saugokite jį ir kitą kartą pradėkite nuo jo. Rodomi tik **užfiksuoti** įvykiai, išdėstyti užfiksavimo tvarka, todėl nė vienas nepraleidžiamas.

- Įvykiai saugomi **30 dienų**. Be `cursor` srautas prasideda nuo seniausio dar išlikusio įvykio.
- Diko užfiksuoja įvykius tik tada, kai paskyra turi neatšauktą raktą arba įjungtą webhook endpointą. Anksčiau pasibaigę susitikimai ir importai įvykių nesukuria, todėl srautas istorijos neatkuria. Istoriją skaitykite per sąrašų endpointus.
- Kai puslapyje yra įvykių, `next_cursor` rodo į paskutinį iš jų.
- Kai puslapis **tuščias**, `next_cursor` yra dabartinė srauto pozicija (niekada ne už jūsų atsiųsto žymeklio), todėl jį įsimenanti sistema neskenuoja to paties srauto ruožo iš naujo.
- Žymeklis, kuris nėra įvykių žymeklis (ne `latest` ir ne gautas iš šio API), grąžina 400 [`invalid_cursor`](https://diko.app/api-docs/klaidos.md#invalid_cursor).

Daugiau: [Įvykiai ir webhooks](https://diko.app/api-docs/webhooks.md#%C4%AFvyki%C5%B3-srautas-kaip-alternatyva).
