# Pagination The Sensay API uses offset-based pagination for most list endpoints, providing a familiar page-based navigation pattern that's easy to implement in user interfaces. ## How offset-based pagination works Offset-based pagination uses page numbers and page sizes, making it familiar and easy to implement UI components like page selectors and "showing X of Y results" displays. ### Parameters - `page`: The page number (starting from 1) - `pageSize`: Number of items per page (typically 1-100) The response includes a `total` field showing the complete number of available items. ### Example: List conversations ```bash curl -X GET "https://api.sensay.io/v1/replicas/{replicaUUID}/conversations?page=2&pageSize=20" \ -H "X-ORGANIZATION-SECRET: $ORGANIZATION_SECRET" \ -H "X-API-Version: $API_VERSION" \ -H "Content-Type: application/json" ``` **Response:** ```json { "success": true, "items": [ { "uuid": "8e9309af-baa4-4a85-8c59-c3a2a0c2ad0f", "source": "web", "messageCount": 42, "firstMessageAt": "2025-05-27T15:02:44.499744+00:00", "lastMessageAt": "2025-05-27T15:02:44.499744+00:00" } ], "total": 156 } ``` ### Implementation pattern ```javascript // Calculate pagination info const totalPages = Math.ceil(response.total / pageSize); const hasNextPage = currentPage < totalPages; const hasPrevPage = currentPage > 1; // Navigation const nextPageUrl = hasNextPage ? `/conversations?page=${currentPage + 1}&pageSize=${pageSize}` : null; const prevPageUrl = hasPrevPage ? `/conversations?page=${currentPage - 1}&pageSize=${pageSize}` : null; // Display info const startItem = (currentPage - 1) * pageSize + 1; const endItem = Math.min(currentPage * pageSize, response.total); console.log(`Showing ${startItem}-${endItem} of ${response.total} results`); ``` ### Building pagination UI ```javascript function createPaginationControls(currentPage, totalPages) { const controls = []; // Previous button if (currentPage > 1) { controls.push({ type: 'previous', page: currentPage - 1, label: 'Previous' }); } // Page numbers (show 5 pages max) const startPage = Math.max(1, currentPage - 2); const endPage = Math.min(totalPages, currentPage + 2); for (let page = startPage; page <= endPage; page++) { controls.push({ type: 'page', page: page, label: page.toString(), active: page === currentPage }); } // Next button if (currentPage < totalPages) { controls.push({ type: 'next', page: currentPage + 1, label: 'Next' }); } return controls; } ``` ## Best practices ### Performance 1. **Choose appropriate page sizes:** - 10-50 items for UI lists with good user experience - Up to 100 for data processing or admin interfaces - Avoid very large page sizes that may cause timeouts 2. **Cache responses when possible:** - List endpoints often return stable data - Cache total counts separately as they change less frequently ### Error handling ```javascript async function fetchPage(page, pageSize) { try { const response = await fetch(`/conversations?page=${page}&pageSize=${pageSize}`); if (!response.ok) { if (response.status === 404) { // Page doesn't exist, redirect to last valid page return fetchPage(1, pageSize); } throw new Error(`HTTP ${response.status}`); } return response.json(); } catch (error) { console.error('Pagination error:', error); throw error; } } ``` ### UI considerations 1. **Loading states:** Show loading indicators during page transitions 2. **Empty states:** Handle cases where no items are returned (page 1 with 0 total) 3. **Invalid pages:** Gracefully handle requests for pages that don't exist 4. **URL synchronization:** Keep browser URL in sync with current page for bookmarking