For AI agents: a documentation index is available at the root level at /llms.txt and /llms-full.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.
LoginStart trialGet a demo
  • Welcome
    • Getting Started
    • Create an API Key
    • Pagination
    • Rate Limiting
    • No-Code Integrations
  • Webhooks
  • OAuth2
  • API Reference
LogoLogo
LoginStart trialGet a demo
On this page
  • Cursor-Based Pagination
  • How It Works
  • Request Parameters
  • Response Format
  • Example Usage
  • Advantages
  • Offset-Based Pagination (Deprecated)
  • Request Parameters
  • Response Format
  • Deprecation Timeline
  • Migration Guide
  • Step 1: Update Your Code
  • Step 2: Handle Response Changes
  • Step 3: Update Pagination Logic
  • Key Differences
  • Backward Compatibility
  • Testing Your Migration
  • Best Practices
  • Cursor Pagination
  • Error Handling
  • Rate Limiting
  • Support
Welcome

Pagination

Was this page helpful?
Previous

Rate Limiting

Prevent unexpected errors by instituting best rate limiting practices in your application.
Next
Built with

The beehiiv API uses pagination to manage large result sets efficiently. We support two pagination methods:

  1. Cursor-based pagination (recommended)
  2. Offset-based pagination (deprecated)

Cursor-Based Pagination

Cursor-based pagination provides consistent, efficient navigation through large datasets. It uses opaque cursor tokens to mark positions in the result set.

How It Works

  • Use the cursor parameter to specify where to start fetching results
  • Set limit to control how many results to return per page (max 100)
  • The response includes a next_cursor for fetching the next page
  • Use has_more to determine if additional pages exist

Request Parameters

ParameterTypeDescription
cursorstringOpaque cursor token for pagination position
limitintegerNumber of results to return (1-100, default: 10)

Response Format

1{
2 "data": [...],
3 "pagination": {
4 "limit": 10,
5 "has_more": true,
6 "next_cursor": "eyJ0aW1lc3RhbXAiOiIyMDI0LTA3LTAyVDE3OjMwOjAwLjAwMDAwMFoifQ=="
7 }
8}

Example Usage

First page:

$GET /v2/publications/pub_123/subscriptions?limit=10

Next page:

$GET /v2/publications/pub_123/subscriptions?limit=10&cursor=eyJ0aW1lc3RhbXAiOiIyMDI0LTA3LTAyVDE3OjMwOjAwLjAwMDAwMFoifQ==

Advantages

  • Consistent results: No duplicates or missing items during pagination
  • Performance: Efficient for large datasets
  • Real-time friendly: Works well when data changes frequently
  • No deep pagination issues: Maintains performance regardless of page depth

Cursor-based pagination is optimized for performance and does not include total counts. Use the has_more field to determine if additional pages exist.

Offset-Based Pagination (Deprecated)

Offset-based pagination is deprecated and will be removed in a future API version. Please migrate to cursor-based pagination.

Offset-based pagination uses page numbers and limits. While still supported, it has several limitations:

  • Page limit: Requests beyond page 100 are blocked
  • Consistency issues: Results may shift when data changes
  • Performance degradation: Slower for deep pagination

Request Parameters

ParameterTypeDescription
pageintegerPage number (1-100)
limitintegerNumber of results per page (1-100, default: 10)

Response Format

1{
2 "data": [...],
3 "pagination": {
4 "page": 1,
5 "limit": 10,
6 "total_results": 1500,
7 "total_pages": 150
8 }
9}

Deprecation Timeline

  • Current: All offset pagination requests return deprecation warning headers
  • After page 100: Requests return a 400 error with migration guidance
  • Future: Complete removal of offset pagination support

Migration Guide

Step 1: Update Your Code

Replace offset pagination parameters:

1- GET /v2/publications/pub_123/subscriptions?page=1&limit=10
2+ GET /v2/publications/pub_123/subscriptions?limit=10

Step 2: Handle Response Changes

Update your response parsing:

1// Old offset pagination
2- if (response.pagination.page < response.pagination.total_pages) {
3- fetchNextPage(response.pagination.page + 1);
4- }
5
6// New cursor pagination
7+ if (response.pagination.has_more) {
8+ fetchNextPage(response.pagination.next_cursor);
9+ }

Step 3: Update Pagination Logic

1// Cursor-based pagination example
2async function getAllSubscriptions(publicationId, limit = 10) {
3 const allSubscriptions = [];
4 let cursor = null;
5 let hasMore = true;
6
7 while (hasMore) {
8 const params = new URLSearchParams({ limit: limit.toString() });
9 if (cursor) {
10 params.append('cursor', cursor);
11 }
12
13 const response = await fetch(
14 `/v2/publications/${publicationId}/subscriptions?${params}`
15 );
16 const data = await response.json();
17
18 allSubscriptions.push(...data.data);
19
20 hasMore = data.pagination.has_more;
21 cursor = data.pagination.next_cursor;
22 }
23
24 return allSubscriptions;
25}

Key Differences

FeatureOffset PaginationCursor Pagination
Page limit100 pages maxUnlimited
PerformanceDegrades with depthConsistent
ConsistencyMay have gaps/duplicatesAlways consistent
Total countAlways includedNot included (performance optimized)
Random accessYes (page number)No (sequential only)

Backward Compatibility

During the transition period:

  • Both pagination methods are supported
  • Offset requests include deprecation warning headers:
    • X-Pagination-Warning: Deprecation notice
    • X-Pagination-Migration-Guide: Link to this documentation
  • Requests beyond page 100 return a 400 error

Testing Your Migration

  1. Test cursor pagination: Verify your code handles cursor tokens correctly
  2. Check error handling: Ensure graceful handling of pagination errors
  3. Performance testing: Compare performance of cursor vs offset pagination
  4. Monitor headers: Watch for deprecation warnings in your logs

Best Practices

Cursor Pagination

  • Store cursors securely: Treat cursor tokens as opaque strings
  • Handle missing cursors: Start from the beginning if cursor is invalid
  • Use appropriate limits: Balance between API calls and memory usage
  • Cache strategically: Cache results but not cursor tokens

Error Handling

1try {
2 const response = await fetch(endpoint);
3
4 if (response.status === 400) {
5 // Handle pagination error (e.g., invalid cursor)
6 console.error('Pagination error:', await response.json());
7 // Restart from beginning
8 return fetchFromBeginning();
9 }
10
11 return await response.json();
12} catch (error) {
13 console.error('Request failed:', error);
14 throw error;
15}

Rate Limiting

Be mindful of rate limits when implementing pagination:

  • Respect rate limits: Don’t exceed API rate limits
  • Implement backoff: Use exponential backoff for rate limit errors
  • Batch wisely: Use appropriate page sizes to minimize requests

Support

If you need help migrating to cursor-based pagination:

  • Check our API Reference for endpoint-specific examples
  • Review the Rate Limiting documentation
  • Contact support if you encounter issues during migration