← 所有文章
教學

如何在客服系統串接 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 或私密通話連結。啟用後,先依建立通話文件驗證一個明確選定的對話,再將操作入口串接至客服流程。

UnifyPort API

讓訊息接入變成一條穩定的產品管線。

先用統一 API 跑通傳送,再用標準事件把所有入站訊息接回業務系統。