このガイドでは、Apps API を使用してサーバーサイドのチャット統合を構築する方法について説明します。このコースを修了すると、統合によって次のことができるようになります。
Apps API に対する認証を行います。
エンドユーザーを作成または更新します。
そのエンドユーザーとのチャットを開始します。
Contact Center AI Platform からの Webhook イベントを受信して検証します。
チャットにテキスト メッセージを送信します。
チャット前の文字起こしのインポート、キュー選択の仮想エージェント ルーティング、エスカレーションの回避、メディアの添付ファイルなどのオプションのブランチを処理します。
会話が完了したら、チャットを終了します。
このガイドは、お客様所有のチャット エクスペリエンスを CCAI Platform に接続するバックエンド サービスを構築するデベロッパーを対象としています。このガイドは、CCAI Platform で API 認証情報を作成し、HTTPS Webhook エンドポイントをホストし、シークレットを安全に保存し、サーバーから HTTP リクエストを送信できることを前提としています。
このガイドは、Apps API Chat エンドポイントを補足するものです。リクエストとレスポンス スキーマの詳細については、API リファレンスをご覧ください。推奨されるエンドツーエンドの実装フローについては、このガイドをご覧ください。
用語
このドキュメントで適用される用語の定義は次のとおりです。
お客様: 独自のソフトウェアにチャット統合を実装している CCAI プラットフォームのお客様。
コンシューマ: Apps API にリクエストを送信し、CCAI Platform Webhook イベントを受信する、お客様所有のサーバーサイド アプリケーション。
エンドユーザー: お客様のソフトウェアを使用して、エージェントまたは仮想エージェントとのチャットを開始または継続するユーザー。
チャット: Apps API が作成する CCAI プラットフォームの会話リソース。
Webhook エンドポイント: CCAI Platform からチャット イベントを受信するコンシューマ アプリケーションの HTTPS エンドポイント。
始める前に
Firebase を追加する前に、次の準備をしてください。
アプリの API 認証情報
CCAI Platform で API 認証情報を作成します。[Settings] > [Developer Settings] > [API Credentials] の順に選択します。
認証情報のシークレットを安全に保存します。ブラウザやモバイル クライアントのコードで公開しないでください。
テナント URL の詳細
CCAI Platform のサブドメインとドメインを特定します。
Apps API のベース URL は次のとおりです。
https://YOUR_SUBDOMAIN.YOUR_DOMAIN/apps/api/v1
Webhook エンドポイント
CCAI Platform から POST リクエストを受信できるパブリック HTTPS エンドポイントをホストします。
CCAI Platform のデベロッパー設定でエンドポイントを構成します。
Webhook のプライマリ シークレットとセカンダリ シークレットを生成して保存します。
キューまたはメニューの設定
新しいチャットが入るキューまたはメニューを特定します。
キュー選択仮想エージェントを使用する場合は、API を介してチャットを作成する前に、その仮想エージェントを構成してエントリキューに割り当てます。
エンドユーザー ID
各エンドユーザーに対してシステムで使用する安定した識別子を決定します。
Apps API から返された CCAI Platform エンドユーザー ID を保存します。
レート制限の処理
- CCAI プラットフォームは、Apps API にレート制限を適用します。統合に再試行とバックオフを組み込み、単一のテナントにリクエストをバースト送信しないようにします。
認証と Webhook のセキュリティ
統合では、次の 2 つの認証パスを使用します。
サーバーから CCAI Platform へのリクエストの Apps API 認証。
CCAI Platform からサーバーへのリクエストの Webhook 署名検証。
Apps API リクエストを認証する
リクエストでは HTTP 基本認証が使用されます。CCAI Platform の [設定] > [デベロッパー設定] > [API 認証情報] で API トークンを作成し、[パスワード] フィールドに渡します(推奨)。テナントが以前の認証パスを使用している場合は、代わりに会社キーをユーザー名として、会社シークレットをパスワードとして渡すことができます。完全な認証設定については、Apps API リファレンスをご覧ください。次の例は、基本認証を使用して Apps API リクエストを認証する方法を示しています。
curl -X GET \
https://YOUR_SUBDOMAIN.YOUR_DOMAIN/apps/api/v1/chats/{chat_id} \
-u "YOUR_SUBDOMAIN:YOUR_API_TOKEN" \
-H "Accept: application/json"
認証情報はサーバーサイドのシークレット ストアに保存し、セキュリティ ポリシーに従ってローテーションします。ブラウザやモバイルアプリでは送信しないでください。
Webhook リクエストを確認する
CCAI Platform は、チャット イベントを Webhook エンドポイントに送信します。各 Webhook リクエストには、次のものが含まれます。
X-SignatureX-Signature-Timestamp
X-Signature ヘッダーには、プライマリ署名、セカンダリ署名、またはその両方を含めることができます。
primary=<primary_signature> secondary=<secondary_signature>
各署名は、Base64 でエンコードされた HMAC-SHA256 ダイジェストです。署名付きの値は、タイムスタンプ ヘッダーと未加工の JSON リクエスト本文を連結したものです。
X-Signature-Timestamp + raw_request_body
Webhook ハンドラで、次の操作を行います。
X-SignatureとX-Signature-Timestampを読み取ります。いずれかのヘッダーがない場合は、リクエストを拒否します。
古いタイムスタンプを拒否して、リプレイのリスクを軽減します。
JSON を解析する前に、未加工のリクエスト本文を読み取ります。
アクティブな各 Webhook シークレットを使用して、想定される署名を計算します。
受信した署名と想定される署名を、定数時間比較を使用して比較します。
アクティブなシークレットが一致する場合は、リクエストを受け入れます。
次の Ruby 実装例は、UJET Webhook 署名を検証する方法を示しています。
require "base64"
require "openssl"
require "active_support/security_utils"
def parse_ujet_signature(header)
header.to_s.split(/\s+/).each_with_object({}) do |part, result|
key, value = part.split("=", 2)
result[key] = value if key && value
end
end
def expected_signature(secret, timestamp, raw_body)
Base64.strict_encode64(
OpenSSL::HMAC.digest(
OpenSSL::Digest.new("sha256"),
secret,
"#{timestamp}#{raw_body}"
)
)
end
def secure_match?(received, expected)
return false if received.nil? || expected.nil?
return false unless received.bytesize == expected.bytesize
ActiveSupport::SecurityUtils.secure_compare(received, expected)
end
def verify_ujet_webhook!(request, primary_secret:, secondary_secret:)
signature_header = request.headers["X-Signature"]
timestamp = request.headers["X-Signature-Timestamp"]
return false if signature_header.nil? || timestamp.nil?
# Optional but recommended: reject stale requests.
return false if (Time.now.utc - Time.at(timestamp.to_i).utc).abs > 5.minutes
raw_body = request.body.read
signatures = parse_ujet_signature(signature_header)
expected = [
expected_signature(primary_secret, timestamp, raw_body),
expected_signature(secondary_secret, timestamp, raw_body)
].compact
received = [
signatures["primary"],
signatures["secondary"]
].compact
received.any? do |received_signature|
expected.any? do |expected_signature_value|
secure_match?(received_signature, expected_signature_value)
end
end
end
検証が成功した場合は、すぐに成功レスポンスを返し、イベントをべき等に処理します。Webhook の配信と API レスポンスは異なる順序で到着する可能性があるため、重複するレコードを作成せずに同じ状態変更を複数回受信できるように統合を構築します。
統合フロー
次のフローでは、エンドユーザーの作成、チャットの開始、CCAI Platform イベントの受信、メッセージの交換、チャットの終了を行います。
エンドユーザーを作成または更新する
目標: チャットを作成する前に、CCAI Platform にエンドユーザーのレコードがあることを確認します。
エンドポイント
エンドユーザーを作成または更新するには、次のエンドポイントを使用します。
POST /apps/api/v1/end_users
リクエストの例
次の例は、エンドユーザーを作成または更新するリクエスト本文を示しています。
{
"identifier": "customer-user-12345",
"email": "customer.user@example.com",
"name": "Customer User",
"phone": "+15551234567"
}
保存するデータ
レスポンスから CCAI Platform エンドユーザー ID を取得して、システムに保存します。チャットを作成するときに、その ID を使用します。
その後の流れ
エンドユーザーが存在しない場合、CCAI Platform は新しいレコードを作成します。
同じ識別子を持つエンドユーザーがすでに存在する場合、CCAI Platform はレコードを更新し、既存のエンドユーザーの情報を返します。
チャットを作成する
目標: エンドユーザー向けに新しい CCAI Platform チャットを開始します。
エンドポイント
新しいチャットを開始するには、次のエンドポイントを使用します。
POST /apps/api/v1/chats
リクエストの例
次の例は、チャットを作成するためのリクエスト本文を示しています。
{
"chat": {
"menu_id": 123,
"end_user_id": 456,
"lang": "en"
}
}
仮想エージェント ルーティングのオプションのコンテキスト
キュー選択仮想エージェントがアプリケーションのコンテキストを必要とする場合は、次の例に示すように、チャットの作成時にコンテキスト ペイロードを含めます。
{
"chat": {
"menu_id": 123,
"end_user_id": 456,
"lang": "en",
"context": {
"value": {
"customer_tier": "gold",
"issue_type": "billing"
}
}
}
}
仮想エージェントは、そのコンテキストの値を使用して、チャットを受信するキューを決定できます。
その後の流れ
Apps API はチャット リソースを返します。
CCAI Platform は、構成済みの Webhook エンドポイントに
chat_createdWebhook イベントを送信します。API レスポンスと Webhook イベントは、どちらの順序でも到着する可能性があります。どちらも、チャット ID をキーとする同じチャット レコードの更新として扱います。
Chat の Webhook イベントを処理する
目標: コンシューマ アプリケーションを CCAI Platform のチャット状態と同期させます。
Webhook エンドポイントは、CCAI Platform からのチャット ライフサイクル イベントとメッセージ イベントを処理します。少なくとも、以下を保存します。
チャット ID。
イベントタイプ。
イベントのタイムスタンプ。
イベントにメッセージが含まれている場合のメッセージ送信者、メッセージ タイプ、メッセージの内容。
イベントがルーティング動作を記述している場合のエスカレーションまたはデフレクションのデータ。
推奨される動作
イベントを処理する前に、すべての Webhook 署名を検証します。
処理されたイベント ID または決定論的なイベントキーを保存して、再試行で重複が作成されないようにします。
イベントを受け入れた後、2xx レスポンスを返します。
可能であれば、ダウンストリームの副作用を非同期で処理します。
その後の流れ
CCAI Platform がチャットの作成、着信したメッセージ、エージェント メッセージ、エスカレーションの変更、チャットの完了などのイベントを送信すると、アプリケーションはチャットの状態を更新します。
テキスト メッセージを送信する
目標: コンシューマ アプリケーションから CCAI Platform チャットにエンドユーザー メッセージを送信する。
エンドポイント
次のエンドポイントを使用して、チャットにテキスト メッセージを送信します。
POST /apps/api/v1/chats/{chat_id}/message
リクエストの例
次の例は、テキスト メッセージを送信するためのリクエスト本文を示しています。
{
"from_user_id": 456,
"message": {
"type": "text",
"content": "Hello, I need help with my order."
}
}
その後の流れ
CCAI プラットフォームがメッセージを受け入れます。
メッセージがエージェントまたは仮想エージェントの会話に表示されます。
Webhook エンドポイントは、メッセージのメッセージ イベントを受信します。これには、独自のアプリケーションが Apps API を介して送信したメッセージも含まれます。
CCAI Platform からメッセージを受信して表示する
目標: お客様が所有するチャット エクスペリエンスにエージェントまたは仮想エージェントのメッセージを表示する。
Webhook エンドポイントがメッセージ イベントを受信すると、次の処理が行われます。
Webhook 署名を検証します。
イベントが新しいかどうかを確認します。
チャット ID でチャットを識別します。
送信者とメッセージの種類を特定します。
お客様所有のチャット UI にメッセージをレンダリングします。
イベントを保持して、更新や再試行で会話履歴が失われないようにします。
その後の流れ
お客様所有のチャット UI には、エージェント、仮想エージェント、エンドユーザーから送信されたメッセージが正しい順序で表示されます。イベントが順不同で到着する場合は、イベント タイムスタンプと独自の永続レイヤを使用して表示順序を調整します。
仮想エージェントから人間のエージェントにエスカレーションする
目標: エンドユーザーがエージェントのサポートを必要としている場合に、チャットを仮想エージェントの処理から人間のキューに移動します。
統合でキュー選択仮想エージェントを使用している場合は、チャットをターゲット キューにルーティングするように仮想エージェントを構成します。サーバーがエスカレーションを直接開始する場合は、Apps API のエスカレーション エンドポイントを使用します。
エンドポイント
仮想エージェントから人間のエージェントにチャットをエスカレーションするには、次のエンドポイントを使用します。
POST /apps/api/v1/chats/{chat_id}/escalations
リクエストの例
次の例は、チャットをエスカレーションするリクエスト本文を示しています。
{
"reason": "by_end_user_ask",
"force_escalate": false
}
その後の流れ
ターゲット キューが利用可能な場合、チャットはエージェントの対応に移行します。
キューがチャットを受け入れることができず、デフレクションの代替手段が構成されている場合、CCAI Platform は仮想エージェントとのチャットを維持し、エンドユーザーが利用できる代替手段を含む
escalation_deflectedWebhook イベントを送信します。代替案がエスカレーション レスポンスに届くことはありません。統合により、利用可能なデフレクション オプションがエンドユーザーに表示されます。
エスカレーションの回避の選択を記録する
目標: エンドユーザーが選択したデフレクション オプションを CCAI プラットフォームに伝えます。
CCAI Platform がエスカレーション回避オプションを提供している場合は、エスカレーション更新エンドポイントを使用してエンドユーザーの選択を記録します。
エンドポイント
次のエンドポイントを使用して、デフレクションの選択でエスカレーション レコードを更新します。
PATCH /apps/api/v1/chats/{chat_id}/escalations/{escalation_id}
サポートされている deflection_channel 値:
email- エンドユーザーがメールによるデフレクション オプションを選択します。virtual_agent- エンドユーザーが仮想エージェントとの会話を継続することを選択します。human_agent- エンドユーザーが人間のエージェントを待つことを選択します。この値は、容量超過の偏向にのみ適用されます。
リクエストの例
次の例は、デフレクションの選択を記録するリクエスト本文を示しています。
{
"deflection_channel": "email"
}
このエンドポイントには、サポートされている deflection_channel 値のみを送信します。external_link は、エスカレーション更新エンドポイントの有効な値ではありません。エンドユーザーが外部のデフレクション リンクをたどると、チャットは終了します。
その後の流れ
CCAI Platform は、エスカレーションの選択を記録します。選択肢を記録しても、チャットはルーティングされません。インテグレーションは、選択に基づいて動作します。たとえば、メールの偏向のためにチャットを終了したり、待機を続ける選択肢のために force_escalate: true を使用して新しいエスカレーションを送信したりします。
チャットを終了
目標: 会話が完了したらチャットを終了します。
エンドポイント
アクティブなチャットを終了するには、次のエンドポイントを使用します。
PATCH /apps/api/v1/chats/{chat_id}/end
リクエストの例
次の例は、チャットを終了するためのリクエスト本文を示しています。
{
"ended_by_user_id": 456
}
その後の流れ
CCAI Platform がチャットを終了します。
Webhook エンドポイントが最後のチャット状態イベントを受信します。
アプリケーションは、チャットを完了としてマークし、そのチャットの新しいエンドユーザー メッセージの受け入れを停止します。
エンドユーザーがデフレクション オプションを選択したためにチャットが終了する場合は、その選択を記録する代わりにこのエンドポイントを使用しないでください。まずエスカレーションで選択内容を記録するか、PATCH /apps/api/v1/chats/{chat_id} を使用して 1 つのリクエストで選択内容を記録してチャットを終了し、ステータスとともに escalation_id と deflection_channel を指定します。選択肢が記録されずに終了したチャットでは、エスカレーションに選択肢が記録されず、デフレクション結果レポートにも表示されません。
高度なフロー
次のブランチは省略可能です。統合に適用されるフローのみを実装します。
チャット前の文字起こしをインポートする
このフローは、CCAI Platform チャットを作成する前に、エンドユーザーがシステムですでに会話(chatbot の会話など)を行っている場合に使用します。
チャットの作成時に、文字起こしのペイロードを追加します。エージェントは、この文字起こしからコンテキストを把握できるため、エンドユーザーが情報を繰り返す必要がありません。
Apps API リファレンスには、正確な文字起こしスキーマが含まれています。
キュー選択仮想エージェントを使用してチャットをルーティングする
このフローは、アプリケーションがすべての新しいチャットをエントリ キューに送信し、仮想エージェントが最終的なターゲット キューを決定する場合に使用します。
キュー選択用の仮想エージェントを作成します。
仮想エージェントをエントリキューに割り当てます。
チャットを作成するときにコンテキストを含めます。
コンテキストを検査し、チャットを適切なキューにエスカレーションするように仮想エージェントを構成します。
ターゲット キューが利用できない場合の転送オプションを処理します。
写真や動画を添付して送信する
エンドユーザーがお客様所有のチャット UI からメディアを送信する場合は、このフローを使用します。
メディアフローには 4 つのステージがあります。
ステージ 1 - 署名付きアップロード URL をリクエストする
写真または動画をアップロードするための署名付き URL をリクエストするには、次のエンドポイントを使用します。
POST /apps/api/v1/chats/{chat_id}/photos/upload
POST /apps/api/v1/chats/{chat_id}/videos/upload
ステージ 2 - 返されたストレージ URL にファイルをアップロードする
ファイルと、CCAI Platform が presigned-upload レスポンスで返すフィールドを含めます。
ステージ 3 - アップロードしたファイルをチャットに追加する
アップロードした写真や動画をチャットに追加するには、次のエンドポイントを使用します。
POST /apps/api/v1/chats/{chat_id}/photos
POST /apps/api/v1/chats/{chat_id}/videos
CCAI プラットフォームから返される media_id を保存します。チャット メッセージのペイロードは、メディア ID でメディアを参照します。
ステージ 4 - メディアをメッセージとして送信する
次のエンドポイントを使用して、チャットにメディア メッセージを送信します。
POST /apps/api/v1/chats/{chat_id}/message
リクエストの例
次の例は、写真の添付ファイルを送信するリクエスト本文を示しています。
{
"from_user_id": 456,
"message": {
"type": "photo",
"content": "Photo of the damaged item",
"media_id": 789
}
}
エンドポイントは、type、content、media_id をフラット値として受け入れます。content で指定されたネストされたオブジェクトは破棄され、メディア参照は失われます。動画メッセージには、video メッセージ タイプと動画 media_id を使用します。media_id は content の兄弟です。
チャット中にカスタムデータを送信する
統合で、お客様が定義したコンテキストをアクティブなチャットに添付する必要がある場合は、次のエンドポイントを使用します。
POST /apps/api/v1/chats/{chat_id}/custom_data
Apps API リファレンスでは、正確なペイロードの形状と予約キーの動作が定義されています。
チャット中にエンドユーザーの ID を更新する
チャットの開始後にエンドユーザーの ID が変更された場合、または判明した場合は、次のエンドポイントを使用します。
POST /apps/api/v1/chats/{chat_id}/end_user
たとえば、匿名のエンドユーザーがアクティブなチャット中にログインし、統合で CCAI Platform がチャットを更新されたエンドユーザー ID に関連付ける必要がある場合は、このエンドポイントを使用します。
CSAT または評価データを収集する
統合でチャット後の評価エクスペリエンスを管理する場合は、次のチャット CSAT と評価エンドポイントを使用します。
GET /apps/api/v1/chats/{chat_id}/csat
GET /apps/api/v1/chats/{chat_id}/rating
PATCH /apps/api/v1/chats/{chat_id}/rating
資格ルールと評価ペイロードの詳細については、Apps API リファレンスをご覧ください。