Overview
The Zochil API uses cursor-based pagination for efficient navigation through large datasets. This approach provides consistent performance regardless of dataset size and handles real-time data changes gracefully.
Most list endpoints accept the following pagination parameters:
Number of items to return (1-100)
Number of items to skip (cursor-based)
Cursor for the next page (when available)
Paginated responses include metadata to help you navigate:
{
"success": true,
"data": {
"items": [
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"name": "Example Item",
"created_at": "2023-01-01T00:00:00Z"
}
],
"pagination": {
"limit": 20,
"offset": 0,
"total": 150,
"has_more": true,
"next_cursor": "eyJpZCI6IjEyM2U0NTY3LWU4OWItMTJkMy1hNDU2LTQyNjYxNDE3NDAwMCIsImNyZWF0ZWRfYXQiOiIyMDIzLTAxLTAxVDAwOjAwOjAwWiJ9"
}
}
}
First Page Request
curl -X GET "https://api.zochil.io/catalog/products?limit=20" \
-H "access-token: your_access_token" \
-H "device-id: your_device_id"
Next Page Request
Using offset-based pagination:
curl -X GET "https://api.zochil.io/catalog/products?limit=20&offset=20" \
-H "access-token: your_access_token" \
-H "device-id: your_device_id"
Iterating Through All Pages
async function fetchAllProducts() {
const allProducts = [];
let offset = 0;
const limit = 50; // Larger page size for efficiency
let hasMore = true;
while (hasMore) {
const response = await fetch(
`https://api.zochil.io/catalog/products?limit=${limit}&offset=${offset}`,
{
headers: {
"access-token": "your_access_token",
"device-id": "your_device_id"
}
}
);
const data = await response.json();
if (!data.success) {
throw new Error(`API Error: ${data.error.message}`);
}
allProducts.push(...data.data.items);
hasMore = data.data.pagination.has_more;
offset += limit;
// Optional: Add delay to avoid rate limiting
await new Promise((resolve) => setTimeout(resolve, 100));
}
return allProducts;
}
For real-time data and better performance:
async function fetchProductsWithCursor(cursor = null) {
const url = cursor
? `https://api.zochil.io/catalog/products?cursor=${encodeURIComponent(
cursor
)}`
: "https://api.zochil.io/catalog/products?limit=20";
const response = await fetch(url, {
headers: {
"access-token": "your_access_token",
"device-id": "your_device_id"
}
});
const data = await response.json();
return {
items: data.data.items,
nextCursor: data.data.pagination.next_cursor,
hasMore: data.data.pagination.has_more
};
}
// Usage
let cursor = null;
do {
const page = await fetchProductsWithCursor(cursor);
console.log(`Fetched ${page.items.length} products`);
// Process items
page.items.forEach((product) => {
console.log(product.name);
});
cursor = page.nextCursor;
} while (cursor);
Pagination with Filtering and Sorting
Combine pagination with filters and sorting:
curl -X GET "https://api.zochil.io/catalog/products?limit=20&offset=0&category=electronics&sort=price&order=asc" \
-H "access-token: your_access_token" \
-H "device-id: your_device_id"
React Hook Example
Here’s a custom hook for handling pagination in React:
import { useState, useEffect } from "react";
function usePagination(endpoint, options = {}) {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const [pagination, setPagination] = useState({
offset: 0,
limit: 20,
total: 0,
hasMore: false
});
const fetchData = async (reset = false) => {
setLoading(true);
setError(null);
try {
const offset = reset ? 0 : pagination.offset;
const params = new URLSearchParams({
limit: pagination.limit.toString(),
offset: offset.toString(),
...options.filters
});
const response = await fetch(`${endpoint}?${params}`, {
headers: {
"access-token": options.accessToken,
"device-id": options.deviceId
}
});
const result = await response.json();
if (!result.success) {
throw new Error(result.error.message);
}
if (reset) {
setData(result.data.items);
} else {
setData((prev) => [...prev, ...result.data.items]);
}
setPagination({
offset: offset + result.data.items.length,
limit: pagination.limit,
total: result.data.pagination.total,
hasMore: result.data.pagination.has_more
});
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
const loadMore = () => {
if (!loading && pagination.hasMore) {
fetchData(false);
}
};
const refresh = () => {
fetchData(true);
};
useEffect(() => {
fetchData(true);
}, [endpoint, JSON.stringify(options.filters)]);
return {
data,
loading,
error,
pagination,
loadMore,
refresh
};
}
// Usage
function ProductList() {
const { data, loading, pagination, loadMore } = usePagination(
"https://api.zochil.io/catalog/products",
{
accessToken: "your_token",
deviceId: "your_device_id",
filters: { category: "electronics" }
}
);
return (
<div>
{data.map((product) => (
<div key={product.id}>{product.name}</div>
))}
{pagination.hasMore && (
<button onClick={loadMore} disabled={loading}>
{loading ? "Loading..." : "Load More"}
</button>
)}
</div>
);
}
Optimal Page Sizes - Use 20-50 items per page for most use cases - Use
smaller pages (10-20) for complex items with large payloads - Use larger pages
(50-100) for simple list items
Cursor vs Offset - Prefer cursor-based pagination for real-time data - Use
offset-based pagination when users need random page access - Cursor pagination
performs better with large datasets
Avoid Deep Pagination Very high offset values (>10,000) may have
performance impacts. Consider using search filters or cursor-based pagination
instead.
Common Patterns by Endpoint
| Endpoint | Pagination Style | Max Limit | Default Limit |
|---|
/catalog/products | Cursor + Offset | 100 | 20 |
/user/orders | Cursor | 50 | 10 |
/admin/users | Offset | 100 | 25 |
/marketplace/search | Offset | 50 | 20 |
Next Steps