Zendeskとの連携を構築している場合、APIがチケットデータベース全体を一度に渡さないことにすぐに気づくでしょう。代わりに、ページネーションと呼ばれるメカニズムを通じて、データを小さく分割して提供します。これは仕様によるものです。ページネーションは、APIの応答性を維持し、数千(または数百万)のサポートチケットを処理する際のタイムアウトを防ぎます。
しかし、ここからが面白いところです。Zendeskは、データをページネーションする2つの異なる方法を提供しています。カーソルページネーションとオフセットページネーションです。1つは高速で、最新で、事実上無制限です。もう1つは、10,000件のレコードに制限されており、古いAPI設計からのいくつかの遺産を引き継いでいます。2023年8月以降、Zendeskはオフセット方式に厳格な制限を課すことで、開発者をカーソルページネーションに移行させています。
このガイドでは、動作するコード例とともに、両方のページネーションアプローチについて説明します。各メソッドをいつ使用するか、エッジケースを処理する方法、および回避すべき落とし穴について学びます。また、自分でページネーションロジックを記述せずにZendeskワークフローを自動化する簡単な方法があるはずだと考えている場合は、それについても説明します。
Zendesk APIのページネーションについて
コードに入る前に、ページネーションが存在する理由と、それがどのように機能するかを大まかに説明しましょう。
Zendesk APIは、パフォーマンス上の理由から、大きな結果セットを小さなページに分割します。1回のAPI呼び出しで100,000件のチケットをリクエストすると、ほとんどのシステムでタイムアウトまたはクラッシュが発生します。代わりに、ページ1をリクエストし、それらの結果を処理してから、ページ2をリクエストします。これをすべて取得するまで繰り返します。
エンドポイントによって、デフォルトのページサイズが異なります。
- チケットとユーザー: 1ページあたり100アイテム
- ヘルプセンターの記事: 1ページあたり30アイテム
- 検索結果: 最大1ページあたり100アイテム
通常、制限内でページサイズを調整できますが、特定のエンドポイントの最大値を超えることはできません。
すべてのAPIリクエストは、レート制限に対してカウントされます。Zendeskでは、プランに応じて1分あたりのリクエスト数が制限されており、大規模なデータセットを取得する場合、ページネーションによってそのクォータをすぐに使い果たす可能性があります。良いニュースは、カーソルページネーションの方がオフセットページネーションよりも効率的であるため、メソッドを切り替えることで、APIの使用量を実際に削減できることです。
知っておくべき重要な変更点の1つは、2023年8月15日から、最初の10,000件のレコード(100ページ)を超えるオフセットベースのページネーションリクエストは、400 Bad Requestエラーを返すことです。10,000件を超えるレコードが必要な場合、カーソルページネーションが唯一のオプションになります。この変更の詳細については、Zendeskオフセットページネーションのお知らせをご覧ください。
カーソルページネーション:推奨される方法
カーソルページネーションは、ほとんどのリストエンドポイントでZendeskが推奨するアプローチです。これは、レコードを最初からカウントするのではなく、データセット内の位置を追跡するポインタ(カーソル)を使用します。これにより、APIがページを見つけるためにレコードをカウントしてスキップする必要がないため、大規模なデータセットでは大幅に高速になります。
カーソルページネーションの仕組み
カーソルページネーションを有効にするには、リクエストにpage[size]パラメーターを追加します。これにより、Zendeskにカーソルモードを使用することを示し、ページごとに返すアイテム数を指定します(ほとんどのエンドポイントで最大100)。
レスポンスには、次の2つのキーオブジェクトが含まれています。
- meta:
has_more(ブール値)、after_cursor、およびbefore_cursorが含まれています - links: 隣接するページの
nextおよびprevURLが含まれています
一般的なレスポンスは次のようになります。
{
"tickets": [
{ "id": 1, "subject": "Sample ticket" },
{ "id": 2, "subject": "Another ticket" }
],
"meta": {
"has_more": true,
"after_cursor": "eyJvIjoibmljZV9pZCIsInYiOiJhV2tCQUFBQUFBQUEifQ==",
"before_cursor": "eyJvIjoibmljZV9pZCIsInYiOiJhUzRCQUFBQUFBQUEifQ=="
},
"links": {
"next": "https://example.zendesk.com/api/v2/tickets.json?page[size]=100&page[after]=eyJvIjoibmljZV9pZCIsInYiOiJhV2tCQUFBQUFBQUEifQ==",
"prev": "https://example.zendesk.com/api/v2/tickets.json?page[size]=100&page[before]=eyJvIjoibmljZV9pZCIsInYiOiJhUzRCQUFBQUFBQUEifQ=="
}
}
meta.has_moreがfalseになるまでページネーションを続けます。その時点で、すべてのレコードを取得しました。
カーソルページネーションを使用したPythonの例
Pythonとrequestsライブラリを使用した完全な動作例を次に示します。
import requests
import time
ZENDESK_SUBDOMAIN = 'your-subdomain'
ZENDESK_EMAIL = 'your-email@example.com'
ZENDESK_API_TOKEN = 'your-api-token'
BASE_URL = f'https://{ZENDESK_SUBDOMAIN}.zendesk.com/api/v2/tickets.json'
auth = (f'{ZENDESK_EMAIL}/token', ZENDESK_API_TOKEN)
def fetch_all_tickets():
tickets = []
url = BASE_URL
params = {'page[size]': 100} # Use cursor pagination with 100 items per page
while url:
response = requests.get(url, auth=auth, params=params)
# Handle rate limiting
if response.status_code == 429:
retry_after = int(response.headers.get('Retry-After', 60))
print(f'Rate limited. Waiting {retry_after} seconds...')
time.sleep(retry_after)
continue
response.raise_for_status()
data = response.json()
# Process tickets from this page
for ticket in data['tickets']:
tickets.append(ticket)
print(f"Fetched ticket {ticket['id']}: {ticket['subject']}")
# Check if there are more pages
if data['meta']['has_more']:
url = data['links']['next']
params = None # Next URL already includes all parameters
else:
url = None
return tickets
if __name__ == '__main__':
all_tickets = fetch_all_tickets()
print(f'\nTotal tickets fetched: {len(all_tickets)}')
この例で注意すべき主な点は次のとおりです。
page[size]=100から始めて、カーソルページネーションを有効にします- レート制限(HTTP 429)を確認し、Retry-Afterヘッダーを尊重します
- 最初の要求の後、後続のページには
links.nextURLを直接使用します - ループは
has_moreがfalseになるまで続行されます
カーソルページネーションを使用したNode.jsの例
axiosを使用したNode.jsでの同じロジックを次に示します。
const axios = require('axios');
const ZENDESK_SUBDOMAIN = 'your-subdomain';
const ZENDESK_EMAIL = 'your-email@example.com';
const ZENDESK_API_TOKEN = 'your-api-token';
const BASE_URL = `https://${ZENDESK_SUBDOMAIN}.zendesk.com/api/v2/tickets.json`;
const auth = Buffer.from(`${ZENDESK_EMAIL}/token:${ZENDESK_API_TOKEN}`).toString('base64');
async function fetchAllTickets() {
const tickets = [];
let url = BASE_URL;
let params = { 'page[size]': 100 };
try {
do {
const response = await axios.get(url, {
headers: { Authorization: `Basic ${auth}` },
params: params
});
const data = response.data;
// Process tickets from this page
for (const ticket of data.tickets) {
tickets.push(ticket);
console.log(`Fetched ticket ${ticket.id}: ${ticket.subject}`);
}
// Prepare for next page
if (data.meta.has_more) {
url = data.links.next;
params = null; // Next URL includes all parameters
} else {
url = null;
}
} while (url);
console.log(`\nTotal tickets fetched: ${tickets.length}`);
return tickets;
} catch (error) {
if (error.response && error.response.status === 429) {
const retryAfter = error.response.headers['retry-after'] || 60;
console.log(`Rate limited. Retry after ${retryAfter} seconds`);
} else {
console.error('Error fetching tickets:', error.message);
}
throw error;
}
}
fetchAllTickets();
オフセットページネーション:レガシーメソッド
オフセットページネーションは、Zendeskがまだサポートしているものの、推奨しなくなった古いアプローチです。これは、ページ番号を指定することで機能し、APIはそのオフセットに基づいて、データセットの先頭からどのレコードを返すかを計算します。
オフセットページネーションの仕組み
オフセットページネーションでは、pageパラメーターを使用して特定のページ番号をリクエストし、オプションでper_pageを使用して1ページあたりのアイテム数(最大100)を設定します。
レスポンスには以下が含まれます。
- next_page: 次のページのURL。最後のページの場合はnull
- previous_page: 前のページのURL。最初のページの場合はnull
- count: データセット内のレコードの総数
一般的なレスポンスは次のようになります。
{
"tickets": [
{ "id": 1, "subject": "Sample ticket" },
{ "id": 2, "subject": "Another ticket" }
],
"count": 15420,
"next_page": "https://example.zendesk.com/api/v2/tickets.json?page=2",
"previous_page": null
}
オフセットページネーションを使用したPythonの例
オフセット方式を使用してページネーションを行う方法は次のとおりです。
import requests
import time
ZENDESK_SUBDOMAIN = 'your-subdomain'
ZENDESK_EMAIL = 'your-email@example.com'
ZENDESK_API_TOKEN = 'your-api-token'
BASE_URL = f'https://{ZENDESK_SUBDOMAIN}.zendesk.com/api/v2/tickets.json'
auth = (f'{ZENDESK_EMAIL}/token', ZENDESK_API_TOKEN)
def fetch_tickets_offset():
tickets = []
url = BASE_URL
while url:
response = requests.get(url, auth=auth)
if response.status_code == 429:
retry_after = int(response.headers.get('Retry-After', 60))
time.sleep(retry_after)
continue
if response.status_code == 400:
# You've hit the 10,000 record limit
print('Error: Cannot paginate beyond 10,000 records with offset pagination')
break
response.raise_for_status()
data = response.json()
for ticket in data['tickets']:
tickets.append(ticket)
# Move to next page
url = data['next_page']
return tickets
注意すべき制限事項
オフセットページネーションには、Zendeskが段階的に廃止している理由を説明するいくつかの欠点があります。
-
10,000件のレコードのハードリミット: オフセットページネーションを使用して10,000件を超えるレコードを取得することはできません。101ページ以降をリクエストしようとすると、400エラーが返されます。
-
パフォーマンスの低下: より深いページ(50ページ、90ページ)をリクエストすると、APIはすべての先行レコードをカウントしてスキップする必要があるため、応答に時間がかかります。
-
データの一貫性の欠如: ページネーション中にレコードが追加または削除された場合、重複が表示されたり、レコードが失われたりする可能性があります。これは、オフセットが現在のデータセットの状態に基づいて各リクエストに対して新たに計算されるために発生します。
-
カーソルページネーションでは合計数が表示されない: オフセットページネーションの1つの利点は、レコードの合計数である
countを返すことです。カーソルページネーションはこれを提供しないため、合計数が必要な場合は、別のAPI呼び出しが必要になります。
カーソル対オフセット:どちらを使用すべきか?
ほとんどのユースケースでは、選択は簡単です。
| 機能 | カーソルページネーション | オフセットページネーション |
|---|---|---|
| レコード制限 | 無制限 | 最大10,000 |
| パフォーマンス | 一貫性がある(深いページでも高速) | ページ番号が増加するにつれて低下する |
| 利用可能な合計数 | いいえ | はい(countプロパティ) |
| 任意のページへのジャンプ | 不可能 | 可能 |
| ページネーション中のデータの一貫性 | より良い | 重複/レコードの欠落が発生しやすい |
| Zendeskの推奨事項 | 推奨 | レガシーサポートのみ |
次の場合にカーソルページネーションを使用します。
- 10,000件を超えるレコードが必要な場合
- パフォーマンスが重要な場合(特に大規模なデータセットの場合)
- ジャンプする必要なく、データを順番に処理する場合
次の場合にオフセットページネーションを使用します。
- レコードの合計数が必要な場合
- ユーザーが特定のページにジャンプできるUIを構築している場合
- 小さなデータセット(10,000件未満のレコード)を扱っており、シンプルさが重要な場合
現在オフセットページネーションを使用しており、10,000件のレコード制限に達している場合は、カーソルページネーションへの移行は簡単です。主な変更点は次のとおりです。
pageパラメーターをpage[size]に置き換えますnext_pageがnullかどうかではなく、meta.has_moreを確認しますnext_pageの代わりに、次のページのURLにlinks.nextを使用します
一般的なページネーションの落とし穴と解決策
動作するコードがあっても、本番環境ではエッジケースが発生します。最も一般的な問題の処理方法を次に示します。
レート制限の処理
レート制限を超えると、ZendeskはHTTP 429を返します。レスポンスには、待機する秒数を示すRetry-Afterヘッダーが含まれています。APIを繰り返し呼び出すのではなく、常に指数バックオフを実装してください。
import time
def make_request_with_backoff(url, auth, max_retries=5):
for attempt in range(max_retries):
response = requests.get(url, auth=auth)
if response.status_code == 429:
retry_after = int(response.headers.get('Retry-After', 60))
# Exponential backoff: wait longer with each retry
wait_time = retry_after * (2 ** attempt)
time.sleep(wait_time)
continue
return response
raise Exception('Max retries exceeded')
空のページの処理
場合によっては、has_moreがtrueであったにもかかわらず、次のリクエストがレコードを返さない空のページが発生することがあります。これは、前のページの最後のレコードがデータセット全体の最後のレコードであった場合に発生する可能性があります。この場合、以前のafter_cursor値を将来の使用のために保存します。
カーソルの有効期限
Export Search Resultsエンドポイントの場合、カーソルは1時間後に期限切れになります。処理にそれ以上の時間がかかる場合は、エクスポートを再開するか、データをより迅速に処理する必要があります。
Search APIの制限事項
Search APIには、独自のページネーションの癖があります。
- クエリあたりの最大結果数は合計1,000件
- 1ページあたりの最大結果数は100件
- オフセットページネーションのみを使用
- ページ11(1ページあたり100件の結果)をリクエストすると、422エラーが返されます
1,000件を超える検索結果が必要な場合は、代わりにExport Search Resultsエンドポイントを使用してください。このエンドポイントはカーソルページネーションをサポートし、1ページあたり最大1,000件のレコードを返します。詳細については、Zendesk Search APIドキュメントを参照してください。
APIなしでZendeskワークフローを自動化する
適切なページネーション、エラー処理、およびレート制限を備えたカスタムAPI連携を構築するには、多大な開発努力が必要です。コードを記述し、ZendeskがAPIを更新する際にそれを維持し、これまで説明したすべてのエッジケースを処理する必要があります。
多くのチームにとって、より簡単な方法があります。eesel AIは、Zendeskアカウントに直接接続し、すべてのデータ取得を自動的に処理します。ページネーションロジックを記述する代わりに、ビジュアルインターフェイスを通じて実行したいことを構成します。

