1. はじめに
Zoom Phone API を使用すると、通話履歴(Call History)をプログラムから取得・分析できます。本記事では、2026年5月時点の最新仕様に基づき、通話ログのデータ構造と API の使い方を、実際の検証結果を交えて解説します。
この記事でわかること
- 通話ログデータの階層構造と各 ID の役割
- Call History API の各エンドポイントと使い分け
- Segment / Node の概念と実際の挙動
- 転送(Warm / Direct)を含む通話フローの追跡方法
本記事の検証履歴
- 初版: 2026年1月の検証結果に基づく
- 更新(2026年5月): 2026年5月18日以降、Call History API において転送通話(Warm Transfer / Direct Transfer)のログ構造が改善され、1つの Call History レコード内で全フェーズを確認可能になりました。
2. 通話ログのデータ構造
2-1. 概念的な階層
Zoom Phone の通話ログは以下の階層で構成されます。
| ID | 説明 | 用途 |
|---|---|---|
call_id |
論理的な通話単位。Direct Transfer では suffix(_1, _2 等)が付加される。Warm Transfer では転送後に新しい call_id が生成されるが、同一レコード内に格納される。 |
通話全体の追跡 |
call_history_uuid |
通話履歴レコードの一意識別子。id フィールドと同値。転送を含む通話では複数セグメントが1つの UUID に統合される。 |
詳細取得 API のパラメータ |
call_element_id |
通話内の各イベント(着信、転送、呼び出しなど)の識別子。 | 個別イベントの特定 |
2-2. Deprecated な ID について
以下は非推奨(deprecated)です。Legacy Call Logs API (v1) は 2026年5月に廃止予定のため、新規開発では使用しないでください。また、すでに利用しているお客様は以下のガイドを活用しマイグレーションを進めてください。
| Deprecated | 代替 | 状態(2026年5月時点) |
|---|---|---|
callLogId |
call_history_uuid |
廃止予定(未実施) |
call_path |
call_elements |
2026年11月廃止予定(まだ返却される) |
GET /phone/call_logs |
GET /phone/call_history |
廃止予定(まだ稼働中) |
GET /phone/call_logs/{callLogId} |
GET /phone/call_history/{callHistoryUuid} |
廃止予定 |
Legacy API (/phone/call_logs) は旧構造のレスポンスを返し続けています。 たとえば転送を含む通話では、Call History API が total_records: 2 を返す場合に、Legacy API は total_records: 6 を返すケースがあります。マイグレーション時にはレスポンス構造の違いに注意してください。
3. 使用する API エンドポイント
3-1. 一覧取得(概要情報)
アカウント全体の通話履歴
GET /phone/call_history
アカウント内のすべての通話履歴を取得します。管理者権限が必要です。
主なパラメータ
-
from/to:取得期間(最大1ヶ月、過去6ヶ月以内、デフォルト過去24時間) -
page_size:1回のレスポンスで返すレコード数(最大300、デフォルト30)
必要なスコープ
phone:read:list_call_logs:admin
2026年5月の仕様変更により、転送を含む通話が1つの call_history_uuid に統合されるようになったため、total_records が以前より少なくなる場合があります。
ユーザー単位の通話履歴
GET /phone/users/{userId}/call_history
特定ユーザーの通話履歴を取得します。
必要なスコープ
phone:read:list_call_logs または phone:read:list_call_logs:admin
3-2. 詳細取得
GET /phone/call_history/{callHistoryUuid}
特定の通話履歴の詳細(call_path、call_elements を含む)を取得します。
必要なスコープ
phone:read:call_log:admin
レスポンス例
{
"id": "20260108-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"call_history_uuid": "20260108-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"call_id": "1234567890123456789",
"direction": "inbound",
"duration": 6,
"start_time": "2026-01-08T05:35:15Z",
"answer_time": "2026-01-08T05:35:24Z",
"end_time": "2026-01-08T05:35:29Z",
"call_elements": [ ... ]
}
id と call_history_uuid は現状同じ値が格納されます。レスポンスには call_path 配列も含まれますが、2026年11月に廃止予定のため call_elements を使用してください。
個別イベントの詳細
GET /phone/call_element/{callElementId}
特定の call_element の詳細情報を取得します。call_element_id、call_id、call_history_uuid を含むレスポンスが返されます。
必要なスコープ
phone:read:call_log:admin
4. 詳細レスポンスの構造
4-1. call_elements の読み方
call_elements 配列には、通話内で発生した各イベントが格納されます。
コールキュー経由の着信例
{
"call_elements": [
{
"call_element_id": "20260108-aaa11111-1111-1111-1111-111111111111",
"event": "incoming",
"result": "answered",
"callee_name": "Sales Queue",
"callee_ext_number": "500",
"callee_ext_type": "call_queue",
"is_node": 1,
"segment": 1,
"node": 1
},
{
"call_element_id": "20260108-bbb22222-2222-2222-2222-222222222222",
"event": "ring_to_member",
"result": "answered",
"callee_name": "Taro Yamada",
"callee_email": "taro.yamada@example.com",
"callee_ext_number": "101",
"callee_ext_type": "user",
"callee_device_type": "ZoomPhone_iOS(6.5.0)",
"operator_name": "Sales Queue",
"operator_ext_number": "500",
"operator_ext_type": "call_queue",
"is_node": 0,
"segment": 1,
"node": 1
},
{
"call_element_id": "20260108-ccc33333-3333-3333-3333-333333333333",
"event": "ring_to_member",
"result": "no_answer",
"result_reason": "answered_by_other",
"callee_name": "Hanako Suzuki",
"callee_email": "hanako.suzuki@example.com",
"callee_ext_number": "102",
"callee_ext_type": "user",
"callee_device_type": "ZoomPhone_Web(5.7.5)",
"operator_name": "Sales Queue",
"operator_ext_number": "500",
"operator_ext_type": "call_queue",
"handler_name": "Taro Yamada",
"handler_ext_number": "101",
"is_node": 0,
"segment": 1,
"node": 1
}
]
}
4-2. 主要フィールド
| フィールド | 説明 | 主な値 |
|---|---|---|
event |
イベント種別 |
incoming, ring_to_member, direct_transfer_outgoing, direct_transfer_incoming, warm_transfer_outgoing, warm_transfer_incoming, forward, park, takeover など |
result |
イベントの結果 |
answered, no_answer, rejected, ring_timeout, busy, voicemail, overflowed, connected, succeeded など |
result_reason |
結果の詳細理由 |
answered_by_other, pickup_by_other など |
is_node |
親子関係フラグ |
1:親(CQ/IVR本体など)、0:子(メンバー) |
operator_* |
呼び出し元(オペレーター)の情報 | CQ 経由着信時はCQが、転送受信時は転送元ユーザーが operator |
handler_* |
実際に応答した人の情報 | 他者が応答した場合に設定 |
event フィールドの変更点(2026年5月以降)
転送関連のイベントに方向を示す suffix が追加されました:
| 旧(OpenAPI spec 上の定義) | 新(実際のAPIレスポンス) |
|---|---|
direct_transfer |
direct_transfer_outgoing / direct_transfer_incoming
|
warm_transfer |
warm_transfer_outgoing / warm_transfer_incoming
|
operator フィールドの詳細
operator_* フィールドは、呼び出し元の情報を格納します。以下のフィールドが存在します:
| フィールド | 説明 |
|---|---|
operator_name |
オペレーター名 |
operator_ext_number |
オペレーターの内線番号 |
operator_ext_id |
オペレーターの内線ID |
operator_ext_type |
オペレーターの種別(call_queue, user 等) |
コンテキストによって operator の意味が異なります:
| コンテキスト | operator の指す対象 | 例 |
|---|---|---|
| CQ メンバー呼び出し(Segment 1) | Call Queue 本体 | operator_name: "Sales Queue" |
| 転送受信(Segment 3) | 転送元のユーザー | operator_name: "Taro Yamada" |
4-3. Segment と Node の概念
Segment(セグメント)
Segment は通話の「フェーズ」を表します。転送が発生すると segment の値が増加します。
| Segment | 内容 |
|---|---|
| 1 | 初期着信フェーズ(外線 → CQ/SLG → メンバー応答) |
| 2 | 転送操作フェーズ(転送元 → 転送先への発信) |
| 3 | 転送受信フェーズ(転送先での着信・応答) |
転送タイプによる挙動
| 転送タイプ | Call ID | Segment | 備考 |
|---|---|---|---|
| Direct Transfer(ブラインド転送) | 同じ(suffix _N が付加) |
増加する | 同一レコード内で継続 |
| Warm Transfer(打診転送) | 転送後に新しい call_id が生成 |
増加する | 同一レコード内に統合 |
Warm Transfer の挙動変更(2026年5月以降)
以前は Warm Transfer を含む通話が複数の独立したレコード(call_history_uuid)として記録されていましたが、現在は Direct Transfer と同様に1つのレコード内に全セグメントが統合されるようになりました。
| Direct Transfer | Warm Transfer(旧) | Warm Transfer(現在) | |
|---|---|---|---|
| レコード数 | 1件 | 2-3件 | 1件 |
call_id |
同じ(suffix付加) | 新規生成 → 独立レコード | 新規生成 → 同一レコード内に共存 |
| Segment | 増加する | 増加しない | 増加する |
| 追跡方法 | API のみ | Webhook 必須 | API のみで可能 |
Call ID の Suffix(Direct Transfer)
Direct Transfer を実行すると、call_id に _1, _2, _3... のような suffix が付加されます。
- 元の
call_id:7641448793367995830 - Direct Transfer 発生 →
7641448793367995830_1
Suffix の数値は転送順序と一致しません。 内部的な採番ロジックにより、1回目の転送で _3、2回目で _1 が付与されるケースもあります。
-
_1だから最初の転送、という判定は避けてください - 転送順序の判定には
segment番号を使用してください
Node(ノード)
Node は各 Segment 内での「深さ」を表します。
通話が進行する中で、Auto Receptionist → Call Queue → User のように処理が深くなると node の値が増加します。
| node | 処理例 |
|---|---|
| 1 | Auto Receptionist での着信・IVR処理 |
| 2 | Call Queue への転送・メンバーへの呼び出し |
5. 転送の追跡
5-1. 転送時のレコード構造
転送が発生すると、1つの call_history_uuid 内に複数のセグメントとして記録されます。
ブラインド転送(Direct Transfer)の場合
Segment 1: 外線着信 → CQ → Agent A 応答 call_id: xxx
Segment 2: Agent A → Agent B への転送操作 call_id: xxx_1
Segment 3: Agent B の着信・応答 call_id: xxx_1
打診転送(Warm Transfer)の場合
Segment 1: 外線着信 → CQ → Agent A 応答 call_id: xxx
Segment 2: Agent A → Agent B への転送操作 call_id: yyy (新規)
Segment 3: Agent B の着信・応答 call_id: yyy (同上)
実データ比較
| Direct Transfer | Warm Transfer | |
|---|---|---|
call_history_uuid |
1件 | 1件 |
call_elements 数 |
8 | 8 |
| Segment | [1, 2, 3] | [1, 2, 3] |
Seg 1 の call_id
|
元の call_id
|
元の call_id
|
Seg 2-3 の call_id
|
元の call_id + suffix _1
|
新しい call_id(Webhook の transfer_call_id と一致) |
Seg 1 の event
|
incoming, ring_to_member
|
incoming, ring_to_member
|
Seg 2 の event
|
direct_transfer_outgoing |
warm_transfer_outgoing |
Seg 3 の event
|
direct_transfer_incoming |
warm_transfer_incoming |
Seg 2 の result
|
succeeded |
connected |
Seg 3 の result
|
answered |
answered |
recording_id |
各セグメントに1つ(計3つ) | 各セグメントに1つ(計3つ) |
5-2. 転送の紐付け方法
ブラインド転送の場合
call_id の suffix で転送フェーズを特定できます。
// Direct Transfer detection
const directTransferOut = callElements.filter(
el => el.event === 'direct_transfer_outgoing'
);
if (directTransferOut.length > 0) {
console.log('Direct Transfer detected');
// Segment-based analysis
const seg1 = callElements.filter(el => el.segment === 1); // Original call
const seg2 = callElements.filter(el => el.segment === 2); // Transfer outgoing
const seg3 = callElements.filter(el => el.segment === 3); // Transfer incoming
// call_id suffix identifies the transfer phase
const suffixedCallId = seg2[0]?.call_id; // e.g. "xxx_1"
}
打診転送の場合
Warm Transfer も call_elements 内でフロー全体を追跡できます。
// Warm Transfer detection
const warmTransferOut = callElements.filter(
el => el.event === 'warm_transfer_outgoing'
);
if (warmTransferOut.length > 0) {
console.log('Warm Transfer detected');
const seg1 = callElements.filter(el => el.segment === 1); // Original call
const seg2 = callElements.filter(el => el.segment === 2); // Transfer outgoing
const seg3 = callElements.filter(el => el.segment === 3); // Transfer incoming
const originalCallId = seg1[0]?.call_id; // e.g. "7641415185322237256"
const transferCallId = seg2[0]?.call_id; // e.g. "06a0bc2cf27a80eced6"
// transferCallId matches Webhook's transfer_call_id
}
Webhook との突合
phone.warm_transfer_initiated Webhook の transfer_call_id は、call_elements の Segment 2, 3 に含まれる call_id と一致します。これにより、Webhook で受信した情報と Call History API のデータを紐付けることができます。
function matchWebhookToCallHistory(webhookPayload, callElements) {
const { call_id: originalCallId, transfer_call_id } = webhookPayload.object;
// call_elements 内の Segment 1 に元の call_id が存在
const originalSegment = callElements.filter(
el => el.call_id === originalCallId
);
// call_elements 内の Segment 2-3 に transfer_call_id が存在
const transferSegments = callElements.filter(
el => el.call_id === transfer_call_id
);
return {
originalCallId,
transferCallId: transfer_call_id,
originalEvents: originalSegment.length,
transferEvents: transferSegments.length,
};
}
Webhook の transfer_call_id はリストAPI(GET /phone/call_history)に独立したレコードとしては出現しません。詳細API(GET /phone/call_history/{callHistoryUuid})の call_elements 内でのみ確認できます。
汎用的な転送検出
転送の種別を問わず、call_elements 内のセグメント数で転送の有無を判定できます。
function analyzeTransfer(callElements) {
const segments = [...new Set(callElements.map(el => el.segment))].sort();
if (segments.length === 1) {
return { hasTransfer: false, type: null };
}
// Segment 2 の event で転送種別を判定
const seg2Events = callElements
.filter(el => el.segment === 2)
.map(el => el.event);
if (seg2Events.includes('direct_transfer_outgoing')) {
return { hasTransfer: true, type: 'direct_transfer' };
}
if (seg2Events.includes('warm_transfer_outgoing')) {
return { hasTransfer: true, type: 'warm_transfer' };
}
return { hasTransfer: true, type: 'unknown' };
}
5-3. 転送種別の識別
call_elements 内の event フィールドで転送の種類を識別できます。
| event | 説明 |
|---|---|
warm_transfer_outgoing |
打診転送の発信側(転送操作を行った Agent のイベント) |
warm_transfer_incoming |
打診転送の受信側(転送先 Agent のイベント) |
direct_transfer_outgoing |
ブラインド転送の発信側 |
direct_transfer_incoming |
ブラインド転送の受信側 |
incoming |
着信(CQ/SLG/ユーザーへの初期着信、転送受信側) |
ring_to_member |
Call Queue メンバーへの呼び出し |
以前は warm_transfer / direct_transfer という単一のイベント名でしたが、現在は方向(_outgoing / _incoming)を示す suffix が付加されています。OpenAPI spec にはまだ旧名のみが記載されています。
5-4. モバイルクライアントでのWebhook発火
転送関連のWebhook(phone.warm_transfer_initiated、phone.blind_transfer_initiated 等)は、モバイルクライアント(iOS/Android)での操作でも問題なく発火することを確認しています。
ただし、API リファレンスには以下の注記があります:
Note: Applicable only to Zoom desktop clients (version 6.1.0 or later) using Zoom native phone numbers. Not applicable to IP phones or BYOC numbers.
この注記はデスクトップクライアントについて言及していますが、実際のテストでは:
- iOS版 Zoom Phone(6.5.1): ✅ 発火確認
- Android版 Zoom Phone(6.6.11): ✅ 発火確認
モバイルクライアントでも同様に動作することが確認できました。
検証環境: Zoom Phone Plan、Zoom ネイティブ番号使用。BYOC環境での動作は確認しておりません。
5-5. 通話Journey追跡のベストプラクティス
| 転送種別 | call_id |
追跡方法 |
|---|---|---|
| ブラインド転送 | 同じ(suffix 付加) |
call_elements の segment + call_id suffix で追跡 |
| 打診転送 | 新しい call_id が生成 |
call_elements の segment + call_id で追跡 |
いずれの場合も、call_elements 内の segment 番号でフェーズを特定し、event 名で転送種別を判定するのが推奨アプローチです。
Webhook(phone.warm_transfer_initiated / phone.blind_transfer_initiated)はリアルタイム通知として有用ですが、通話Journey の完全な追跡は Call History API のみで可能です。
推奨構成:
[Webhook] → リアルタイム通知(転送発生時に即座に検知)
↓
[Call History API] → 通話完了後に call_elements で完全なフローを取得
↓
[ビジネスロジック] → segment 分析で転送フローを再構築
6. おわりに
まとめ
| 目的 | 使用するフィールド / 方法 |
|---|---|
| 通話全体の追跡 |
call_history_uuid で詳細取得、call_elements で全セグメント把握 |
| 詳細取得 |
call_history_uuid で API 呼び出し |
| 応答者の特定 |
result: "answered" + handler_*
|
| 親子関係の判定 |
is_node(1=親、0=子) |
| 転送の検出 |
call_elements 内の segment 数 + event 名(*_outgoing / *_incoming) |
| 転送種別の判定 |
event 名:direct_transfer_* or warm_transfer_*
|
| 転送元の特定 |
operator_name / operator_ext_number
|
参考リンク
検証環境
- Zoom Phone Pro ライセンス
- コールキュー(一斉着信設定)
- テスト実施日:2026年1月8日(初版)、2026年5月19日(更新版)
本記事の内容は検証時点のものです。今後の API アップデートで挙動が変更される可能性があります。最新の仕様は公式ドキュメントおよび実際の API レスポンスで確認してください。
付録: 2026年5月の変更による影響まとめ
変更されたこと
| 項目 | 旧仕様 | 新仕様 |
|---|---|---|
| Warm Transfer のレコード数 | 2-3件の独立レコード | 1件に統合 |
event フィールド名 |
warm_transfer, direct_transfer
|
warm_transfer_outgoing/_incoming, direct_transfer_outgoing/_incoming
|
Warm Transfer の call_id
|
独立レコードに格納 | 同一レコードの call_elements 内に共存 |
| Warm Transfer の Segment | 増加しない | 増加する(1→2→3) |
recording_id |
各レコードに1つ | 同一レコード内に複数(各セグメントに1つ) |
Webhook transfer_call_id
|
リストAPIに独立レコードとして出現 | リストAPIに出現しない(call_elements 内にのみ存在) |
変更されていないこと
| 項目 | 状態 |
|---|---|
| Direct Transfer の基本構造(1レコード、segment増加、suffix付加) | 変更なし |
Webhook の発火(warm_transfer_initiated, blind_transfer_initiated) |
正常発火 |
call_path の返却(deprecated だがまだ存在) |
変更なし |
Legacy API (/phone/call_logs) の稼働 |
まだ稼働中 |
| GUI 上の通話履歴件数 | 変化なし |
