この記事は旧バージョンの Amazon Connect Salesforce CTI アダプタに対する記事です。
最新の v5 系の CTI アダプタを使用している場合、GUI ベースの CTI Script を使用してイベントを処理することができます。詳細は公式のドキュメントをご確認ください。
Amazon ConnectではSalesforce用のOpen CTIアダプタが提供されており、最近ではSSOやオムニチャネル連動など便利な機能が増えてきました。しかし、着信時や切電時のようなテレフォニー側のイベントをSalesforceで処理するには少々工夫が必要です。簡単に思いつく方法としては以下があります。
-
ソフトフォンレイアウトにVisualforceページを指定してカスタムロジックを実行する
- 着信時だけであればこれが一番簡易ですが、一度余計な画面が挟まってしまいます。
- LightningコンポーネントでAmazon Connect Streams APIを利用する
- Locker ServiceというSalesforce独自のセキュリティルールのため、スクリプトを直接読み込むことができません…😭
- Open CTIアダプタそのものを作り直す
- VisualforceページであればStreams APIが読み込めますが、アダプタを作り直すのは単純に手間がかかりますし、標準で提供されているアダプタの機能はそのまま利用したいところです。
そこで、やや遠回りではありますが、Kinesisストリームに流れるAmazon ConnectのエージェントイベントをトリガにLambdaを起動してSalesforceに通知するサンプルを紹介します。
連携イメージ

設定手順
Amazon Connectでエージェントイベントストリームを有効化する
データストリーミングを有効化し、エージェントイベントのセクションでKinesisストリームを選択します。ない場合は新規作成します。
Salesforceでプラットフォームイベントを設定する
プラットフォームイベントは、Salesforceでイベント駆動型のシステム連携を実現するための仕組みです。[設定] - [プラットフォームイベント]からプラットフォームイベントを新規作成します。ここでは、ContactId(呼のId)、エージェントのユーザ名、呼のステータスを渡すための項目を作成してみます。

プラットフォームイベントをPublishするLambdaを作成する
サンプルのLambdaプログラムは以下の通りです。全量はこちらのリポジトリをどうぞ。エージェントイベントの構造は公式のドキュメントを参照してください。
import * as jsforce from 'jsforce';
import 'source-map-support/register';
import { Buffer } from 'buffer';
import { KinesisStreamEvent, KinesisStreamHandler } from 'aws-lambda';
export const index :KinesisStreamHandler = async (event :KinesisStreamEvent): Promise<any> => {
interface AgentEvent {
ContactId__c: String,
Username__c: String,
ContactState__c: String,
}
let sfEventList: AgentEvent[] = [];
for(const record of event.Records){
const base64Record = record.kinesis.data;
const decodedRecord = JSON.parse(Buffer.from(base64Record, 'base64').toString());
if(decodedRecord.EventType != "HEART_BEAT" && decodedRecord.CurrentAgentSnapshot.Contacts.length > 0){
sfEventList.push({
ContactId__c : decodedRecord.CurrentAgentSnapshot.Configuration.ContactId,
Username__c : decodedRecord.CurrentAgentSnapshot.Contacts[0].Username,
ContactState__c : decodedRecord.CurrentAgentSnapshot.Contacts[0].State
});
}
}
const conn = new jsforce.Connection({
loginUrl: process.env.LOGIN_URL
});
await conn.login(process.env.SALESFORCE_USERNAME, process.env.SALESFORCE_PASSWORD);
conn.sobject("AmazonConnectAgentEvent__e").insert(sfEventList);
return {
eventRecords : sfEventList
};
}
- KinesisストリームのイベントデータはBase64のためデコードが必要です。
-
EventType
がHEART_BEAT
のものはシステムイベントなので除外すると良いでしょう。 - コールフローで設定した問い合わせ属性はエージェントイベントには含まれないので、APIで取得する必要があります。
- Winter' 19以降に作成するプラットフォームイベントの種別は自動的に大量(High Volume)になりますが、コンタクトセンターの規模とプラットフォームイベントの制約を鑑みて必要な場合のみPublishしましょう。
SalesforceでプラットフォームイベントをSubscribeする
UIで処理が必要な場合はバックグラウンドのユーティリティ項目を、そうでない場合はApexトリガやプロセスビルダーを用いてSubscribeすると良いでしょう。以下はバックグラウンドのユーティリティ項目のサンプルです。
<aura:component implements="lightning:backgroundUtilityItem">
<lightning:empApi aura:id="empApi"/>
<aura:handler name="init" value="{!this}" action="{!c.doInit}" />
</aura:component>
({
doInit : function(component, event, helper) {
const empApi = component.find("empApi");
const channel = "/event/AmazonConnectAgentEvent__e";
const replayId = -1; //登録後に発生したすべての新規イベントを受信
// イベント受信時の処理
const onMessageCallback = (message) => {
console.log("Event received : " + JSON.stringify(message));
//ここに例えば一致するログインユーザに対してタブを制御する処理を入れるなど
};
// Subscribeの開始
empApi.subscribe(channel, replayId, onMessageCallback).then((value) => {
console.log("Subscribed to channel " + channel);
});
// エラー処理
empApi.onError((message) => {
console.log("Received error ", message);
});
}
})
messageの中身は以下のようになります。
{
"data": {
"schema": "HcRzaHqAkOE7bF_o5gQjiA",
"payload": {
"ContactId__c": "14f3a899-da72-4d39-a39f-84b6adae687b",
"ContactState__c": "CONNECTING",
"CreatedById": "0052v00000W0wg4AAB",
"CreatedDate": "2019-06-30T03:43:55Z",
"Username__c": "shun.kosaka"
},
"event": {
"replayId": 4711
}
},
"channel": "/event/AmazonConnectAgentEvent__e"
}
最後に、アプリケーションの設定で作成したユーティリティバーを含めれば完了です。
おわりに
Amazon ConnectのエージェントイベントストリームはWFMソリューションとの連携が大半の用途だとは思いますが、Salesforceでイベントを処理することで電話応対時のUXの向上やデータの統合(レポーティングに関してはSalesforceで行うのが良いのかという議論もありますが)などが実現可能です。より簡易に統合できるような、今後のOpen CTIアダプタのアップデートに期待したいところです。