Skip to Content
Developer APIAPI GuidesPagination & Delta Sync

Pagination & Delta Sync


Cursor-based pagination

All list endpoints in the external API use cursor pagination. Every list response returns a CursorPage wrapper:

{ "items": [ ], "next_cursor": "eyJpZCI6IjNhOTEiLCJkaXIiOiJuZXh0In0", "has_more": true, "limit": 20 }
FieldTypeDescription
itemsarrayThe current page of results
next_cursorstring | nullOpaque cursor for the next page; null when has_more is false
has_morebooleanWhether more results exist after this page
limitintegerPage size used for this response

Query parameters

ParameterDefaultRangeDescription
cursor(omit for first page)Cursor from the previous response’s next_cursor
limit201100Results per page

Example — iterate all partner orgs

# First page curl "https://api.eunifyer.com/api/v1/partner/orgs?limit=50" \ -H "Authorization: Bearer $TOKEN" # Next page (use next_cursor from previous response) curl "https://api.eunifyer.com/api/v1/partner/orgs?limit=50&cursor=eyJpZCI6IjNhOTEi..." \ -H "Authorization: Bearer $TOKEN"
import httpx def list_all_orgs(token: str) -> list[dict]: client = httpx.Client( base_url="https://api.eunifyer.com/api/v1", headers={"Authorization": f"Bearer {token}"}, ) orgs, cursor = [], None while True: params = {"limit": 100, **({"cursor": cursor} if cursor else {})} page = client.get("/partner/orgs", params=params).raise_for_status().json() orgs.extend(page["items"]) if not page["has_more"]: break cursor = page["next_cursor"] return orgs
async function listAllOrgs(token: string): Promise<Org[]> { const orgs: Org[] = []; let cursor: string | null = null; do { const url = new URL("https://api.eunifyer.com/api/v1/partner/orgs"); url.searchParams.set("limit", "100"); if (cursor) url.searchParams.set("cursor", cursor); const page = await fetch(url, { headers: { Authorization: `Bearer ${token}` }, }).then((r) => r.json()); orgs.push(...page.items); cursor = page.has_more ? page.next_cursor : null; } while (cursor); return orgs; }

Cursor stability

Cursors are stable for 24 hours. A cursor that has expired returns 400 Bad Request — restart pagination from the beginning.


Drive delta sync

The delta sync feed is designed for sync clients — desktop or mobile apps that maintain a local replica of a user’s Drive.

First sync

Omit cursor to request the initial full snapshot:

curl "https://api.eunifyer.com/api/v1/drive/sync/delta?device_id=MY_DEVICE_ID" \ -H "Authorization: Bearer $TOKEN"

device_id is a stable, client-generated identifier (UUID, max 64 chars). Store it persistently on the device.

Response:

{ "items": [ { "id": "file-uuid", "name": "report.pdf", "parent_id": "folder-uuid", "deleted": false, "content_hash": "sha256:abc123…", "version": 3, "size_bytes": 204800, "updated_at": "2026-04-24T10:00:00Z" } ], "cursor": "opaque-cursor-string", "has_more": false }

When has_more is true, page through using the returned cursor until has_more is false. Store the final cursor.

Incremental sync

On subsequent syncs, pass the stored cursor:

curl "https://api.eunifyer.com/api/v1/drive/sync/delta?device_id=MY_DEVICE_ID&cursor=opaque-cursor" \ -H "Authorization: Bearer $TOKEN"

The server returns only files that changed since the cursor was issued.

Deleted items

Items with "deleted": true should be removed from the local replica. The id field is always present even for deleted items.

Applying changes

def apply_delta(local_db, items): for item in items: if item["deleted"]: local_db.remove(item["id"]) else: local_db.upsert(item)

Committing sync state

After a successful sync cycle, commit the cursor to record the device’s sync progress server-side:

POST /api/v1/drive/sync/commit { "device_id": "MY_DEVICE_ID", "cursor": "latest-cursor" }

Sync endpoints

EndpointPurpose
GET /drive/sync/deltaFetch changes since cursor (or full snapshot)
POST /drive/sync/commitRecord sync progress server-side
GET /drive/sync/statusCheck sync status for a device
GET /drive/sync/devicesList registered sync devices

Which endpoints use which pagination

EndpointPagination type
GET /partner/orgsCursor
GET /partner/orgs/{id}/usersCursor
GET /partner/plansCursor
GET /developer/service-principalsCursor
GET /developer/service-principals/{id}/tokensCursor
GET /webhooks/subscriptionsCursor
GET /webhooks/subscriptions/{id}/deliveriesCursor (most-recent-first)
GET /drive/browseOffset (limit + offset on folder contents)
GET /drive/sync/deltaCursor (Drive-specific delta format)