Theme

Technical guides

Pagination

Large API responses are paginated to optimize performance and prevent timeout errors. Use pageStartIndex and pageSize query parameters to retrieve data in manageable chunks.


Pagination Parameters

Control pagination using these query parameters:

  • pageStartIndex: 1-based index of the first item to return (default: 1)
  • pageSize: Number of items per page (default: 50, maximum: 1000)

Pagination Response Headers

When pagination is active, the API includes an X-Pagination header containing:

{
  "TotalCount": 5420,
  "TotalPages": 28,
  "CurrentPage": 1,
  "PageSize": 200,
  "PrevPageLink": null,
  "NextPageLink": "/Catalog/Products?pageStartIndex=201&pageSize=200"
}

Use Cases

  • Syncing full product catalogs without timeouts
  • Processing large order histories
  • Building infinite scroll interfaces
  • Batch processing of inventory updates

Implementation Example

Async Iterator Pattern

const apiUrl = 'https://api.hlc.bike/us/v3.0'
const apiKey = process.env.HLC_API_KEY

/**
 * Paginate through API results using an async generator
 * @param {string} path - API endpoint path
 * @param {number} pageSize - Items per page
 */
async function* paginate(path, pageSize = 200) {
  let pageStartIndex = 1
  let hasMore = true

  while (hasMore) {
    const url = `${apiUrl}${path}?pageStartIndex=${pageStartIndex}&pageSize=${pageSize}`
    const response = await fetch(url, {
      headers: {
        ApiKey: apiKey,
        language: 'en',
      },
    })

    if (!response.ok) {
      throw new Error(
        `HTTP ${response.status} at page ${pageStartIndex}: ${response.statusText}`,
      )
    }

    const data = await response.json()
    yield data

    // Parse pagination metadata
    const paginationHeader = response.headers.get('X-Pagination')
    if (paginationHeader) {
      const meta = JSON.parse(paginationHeader)
      hasMore = meta.NextPageLink !== null
      pageStartIndex += pageSize
    } else {
      hasMore = false
    }
  }
}

// Usage: iterate through all products
for await (const products of paginate('/Catalog/Products', 200)) {
  console.log(`Processing batch of ${products.length} products`)
  // Process each batch
}

Traditional Promise-based Approach

async function getAllProducts() {
  const allProducts = []
  let pageStartIndex = 1
  const pageSize = 200
  let hasMore = true

  while (hasMore) {
    const response = await fetch(
      `${apiUrl}/Catalog/Products?pageStartIndex=${pageStartIndex}&pageSize=${pageSize}`,
      {
        headers: {
          ApiKey: apiKey,
          language: 'en',
        },
      },
    )

    if (!response.ok) {
      throw new Error(`HTTP ${response.status}: ${response.statusText}`)
    }

    const products = await response.json()
    allProducts.push(...products)

    const paginationHeader = response.headers.get('X-Pagination')
    const meta = paginationHeader ? JSON.parse(paginationHeader) : {}
    hasMore = meta.NextPageLink !== null
    pageStartIndex += pageSize
  }

  return allProducts
}
Previous
Compression