Skip to main content

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.

Pagination Parameters

Most list endpoints accept the following pagination parameters:
limit
integer
default:"20"
Number of items to return (1-100)
offset
integer
default:"0"
Number of items to skip (cursor-based)
cursor
string
Cursor for the next page (when available)

Response Format

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"
    }
  }
}

Basic Pagination

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"

Advanced Pagination Patterns

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>
  );
}

Performance Tips

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

EndpointPagination StyleMax LimitDefault Limit
/catalog/productsCursor + Offset10020
/user/ordersCursor5010
/admin/usersOffset10025
/marketplace/searchOffset5020

Next Steps