如何在客服系統串接 WhatsApp 語音通話:從建立連結到接通回呼
在客服系統串接 UnifyPort WhatsApp 語音通話時,先由後端以 media_type: "voice" 準備通話,再把私密瀏覽器連結交給負責的客服。客服開啟連結並按下 Start call 後才會撥號。後端將回傳的 call_id 與客服任務關聯,透過通話事件追蹤結果。
本文涵蓋內測中的人工發起、一對一撥出通話。UnifyPort 使用非官方介面,這不是 Meta WhatsApp Business Calling API 的串接教學。功能總覽及申請方式請見通話內測公告。
1. 準備訊息帳號並選定對話
先向技術支援申請工作區通話資格。建立 API Key 不會自動啟用;is_beta 是唯讀資格標記,不能藉由修改工作區 metadata 自行開啟。
顯示通話操作前,確認 WhatsApp 訊息帳號已授權,且 runtime_status 為 running。從同一帳號選取私人對話,保留介面回傳的 conversation_id,不要改用電話號碼或自行組合平台識別碼。
在應用程式中,將選定的工作區、帳號、對話與客服任務綁定至本次操作,並由後端檢查操作人的權限。新訊息抵達或客服切換對話時,不應悄悄改變已準備好的通話對象。
以下流程將 API Key 保存在伺服器端,瀏覽器只取得本次所需的私密通話連結。
2. 由後端準備語音通話
將預留值換成工作區 API Key、已連線帳號及選定的對話,於伺服器端執行:
curl -X POST 'https://api.unifyport.ai/v1/calls' \
-H 'X-Api-Key: <YOUR_API_KEY>' \
-H 'Content-Type: application/json' \
-d '{
"account_id": "acc_example",
"to": { "id": "<conversation_id>", "type": "user" },
"media_type": "voice"
}'
建立通話文件規定成功時回傳 201 Created,回應結構如下。這些值僅供示範,不是真實通話回執:
{
"request_id": "req_example",
"data": {
"call_id": "call_example",
"direction": "outbound",
"media_type": "voice",
"state": "preparing",
"join_url": "https://calls.example.com/call/call_example#ticket=example-only",
"expires_at": "2026-10-27T08:02:00Z"
}
}
將 data.call_id 與選定的帳號、對話及任務一起儲存,並保留 request_id 供問題排查。將 data.join_url 視為機密,原樣交給負責本次通話的客服;完整連結不得進入日誌、分析追蹤或公開訊息。
201 與 preparing 只表示連結已準備好,不代表客戶手機已響鈴,也不代表客戶已接聽。
3. 讓客服在瀏覽器開始通話
在業務介面顯示選定的客戶及「可開始通話」提示,只向本次操作人提供 join_url。客服在通話頁允許麥克風存取,並於 expires_at 前按下 Start call。
準備期預設為建立後兩分鐘,但伺服器可調整,因此應讀取 expires_at,不要寫死截止時間。準備期限不限制已接通的通話長度。麥克風權限必須開啟,攝影機權限則為選用。
等待建立回應時,停用重複提交。若回應遺失,先顯示結果待確認並查詢目前通話,再考慮是否重新建立。停用按鈕無法協調多位客服,後端也必須處理帳號層級的通話衝突。
4. 透過 Webhook 關聯客服任務
若 Webhook 端點採用明確的事件清單,請保留仍需要的其他訂閱,並加入下列兩個事件。這只是欄位片段,不是完整的端點建立請求:
{
"subscribed_events": ["call.answered", "call.ended"]
}
內測工作區使用 *、空清單或省略清單時,也包含有權接收的通話事件。非內測工作區不會因使用萬用訂閱而取得通話事件權限。
| 觀察結果 | 應用程式的處理 |
|---|---|
建立回應的 data.call_id | 與選定的客服任務建立關聯 |
call.answered 的 data.call.id | 記錄本次通話已接通 |
call.ended 的 data.call.id、data.reason、data.duration_seconds | 記錄結束原因及接通時長 |
處理簽章事件前,先為端點設定 signing_secret,並將簽章密鑰保存在伺服器端。
依照 Webhook 投遞契約,以原始請求內文驗證簽章,並按事件信封的 id 去除重複。使用事件的 account_id 及 data.call.id 比對已儲存的關聯。處理延遲或重複事件時,不要讓已結束的通話在畫面上重新變成進行中。
另外保留「已接通」證據:duration_seconds 採無條件捨去,單憑 0 不能判定未接通。建立階段同步失敗可能沒有結束事件,HTTP 錯誤需獨立記錄。完整內容請見接通事件及結束事件文件。通話結束也不代表客服任務自動解決。
5. 查詢或結束受管理通話
恢復狀態或遺失通話識別碼時,使用查詢目前通話介面:
curl --get 'https://api.unifyport.ai/v1/calls/active' \
-H 'X-Api-Key: <YOUR_API_KEY>' \
--data-urlencode 'account_id=acc_example'
data: {} 表示該帳號目前沒有 UnifyPort 管理的通話。這不是通話歷史,不能證明上次嘗試的結果,也無法偵測 WhatsApp 原生應用程式中的通話。回應不會重新簽發一次性 join_url。
操作人決定結束一通已知通話時,使用儲存的 call_id 及其所屬帳號:
curl -X POST 'https://api.unifyport.ai/v1/calls/call_example/hangup' \
-H 'X-Api-Key: <YOUR_API_KEY>' \
-H 'Content-Type: application/json' \
-d '{"account_id":"acc_example"}'
掛斷介面回傳 ended 或 failed 終態;重複掛斷可能回傳既有終態。不要只因狀態為 failed 就再次掛斷,也不要為了消除建立衝突而結束其他客服的通話。
常見串接問題
| 情況 | 下一步 |
|---|---|
403 beta_feature_not_enabled | 請支援人員確認工作區資格,修改 metadata 無法啟用 |
| 準備連結過期 | 停止重複使用;確認目前通話後,讓客服明確決定是否重新準備 |
| 瀏覽器無法使用麥克風 | 先檢查通話頁的麥克風權限,再確認撥號是否正常 |
| 建立請求與既有通話衝突 | 查詢受管理通話,於業務系統確認負責客服及用途 |
| 建立或掛斷請求逾時 | 維持結果待確認,綜合目前狀態與已收到的事件後再決定是否重試 |
驗收一條完整客服流程
在已取得同意的測試對話中,檢查正常接通與掛斷、準備連結過期、拒絕麥克風權限、重複點擊、帳號衝突及 HTTP 回應遺失。確認事件重送不會產生重複任務記錄,完整通話連結也不會進入日誌。這些是串接時應執行的驗收項目,不是本文宣稱完成的實測結果。
可以自動撥打一批電話號碼嗎?
不可以。本流程需要帳號下的 conversation_id,並由人工在瀏覽器按下 Start call。
同一套串接可以接聽來電嗎?
目前內測不可以。call.incoming 是預留契約,出現在事件目錄不代表已開放來電。群組通話、錄音、轉寫、SIP/PBX 整合及 AI 語音客服也不在本次內測範圍。
團隊應從哪裡開始?
尚未取得資格時,可提供工作區 ID 及預計使用的客服情境,聯絡技術支援申請,不要傳送 API Key 或私密通話連結。啟用後,先依建立通話文件驗證一個明確選定的對話,再將操作入口串接至客服流程。
讓訊息接入變成一條穩定的產品管線。
先用統一 API 跑通傳送,再用標準事件把所有入站訊息接回業務系統。