Pagination
Navigate results with auto-pagination and async iterators
The SDK provides two ways to paginate: manual pagination with cursors and auto-pagination with async generators.
Manual Pagination
Every list() call returns data and pagination metadata:
interface ListResponse<T> {
data: T[]
pagination: {
next_cursor: string | null
has_more: boolean
}
}Fetch a Single Page
const page = await client.contacts.list({
limit: 25,
sort: '-created_at',
})
console.log(page.data) // Contact[]
console.log(page.pagination.has_more) // boolean
console.log(page.pagination.next_cursor) // string | nullFetch the Next Page
if (page.pagination.has_more && page.pagination.next_cursor) {
const nextPage = await client.contacts.list({
limit: 25,
sort: '-created_at',
cursor: page.pagination.next_cursor,
})
}Loop Through All Pages
const allContacts = []
let cursor: string | undefined
do {
const result = await client.contacts.list({
limit: 100,
cursor,
})
allContacts.push(...result.data)
cursor = result.pagination.next_cursor ?? undefined
} while (cursor)
console.log(`Total: ${allContacts.length} contacts`)Auto-Pagination
The listAll() method returns an AsyncGenerator that automatically fetches pages as needed:
for await (const contact of client.contacts.listAll()) {
console.log(contact.email)
}With Filters
All list parameters (except cursor) work with listAll():
for await (const deal of client.deals.listAll({
pipeline_id: 'pp_abc123',
sort: '-value',
limit: 100, // page size (not total limit)
})) {
console.log(`${deal.title}: ${deal.value}`)
}The limit parameter in listAll() controls the page size (how many items per API call), not the total number of results.
Collect into an Array
const allDeals: Deal[] = []
for await (const deal of client.deals.listAll({
pipeline_id: 'pp_abc123',
})) {
allDeals.push(deal)
}Break Early
You can break out of the loop at any time — no additional API calls will be made:
let count = 0
for await (const contact of client.contacts.listAll({ limit: 100 })) {
console.log(contact.email)
count++
if (count >= 500) {
break // stops fetching more pages
}
}Process in Batches
async function processBatches(batchSize: number) {
let batch: Contact[] = []
for await (const contact of client.contacts.listAll({ limit: 100 })) {
batch.push(contact)
if (batch.length >= batchSize) {
await processBatch(batch)
batch = []
}
}
// Process remaining items
if (batch.length > 0) {
await processBatch(batch)
}
}Available on All Resources
Auto-pagination works on every resource that supports listing:
// Contacts
for await (const c of client.contacts.listAll()) { ... }
// Companies
for await (const c of client.companies.listAll()) { ... }
// Deals
for await (const d of client.deals.listAll()) { ... }
// Pipelines
for await (const p of client.pipelines.listAll()) { ... }
// Activities
for await (const a of client.activities.listAll()) { ... }
// Custom Field Definitions
for await (const d of client.customFields.definitions.listAll()) { ... }
// API Keys
for await (const k of client.apiKeys.listAll()) { ... }Performance Tips
- Use
listAll()for simplicity — it handles everything automatically - Set
limit: 100for bulk operations to minimize API calls - Break early when you only need the first N results
- Use filters to reduce the total dataset before paginating
- Pages are fetched lazily — only when the current page is exhausted