Paginating through lists using cursor pagination
The Zendesk Support, Talk, and Help Center APIs have several endpoints that return lists of items, such as tickets, users, or articles. For performance reasons, the API does not return large record sets all at once. It breaks up the results into smaller subsets and returns them in pages. The number of items per page varies by endpoint. For example, the tickets and users endpoints return 100 items per page while the articles endpoint returns 30 items per page.
This article explains how to paginate through the lists using cursor pagination. Cursor pagination is already supported by most resources, such as tickets and users, and will be progressively introduced to all resources. See the API documentation for the specific resource.
Zendesk recommends using cursor pagination instead of offset pagination where possible. Cursor pagination provides greatly improved performance when retrieving extremely large record sets. See Comparing cursor pagination and offset pagination for a comparison of the different pagination methods supported by the Zendesk APIs.
Disclaimer: Zendesk provides this article for instructional purposes only. Zendesk does not support or guarantee the code. Zendesk also can't provide support for third-party technologies such as Python and Ruby.
Using cursor pagination
To use cursor pagination instead of offset pagination, include the page[size]
parameter in the request parameters. This parameter is also used to specify the number of items to return per page. Most endpoints limit this to a maximum of 100. See the API documentation for the specific resource.
For example, a request to the tickets endpoint with the URL https://example.zendesk.com/api/v2/tickets.json?page[size]=100
would return a response with the following format:
"tickets": [ ... ],
"meta": {
"has_more": true,
"after_cursor": "xxx",
"before_cursor": "yyy"
},
"links": {
"next": "https://example.zendesk.com/api/v2/tickets.json?page[size]=100&page[after]=xxx",
"prev": "https://example.zendesk.com/api/v2/tickets.json?page[size]=100&page[before]=yyy"
}
The values xxx
and yyy
are example placeholder values.
Notice that the next
and prev
properties nested in the links
JSON object are URLs. Use these to retrieve the next or previous page of results. Using the above example:
- Make a request to the URL
https://example.zendesk.com/api/v2/tickets.json?page[size]=100&page[after]=xxx
to retrieve the next page of results. - Make a request to the URL
https://example.zendesk.com/api/v2/tickets.json?page[size]=100&page[before]=yyy
to retrieve the previous page of results.
Alternatively, use the after_cursor
and before_cursor
properties nested in the meta
JSON object to construct the URL to retrieve the next or previous page of results. Using the above example:
- Copy the value of
after_cursor
from the previous response to thepage[after]
request parameter of the subsequent request to retrieve the next page of results. - Copy the value of
before_cursor
from the previous response to thepage[before]
request parameter of the subsequent request to retrieve the previous page of results.
Repeat either of the above steps to continue paginating as desired, or until the has_more
property nested in the meta
JSON object is false. This indicates there are no further records and you should stop paginating. Save the value of after_cursor
or next
to retrieve new records in the future.
Occasionally, you may get an empty record set, where after_cursor
, before_cursor
, next
and prev
are null, even though has_more
was true in the previous page. This occurs when the final record returned by the previous page is the final record in the entire record set. In this case, save the previous value of after_cursor
for future usage.
Certain resources limit how long the value of after_cursor
is valid for. See the API documentation for the specific resource.
Filtering results
Certain resources allow filtering the record set by certain attributes. For example, users may be filtered by roles. See the API documentation for the specific resource.
Sorting results
Certain resources allow sorting the record set by certain attributes. For example, tickets may be sorted by their creation date. See the API documentation for the specific resource.
Limitations
It is not possible to jump to an arbitrary page number or location in the record set when using cursor pagination.
The total number of records in the set is not provided when using cursor pagination. Certain resources provide a different endpoint to retrieve this value. For example, the total number of users can be retrieved from the URL https://example.zendesk.com/api/v2/users/count.json
. See the API documentation for the specific resource.
Paginated data may be inaccurate due to the addition, removal or modification of records while you are paginating through the list. One way to reduce pagination inaccuracies -- though not eliminate them altogether -- is to sort the records by an attribute that cannot be modified, such as the id or the creation date, if this is supported by the resource.
Python example
This example uses the third-party Requests library. Authenticating the request is not shown.
import requests
url = 'https://example.zendesk.com/api/v2/users.json?page[size]=100'
while url:
response = requests.get(url)
data = response.json()
for user in data['users']:
print(user['name'])
if data['meta']['has_more']:
url = data['links']['next']
else:
url = None
Ruby example
Authenticating the request is not shown.
require 'net/http'
require 'json'
url = URI('https://example.zendesk.com/api/v2/users.json?page[size]=100')
while url do
request = Net::HTTP::Get.new(url)
response = Net::HTTP.start(url.hostname, url.port, use_ssl: true) do |http|
http.request(request)
end
data = JSON.parse(response.body)
data['users'].each { |user| puts user['name'] }
url = if data['meta']['has_more']
URI(data['links']['next'])
else
nil
end
end