Docs/API Reference/Conventions

Pagination

List endpoints are paginated with an opaque cursor. Pass it back on the next request to get the next page. No offsets, no page numbers, no skipped or duplicated rows when the underlying data shifts.

TL;DR

Send limit + (optional) cursor on the request. Read pagination.nextCursor + pagination.hasMore on the response. Loop while hasMore is true.

Request parameters

ParameterTypeDescription
limitintegerPage size. Default 25, max 100. Servers may return fewer rows than requested even when more results exist — always trust hasMore, not the row count.
cursorstringOpaque token from the previous response's pagination.nextCursor. Omit for the first page. Don't parse, don't persist long-term — cursors can change shape between releases.

Response envelope

Every list endpoint returns the rows plus a pagination block:

{
  "data": [
    { "id": "res_abc", "checkIn": "2026-06-01", ... },
    { "id": "res_def", "checkIn": "2026-06-02", ... }
  ],
  "pagination": {
    "nextCursor": "eyJpZCI6InJlc19kZWYifQ==",
    "hasMore": true
  }
}

When you reach the end, hasMore is false and nextCursor is null.

Paging loop

let cursor: string | null = null
const all: Reservation[] = []

do {
  const url = new URL('https://api.repull.dev/v1/reservations')
  url.searchParams.set('limit', '100')
  if (cursor) url.searchParams.set('cursor', cursor)

  const res = await fetch(url, {
    headers: {
      Authorization: `Bearer ${process.env.REPULL_API_KEY}`,
      'X-Workspace-Id': process.env.REPULL_WORKSPACE_ID!,
    },
  })
  const body = await res.json()

  all.push(...body.data)
  cursor = body.pagination.hasMore ? body.pagination.nextCursor : null
} while (cursor)

Behavior to know

  • Cursors are stable across mutations.Inserts and deletes during a paging session don't shift other rows in or out — you won't skip or double-count.
  • Cursors are scoped to the query. If you change a filter (e.g. status or checkInAfter) between requests, start over with no cursor.
  • Cursors expire after 24 hours. A long pause and resume may return invalid_params on cursor — restart from the first page.
  • Order is endpoint-specificand documented on each list endpoint's page. For most resources it's newest-first by creation time.
  • No total count. The API never returns a total — counting every row would force a full scan on every request. Use hasMore to know when to stop.
  • Rate limits — large pages cost less than many small ones, but don't exceed the per-window budget.
  • Errors — paging errors return invalid_params on the cursor or limit field.
AI