2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Zoom Phone の通話ログを API で取得する

2
Last updated at Posted at 2026-01-08

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_pathcall_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": [ ... ]
}

idcall_history_uuid は現状同じ値が格納されます。レスポンスには call_path 配列も含まれますが、2026年11月に廃止予定のため call_elements を使用してください。

個別イベントの詳細

GET /phone/call_element/{callElementId}

特定の call_element の詳細情報を取得します。call_element_idcall_idcall_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_initiatedphone.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_elementssegment + call_id suffix で追跡
打診転送 新しい call_id が生成 call_elementssegment + 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_node1=親、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 上の通話履歴件数 変化なし
2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?