仕組みは次のとおりです。
- 数分でeesel AIをZendeskアカウントに接続します
- AIは、過去のチケット、ヘルプセンターの記事、およびマクロから学習します
- プレーンな英語で自動化ルールを定義します(コードは不要)
- eesel AIは、すべてのAPI呼び出し、ページネーション、およびデータ処理を処理します
チケットのルーティング、エージェントの応答のドラフト作成、受信チケットのタグ付けと優先順位付け、およびレポートの生成を自動化できます。ページネーションコードを1行も記述せずに。
カスタム連携が必要なチームにとって、Zendesk APIは依然として適切な選択肢です。ただし、ワークフローを自動化し、効率を向上させることが目標である場合は、eesel AIのようなツールを使用すると、より迅速に目標を達成できます。
今すぐZendeskワークフローの自動化を開始する
ページネーションは、Zendesk APIを使用する際の基本的な概念です。カーソルページネーションは、より優れたパフォーマンスとレコード制限がないため、最新の連携のほとんどで明確な選択肢となります。オフセットページネーションは、小さなデータセットや、レコードの合計数が必要な場合に依然として役立ちますが、10,000件のレコード制限は、大規模なデータ取得には適していないことを意味します。
このガイドのコード例は、独自のプロジェクトでページネーションを実装するための確固たる基盤となるはずです。レート制限を適切に処理し、空のページのようなエッジケースに注意し、特定のユースケースに合ったページネーション方法を選択することを忘れないでください。
API開発を完全にスキップして、今すぐZendeskワークフローの自動化を開始したい場合は、eesel AIをお試しください。技術的な複雑さを処理するため、より優れたカスタマーサポートの提供に集中できます。
よくある質問
この記事を共有

Article by
Stevia Putri
Stevia Putri is a marketing generalist at eesel AI, where she helps turn powerful AI tools into stories that resonate. She’s driven by curiosity, clarity, and the human side of technology.



