DoloresDocs
Conventions

Pagination

Cursor-based list traversal with has_more and next_cursor.

List endpoints (GET /v1/customers, GET /v1/appointments, GET /v1/sessions, etc.) return at most 100 items per page. Use cursor pagination to walk past the first page.

Request parameters

ParamTypeDefaultNotes
limitinteger20Clamped to [1, 100].
starting_afterstringPublic id of the last item from the previous page.

Response shape

{
  "object": "list",
  "data": [
    { "id": "cust_01HXY...", "object": "customer", ... },
    { "id": "cust_01HXY...", "object": "customer", ... }
  ],
  "has_more": true,
  "next_cursor": "cust_01HXY..."
}
  • has_more is true whenever more pages exist past this one.
  • next_cursor is the cursor to pass as starting_after on the next request. It's null on the final page.
  • Cursors are opaque — never parse or mutate them. We may change the format in a future API version.

Looping through all results

NEXT=""
while :; do
  URL="https://app.meetdolores.ai/v1/customers?limit=100"
  [ -n "$NEXT" ] && URL="${URL}&starting_after=${NEXT}"
  RESP=$(curl -s "$URL" -H "Authorization: Bearer $DOLORES_API_KEY")
  echo "$RESP" | jq -c '.data[]'
  HAS_MORE=$(echo "$RESP" | jq -r '.has_more')
  [ "$HAS_MORE" = "true" ] || break
  NEXT=$(echo "$RESP" | jq -r '.next_cursor')
done
let cursor = undefined;
do {
  const url = new URL('https://app.meetdolores.ai/v1/customers');
  url.searchParams.set('limit', '100');
  if (cursor) url.searchParams.set('starting_after', cursor);
  const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.DOLORES_API_KEY}` } });
  const page = await res.json();
  for (const row of page.data) {
    // process row
  }
  cursor = page.has_more ? page.next_cursor : undefined;
} while (cursor);

Stability across deletes

Cursors include the page item's created_at plus its internal sort id, so deleting the cursor item between pages doesn't lose rows or repeat them. You'll still see whatever rows existed at the moment of the original list call, plus any subsequent inserts/updates ordered consistently against the cursor's timestamp.

If a customer is soft-deleted (via DELETE /v1/customers/{id}) and you continue paginating using a cursor referencing that customer's id, the next page still resolves correctly — we resume at the position immediately past it.