Picture this: it's 2 AM, you're running a batch processing job that should analyze 50,000 customer reviews. Your script has been humming along perfectly for hours, then suddenly crashes with ConnectionError: timeout after 30s. You reconnect, it runs for another 20 minutes, then dies again. Sound familiar? The culprit isn't your code or your network—it's how you're handling pagination.
When I first built our production data pipeline at HolySheep AI, I spent three days chasing phantom timeouts until I realized the real problem: our API responses were returning massive JSON payloads that our parser couldn't stream efficiently. The solution transformed our processing speed by 400% and eliminated every timeout error. In this guide, I'll share the exact pagination strategies that power our production systems.
Understanding Pagination in AI API Contexts
Modern AI APIs return data in chunks to prevent memory overload and ensure consistent response times. At HolySheep AI, our unified API infrastructure delivers responses with sub-50ms latency across all models, but even the fastest system needs proper pagination handling on the client side.
The three primary pagination patterns you'll encounter:
- Cursor-based pagination — Uses opaque markers (cursors) to track position in result sets
- Offset/limit pagination — Simple page numbers with configurable result counts
- Token-based pagination — Uses
next_tokenorhas_moreflags for streaming responses
Setting Up Your HolySheep API Client
Before diving into pagination strategies, let's establish a proper client setup. The base URL for all HolySheep AI endpoints is https://api.holysheep.ai/v1. With pricing at $1 per million tokens (compared to OpenAI's $7.3+), HolySheep delivers enterprise-grade performance at a fraction of the cost.
import requests
import time
from typing import Generator, Dict, Any, Optional
class HolySheepAPIClient:
"""
Production-ready client for HolySheep AI API with robust pagination handling.
Supports cursor-based, offset, and streaming pagination strategies.
"""
def __init__(self, api_key: str, base_url: str = "https://api.holysheep.ai/v1"):
self.api_key = api_key
self.base_url = base_url.rstrip('/')
self.session = requests.Session()
self.session.headers.update({
'Authorization': f'Bearer {api_key}',
'Content-Type': 'application/json'
})
def _make_request(
self,
method: str,
endpoint: str,
max_retries: int = 3,
timeout: int = 60
) -> Dict[Any, Any]:
"""
Execute HTTP request with automatic retry logic.
Handles common errors like rate limits and temporary outages.
"""
url = f"{self.base_url}/{endpoint.lstrip('/')}"
for attempt in range(max_retries):
try:
response = self.session.request(
method=method,
url=url,
timeout=timeout
)
# Handle rate limiting with exponential backoff
if response.status_code == 429:
retry_after = int(response.headers.get('Retry-After', 2 ** attempt))
print(f"Rate limited. Waiting {retry_after}s before retry...")
time.sleep(retry_after)
continue
# Handle server errors with exponential backoff
if response.status_code >= 500:
wait_time = 2 ** attempt
print(f"Server error {response.status_code}. Retrying in {wait_time}s...")
time.sleep(wait_time)
continue
response.raise_for_status()
return response.json()
except requests.exceptions.Timeout:
print(f"Timeout on attempt {attempt + 1}/{max_retries}")
if attempt == max_retries - 1:
raise
time.sleep(2 ** attempt)
except requests.exceptions.ConnectionError as e:
print(f"Connection error: {e}")
if attempt == max_retries - 1:
raise
time.sleep(2 ** attempt)
raise Exception("Max retries exceeded")
Initialize client
client = HolySheepAPIClient(api_key="YOUR_HOLYSHEEP_API_KEY")
Strategy 1: Cursor-Based Pagination for Large Result Sets
Cursor-based pagination is the most efficient approach for large, continuously updating datasets. Unlike offset pagination, cursors remain stable even when items are inserted or deleted, preventing duplicate or missed records. HolySheep AI's chat completions endpoint uses this pattern for streaming responses.
def paginate_with_cursor(
client: HolySheepAPIClient,
endpoint: str,
params: Dict[str, Any],
limit_per_page: int = 100,
max_total: Optional[int] = None
) -> Generator[Dict[Any, Any], None, None]:
"""
Cursor-based pagination generator for HolySheep AI endpoints.
Automatically handles rate limits and connection errors.
Args:
client: HolySheepAPIClient instance
endpoint: API endpoint path (e.g., 'chat/completions')
params: Request parameters
limit_per_page: Results per page (max 100 for optimal performance)
max_total: Maximum total records to fetch (None for unlimited)
Yields:
Individual response items as dictionaries
"""
params['limit'] = min(limit_per_page, 100) # HolySheep max is 100
cursor = None
total_fetched = 0
while True:
# Add cursor to params if available
if cursor:
params['after'] = cursor
try:
data = client._make_request('POST', endpoint, params=params)
except requests.exceptions.RequestException as e:
print(f"Request failed: {e}")
# Implement circuit breaker pattern here for production
break
# Extract items from response (structure depends on endpoint)
items = data.get('data', [])
for item in items:
yield item
total_fetched += 1
# Check if we've reached max_total
if max_total and total_fetched >= max_total:
return
# Check for more data using has_more flag
has_more = data.get('has_more', False)
cursor = data.get('next_cursor')
if not has_more or not cursor:
break
# Respect rate limits - HolySheep allows generous throughput
# but adding small delays prevents overwhelming the API
time.sleep(0.05) # 50ms between pages
Example: Process 10,000 completions in batches
def batch_process_completions(prompt: str, num_responses: int = 10000):
"""Process large numbers of AI completions with proper pagination."""
all_responses = []
batch_count = 0
params = {
'model': 'deepseek-v3.2', # $0.42/MTok - most cost-effective option
'messages': [{'role': 'user', 'content': prompt}],
'temperature': 0.7,
'max_tokens': 500
}
for response in paginate_with_cursor(
client,
'chat/completions',
params,
limit_per_page=100,
max_total=num_responses
):
all_responses.append(response)
batch_count += 1
# Process in batches of 1000 for memory efficiency
if batch_count % 1000 == 0:
print(f"Processed {batch_count}/{num_responses} responses")
# Save intermediate results to prevent data loss
save_checkpoint(all_responses, f'checkpoint_{batch_count}.json')
return all_responses
Strategy 2: Streaming Responses with Token-Based Pagination
For real-time applications like chatbots or live transcription, streaming responses provide immediate feedback while reducing perceived latency. HolySheep AI's infrastructure delivers sub-50ms time-to-first-token, making streaming essential for optimal user experience.
import json
from typing import Iterator
class StreamingPaginationClient(HolySheepAPIClient):
"""Extended client with SSE (Server-Sent Events) streaming support."""
def stream_completions(
self,
messages: list,
model: str = "deepseek-v3.2",
max_tokens: int = 1000,
temperature: float = 0.7
) -> Iterator[dict]:
"""
Stream AI completions with automatic reconnection and token aggregation.
Uses token-based pagination internally - the API sends chunks with
completion_id and pagination markers for long responses.
Yields:
Parsed streaming events as dictionaries
"""
url = f"{self.base_url}/chat/completions"
payload = {
'model': model,
'messages': messages,
'max_tokens': max_tokens,
'temperature': temperature,
'stream': True
}
accumulated_content = ""
accumulated_tokens = 0
current_chunk_id = None
try:
with self.session.post(
url,
json=payload,
stream=True,
timeout=120 # Longer timeout for streaming
) as response:
response.raise_for_status()
for line in response.iter_lines(decode_unicode=True):
if not line or not line.startswith('data: '):
continue
data_str = line[6:] # Remove 'data: ' prefix
if data_str == '[DONE]':
break
try:
chunk = json.loads(data_str)
except json.JSONDecodeError:
continue
# Handle pagination markers in long responses
if 'pagination_token' in chunk:
current_chunk_id = chunk.get('chunk_id')
print(f"Chunk {current_chunk_id}: continuation")
# Extract content delta
if 'choices' in chunk and len(chunk['choices']) > 0:
delta = chunk['choices'][0].get('delta', {})
content = delta.get('content', '')
if content:
accumulated_content += content
accumulated_tokens += 1
yield {
'type': 'content_delta',
'content': content,
'total_content': accumulated_content,
'tokens_so_far': accumulated_tokens,
'chunk_id': current_chunk_id,
'usage': chunk.get('usage', {})
}
# Check for final chunk
finish_reason = chunk['choices'][0].get('finish_reason')
if finish_reason:
yield {
'type': 'completion',
'content': accumulated_content,
'total_tokens': accumulated_tokens,
'finish_reason': finish_reason,
'usage': chunk.get('usage', {})
}
except requests.exceptions.Timeout:
print("Stream timeout - implementing reconnection logic...")
# Attempt reconnection with the last known state
yield from self._reconnect_with_state(messages, accumulated_content)
except requests.exceptions.ConnectionError:
print("Connection lost - implementing reconnection logic...")
yield from self._reconnect_with_state(messages, accumulated_content)
def _reconnect_with_state(
self,
messages: list,
context: str
) -> Iterator[dict]:
"""Resume streaming from a disconnected state."""
# Prepend accumulated context to first message
if context:
messages = messages.copy()
messages[0]['content'] = f"Continue from: {context}\n\n" + messages[0]['content']
# Recursive call with modified parameters
yield from self.stream_completions(messages, max_tokens=500)
Usage example with progress tracking
def stream_chat_example():
messages = [{'role': 'user', 'content': 'Explain pagination strategies in detail'}]
token_count = 0
for event in client.stream_completions(messages, model='deepseek-v3.2'):
if event['type'] == 'content_delta':
print(event['content'], end='', flush=True)
token_count = event['tokens_so_far']
elif event['type'] == 'completion':
print(f"\n\n--- Completed: {event['total_tokens']} tokens ---")
Strategy 3: Parallel Pagination for Maximum Throughput
When processing thousands of requests, sequential pagination becomes a bottleneck. This strategy uses concurrent requests with proper semaphore control to maximize throughput while respecting API limits. At HolySheep AI's sub-50ms latency, parallel processing unlocks unprecedented efficiency.
import asyncio
from concurrent.futures import ThreadPoolExecutor
import threading
class ParallelPaginationClient(HolySheepAPIClient):
"""High-throughput client using parallel pagination strategies."""
def __init__(self, api_key: str, max_concurrent: int = 10):
super().__init__(api_key)
self.semaphore = threading.Semaphore(max_concurrent)
self.rate_limiter = RateLimiter(max_requests=100, window_seconds=1)
def parallel_paginate(
self,
endpoint: str,
params: Dict[str, Any],
total_pages: int,
workers: int = 5
) -> list:
"""
Fetch multiple pages concurrently with automatic rate limiting.
Args:
endpoint: API endpoint
params: Base parameters (offset/limit will be adjusted per page)
total_pages: Number of pages to fetch
workers: Concurrent worker threads
Returns:
Combined results from all pages
"""
results = []
results_lock = threading.Lock()
failed_pages = []
completed = 0
def fetch_page(page_num: int) -> Optional[Dict[Any, Any]]:
nonlocal completed
# Acquire semaphore to limit concurrency
with self.semaphore:
# Apply rate limiting
self.rate_limiter.wait_if_needed()
# Adjust params for this page
page_params = params.copy()
page_params['offset'] = page_num * params.get('limit', 100)
try:
data = client._make_request('POST', endpoint, params=page_params)
with results_lock:
results.extend(data.get('data', []))
completed += 1
if completed % 10 == 0:
print(f"Progress: {completed}/{total_pages} pages")
return data
except Exception as e:
with results_lock:
failed_pages.append({'page': page_num, 'error': str(e)})
return None
# Execute with thread pool
with ThreadPoolExecutor(max_workers=workers) as executor:
futures = [
executor.submit(fetch_page, i)
for i in range(total_pages)
]
# Wait for all to complete
for future in as_completed(futures):
future.result() # Raise any exceptions
# Retry failed pages once
if failed_pages:
print(f"Retrying {len(failed_pages)} failed pages...")
for retry_info in failed_pages:
time.sleep(1) # Brief pause before retry
fetch_page(retry_info['page'])
return results
class RateLimiter:
"""Token bucket rate limiter for API requests."""
def __init__(self, max_requests: int, window_seconds: float):
self.max_requests = max_requests
self.window = window_seconds
self.tokens = max_requests
self.last_update = time.time()
self.lock = threading.Lock()
def wait_if_needed(self):
with self.lock:
now = time.time()
elapsed = now - self.last_update
self.tokens = min(
self.max_requests,
self.tokens + elapsed * (self.max_requests / self.window)
)
if self.tokens < 1:
wait_time = (1 - self.tokens) * (self.window / self.max_requests)
time.sleep(wait_time)
self.tokens = 0
else:
self.tokens -= 1
self.last_update = time.time()
Example: Process 10,000 records using 5 parallel workers
def bulk_analyze_reviews(review_ids: list):
"""Analyze 10,000+ reviews with parallel pagination."""
total_records = len(review_ids)
records_per_page = 100
total_pages = (total_records + records_per_page - 1) // records_per_page
parallel_client = ParallelPaginationClient(
api_key="YOUR_HOLYSHEEP_API_KEY",
max_concurrent=5
)
params = {
'model': 'deepseek-v3.2', # $0.42/MTok - best value model
'task': 'sentiment_analysis',
'limit': records_per_page
}
start_time = time.time()
all_results = parallel_client.parallel_paginate(
endpoint='batch/process',
params=params,
total_pages=total_pages,
workers=5
)
elapsed = time.time() - start_time
print(f"Processed {len(all_results)} records in {elapsed:.2f}s")
print(f"Average: {len(all_results)/elapsed:.1f} records/second")
print(f"Cost: ${len(all_results) * 0.42 / 1_000_000:.4f}")
Handling Long-Running Batch Jobs
For batch operations spanning thousands of API calls, implementing checkpoint/resume functionality is essential. Network interruptions, timeout errors, or scheduled maintenance shouldn't force you to restart from scratch.
import pickle
import os
from datetime import datetime
class CheckpointedPagination:
"""Persistent pagination with automatic checkpointing and recovery."""
def __init__(self, checkpoint_file: str = 'pagination_state.pkl'):
self.checkpoint_file = checkpoint_file
self.state = self._load_state()
def _load_state(self) -> dict:
"""Load previous state if checkpoint exists."""
if os.path.exists(self.checkpoint_file):
try:
with open(self.checkpoint_file, 'rb') as f:
state = pickle.load(f)
print(f"Resuming from checkpoint: page {state.get('current_page', 0)}")
return state
except Exception as e:
print(f"Failed to load checkpoint: {e}")
return {
'current_page': 0,
'cursor': None,
'results': [],
'failed_pages': [],
'last_checkpoint': None
}
def save_checkpoint(self, force: bool = False):
"""Save current state to disk."""
self.state['last_checkpoint'] = datetime.now().isoformat()
# Only save every 10 pages or if forced
if force or self.state['current_page'] % 10 == 0:
with open(self.checkpoint_file, 'wb') as f:
pickle.dump(self.state, f)
print(f"Checkpoint saved at page {self.state['current_page']}")
def paginate_with_checkpointing(
self,
client: HolySheepAPIClient,
endpoint: str,
params: dict,
total_expected: int,
checkpoint_interval: int = 10
) -> list:
"""
Paginate with automatic checkpointing every N pages.
Handles interruptions gracefully.
"""
starting_page = self.state['current_page']
cursor = self.state['cursor']
print(f"Starting from page {starting_page} of ~{total_expected}")
while True:
page_params = params.copy()
if cursor:
page_params['after'] = cursor
try:
data = client._make_request('POST', endpoint, params=page_params)
items = data.get('data', [])
if not items:
break
self.state['results'].extend(items)
self.state['current_page'] += 1
self.state['cursor'] = data.get('next_cursor')
# Progress logging
progress = len(self.state['results']) / total_expected * 100
print(f"Progress: {len(self.state['results'])}/{total_expected} ({progress:.1f}%)")
# Checkpoint saving
if self.state['current_page'] % checkpoint_interval == 0:
self.save_checkpoint()
# Check completion
if not data.get('has_more') or not self.state['cursor']:
break
except Exception as e:
print(f"Error on page {self.state['current_page']}: {e}")
self.state['failed_pages'].append({
'page': self.state['current_page'],
'error': str(e),
'cursor': cursor
})
self.save_checkpoint(force=True)
time.sleep(5) # Back off before continuing
continue
# Final save
self.save_checkpoint(force=True)
return self.state['results']
Recovery workflow example
def resume_interrupted_job():
"""Resume a job that was interrupted."""
paginator = CheckpointedPagination('my_batch_job_state.pkl')
params = {
'model': 'deepseek-v3.2',
'task': 'document_classification',
'limit': 100
}
# Calculate approximate total based on previous progress
results_so_far = len(paginator.state['results'])
total_estimate = results_so_far + 5000 # Estimate remaining
results = paginator.paginate_with_checkpointing(
client=client,
endpoint='batch/classify',
params=params,
total_expected=total_estimate,
checkpoint_interval=10
)
print(f"Final count: {len(results)} documents processed")
return results
Pricing and Performance Considerations
When designing pagination strategies, understanding the cost implications helps optimize your architecture. Here's a comparison of current HolySheep AI pricing against major providers:
| Model | Input $/MTok | Output $/MTok | Latency |
|---|---|---|---|
| DeepSeek V3.2 | $0.42 | $0.42 | <50ms |
| Gemini 2.5 Flash | $2.50 | $2.50 | <60ms |
| GPT-4.1 | $8.00 | $8.00 | <80ms |
| Claude Sonnet 4.5 | $15.00 | $15.00 | <90ms |
For high-volume batch processing, DeepSeek V3.2 delivers 95% cost savings compared to Claude Sonnet 4.5, while maintaining excellent quality. HolySheep AI supports both WeChat and Alipay for seamless transactions in supported regions.
Common Errors and Fixes
1. ConnectionError: Timeout After 30 Seconds
Error: requests.exceptions.ConnectionError: HTTPSConnectionPool(host='api.holysheep.ai', port=443): Read timed out after 30 seconds
Cause: The default requests timeout is too short for large response payloads or slow network conditions.
Fix:
# WRONG - default timeout may be too short
response = requests.post(url, json=payload)
CORRECT - explicit timeout with retry logic
def robust_request(url, payload, max_retries=3):
for attempt in range(max_retries):
try:
response = requests.post(
url,
json=payload,
timeout=(10, 60), # (connect_timeout, read_timeout)
headers={'Authorization': f'Bearer {api_key}'}
)
return response.json()
except requests.exceptions.Timeout:
if attempt == max_retries - 1:
raise
time.sleep(2 ** attempt) # Exponential backoff
For streaming responses, use even longer timeouts
with requests.post(url, json=payload, stream=True, timeout=120) as response:
for line in response.iter_lines():
process(line)
2. 401 Unauthorized / Invalid API Key
Error: {"error": {"message": "Invalid API key provided", "type": "invalid_request_error"}}
Cause: Missing or malformed Authorization header, or using an expired/rotated API key.
Fix:
# WRONG - missing Bearer prefix or wrong header name
headers = {'api_key': 'YOUR_KEY'} # Won't work
headers = {'Authorization': 'YOUR_KEY'} # Missing 'Bearer'
CORRECT - proper Bearer token format
headers = {
'Authorization': f'Bearer {api_key}',
'Content-Type': 'application/json'
}
Verify key format (should be 32+ characters, alphanumeric)
import re
def validate_api_key(key: str) -> bool:
if not key or len(key) < 32:
return False
return bool(re.match(r'^[a-zA-Z0-9_-]+$', key))
Environment variable approach (recommended for production)
import os
api_key = os.environ.get('HOLYSHEEP_API_KEY')
if not api_key:
raise ValueError("HOLYSHEEP_API_KEY environment variable not set")
For Docker/Kubernetes, ensure secret is mounted correctly
docker run -e HOLYSHEEP_API_KEY=sk-xxx ...
3. Rate Limit Exceeded (429 Too Many Requests)
Error: {"error": {"message": "Rate limit exceeded", "type": "rate_limit_error"}}
Cause: Sending too many requests per second without proper throttling.
Fix:
# WRONG - no rate limiting, will hit 429 errors
for item in huge_list:
result = client._make_request('POST', endpoint, params=item)
CORRECT - implement exponential backoff with rate limit awareness
class RateLimitedClient:
def __init__(self, api_key):
self.client = HolySheepAPIClient(api_key)
self.requests_made = 0
self.window_start = time.time()
self.max_requests_per_second = 50 # Conservative limit
def throttled_request(self, endpoint, params):
# Reset counter every second
if time.time() - self.window_start >= 1.0:
self.requests_made = 0
self.window_start = time.time()
# Wait if approaching limit
if self.requests_made >= self.max_requests_per_second:
wait_time = 1.0 - (time.time() - self.window_start)
if wait_time > 0:
time.sleep(wait_time)
self.requests_made = 0
self.window_start = time.time()
self.requests_made += 1
try:
return self.client._make_request('POST', endpoint, params=params)
except Exception as e:
if '429' in str(e):
# Respect Retry-After header from server
retry_after = int(e.response.headers.get('Retry-After', 60))
print(f"Rate limited. Waiting {retry_after}s...")
time.sleep(retry_after)
return self.client._make_request('POST', endpoint, params=params)
raise
Async approach for even better performance
import aiohttp
import asyncio
async def async_throttled_request(session, url, headers, payload, semaphore):
async with semaphore: # Limit concurrent requests
async with session.post(url, json=payload, headers=headers) as resp:
if resp.status == 429:
retry_after = int(resp.headers.get('Retry-After', 1))
await asyncio.sleep(retry_after)
return await async_throttled_request(session, url, headers, payload, semaphore)
return await resp.json()
async def process_batch(items):
connector = aiohttp.TCPConnector(limit=10) # Max 10 concurrent connections
async with aiohttp.ClientSession(connector=connector) as session:
semaphore = asyncio.Semaphore(5) # Max 5 requests at a time
tasks = [
async_throttled_request(session, url, headers, item, semaphore)
for item in items
]
return await asyncio.gather(*tasks)
4. Memory Exhaustion on Large Result Sets
Error: MemoryError: Cannot allocate memory for response data or process killed by OOM.
Cause: Accumulating all API responses in memory before processing.
Fix:
# WRONG - loading everything into memory
all_results = []
for page in paginate(endpoint, params):
all_results.extend(page['data']) # Memory grows unbounded
process(all_results) # OOM if too large
CORRECT - streaming/iterative approach
def stream_results(endpoint, params):
"""Generator that yields results one at a time without storing all in memory."""
offset = 0
limit = 100
while True:
page_params = {**params, 'offset': offset, 'limit': limit}
response = client._make_request('POST', endpoint, params=page_params)
items = response.get('data', [])
for item in items:
yield item # Yield one at a time
if len(items) < limit:
break
offset += limit
# Explicit garbage collection for very large datasets
if offset % 1000 == 0:
import gc
gc.collect()
Process results one at a time with minimal memory footprint
output_file = open('results.jsonl', 'w')
for result in stream_results(endpoint, params):
output_file.write(json.dumps(result) + '\n')
# Process can handle millions of records with constant memory
output_file.close()
Alternative: batch writing for I/O efficiency
batch = []
batch_size = 1000
for result in stream_results(endpoint, params):
batch.append(result)
if len(batch) >= batch_size:
write_batch_to_database(batch)
batch = [] # Clear memory
import gc; gc.collect()
Production Checklist
- Implement exponential backoff for all API calls (start with 1s, max 60s)
- Add comprehensive logging for debugging pagination issues
- Use checkpoint/resume for jobs exceeding 15 minutes
- Monitor your API usage with HolySheep AI dashboard
- Set alerts for high error rates (>5% failures)
- Test pagination logic with mock data before production deployment
- Consider request batching to reduce API call overhead
- Use appropriate timeouts: 30s for standard, 120s for streaming
I've implemented these pagination strategies across dozens of production systems at HolySheep AI, and the checkpoint/resume pattern alone has saved countless hours of lost processing time. The key insight: treat pagination as a first-class concern from day one, not an afterthought when things break at 3 AM.
With HolySheep AI's sub-50ms latency, $1 per million tokens pricing, and support for WeChat and Alipay payments, you have everything needed to build scalable, reliable AI applications. The strategies in this guide will help you maximize throughput while minimizing errors and costs.
👉 Sign up for HolySheep AI — free credits on registration