← 所有文章
教學

WhatsApp 對話跨標籤交接:安全的 API 操作流程

透過 UnifyPort 將 WhatsApp 對話由一個工作流程標籤轉到另一個,需要兩次成員關係操作:先加入目標標籤,核實結果,再移除來源標籤。公開文件沒有承諾原子轉移。應保留無關標籤,讓未完成的交接保持可見;不要刪除整個標籤,也不要將請求逾時當成「一定沒有改動」。

重點

  • action: "remove" 是替選定對話移除標籤;刪除標籤是另一項操作。
  • 多個標籤可以並存,不能強制唯一負責人或唯一工作階段。
  • 先加入再移除有助維持可見性,但中途會暫時有兩個標籤。
  • 正式指派紀錄與交接進度應存於應用程式,不應只靠標籤推斷。

定義交接,而非取代全部標籤

WhatsApp 的標籤說明介紹用標籤整理對話,以及替同一對話加入多個標籤。頁面亦指出標籤正逐步轉為清單。這種介面用語轉變不代表 UnifyPort 的 label_id 欄位已改名,也不保證應用程式內所有清單都有對應 API。

以下是假設情境:對話已有「待處理」及「VIP」,客服想轉到「處理中」。預期改動是加入「處理中」、移除「待處理」,保留「VIP」,而不是將全部標籤換成「處理中」。

六月 API 更新介紹過標籤端點。交接時,要先分清操作對象:

意圖操作對象
建立或重新命名分類建立或更新標籤標籤定義
加入目標標籤成員關係 action: "add"此標籤下的選定對話
移除來源標籤成員關係 action: "remove"此標籤下的選定對話
停用分類刪除標籤標籤本身,而非單一對話的歸屬

不要用刪除標籤代替替一個對話移除標籤;其他對話可能仍使用該分類。

準備兩次操作

在選定訊息帳戶下讀取標籤目錄,取得來源及目標 ID,並完成分頁。名稱只是顯示文字,不是穩定識別鍵。如需建立目標標籤,使用建立或更新標籤,保留傳回的 data.id。

在同一帳戶下確認對話的 conversation_id。不要把標籤名稱、聯絡人顯示名稱或訊息 ID 當成對話 ID。先核對操作支援矩陣:這些標籤操作目前支援 whatsapp,不支援 LINE、Telegram、Zalo,亦不支援獨立的 whatsapp-protocol 渠道。

標籤成員關係參考定義 POST /v1/accounts/{account_id}/conversations/labels,請求包含 label_id、action 及非空的 conversation_ids 陣列。

以下伺服器端 JavaScript 函式只執行一次操作,刻意不自動完成整個交接。請傳入後端實際選取的 ID 和安全儲存的 API key。這是示意程式碼,不是已測試的正式環境用戶端。

async function changeLabelMembership({
  apiKey, accountId, labelId, conversationIds, action
}) {
  const validId = value => typeof value === 'string' && value.trim() !== '';
  if (!validId(accountId) || !validId(labelId) ||
      !Array.isArray(conversationIds) || conversationIds.length === 0 ||
      !conversationIds.every(validId) || !['add', 'remove'].includes(action)) {
    throw new Error('Select an account, label, conversations, and action');
  }
  const response = await fetch(
    `https://api.unifyport.ai/v1/accounts/${encodeURIComponent(accountId)}/conversations/labels`,
    {
      method: 'POST',
      headers: { 'X-Api-Key': apiKey, 'Content-Type': 'application/json' },
      body: JSON.stringify({
        label_id: labelId,
        action,
        conversation_ids: [...new Set(conversationIds)]
      })
    }
  );
  const result = await response.json();
  return { httpStatus: response.status, result };
}

第一次呼叫使用目標 ID 及 add;之後使用來源 ID 及 remove,對話維持相同。在本地拒絕來源與目標 ID 相同的交接。檢查 HTTP 狀態及回應內容;fetch 正常回傳未必代表成功。文件中的成功回應會標識受影響的 label_id、action 及 conversation_ids。

在加入與移除之間設核實關卡

以下屬應用程式設計建議,不是 UnifyPort 的交易保證:

  1. 在本地保存預定帳戶、對話、來源及目標標籤,確認操作員有權更改指派。
  2. 加入目標標籤,記錄回應及 request_id,不要記錄 API key。
  3. 使用明確的 label_id 呼叫對話列表,讀取目標標籤檢視。確認選定對話已出現,再移除來源。
  4. 只移除來源成員關係,保留 VIP 等獨立標籤。
  5. 核對兩個檢視;觀察結果與預期不符時,顯示尚未完成的工作。

不要用未指定標籤的列表驗證目標。文件規定,WhatsApp 省略 label_id 時只傳回特別關注的對話。對話缺漏與標籤篩選排查解釋了這項邊界及分頁方式。第一頁找不到某個對話,不等於它不存在;讀取失敗亦不等於空結果。即時分頁讀取沒有不可變快照保證。

觀察到的歸屬對本次交接的解讀建議處理
只有來源尚未觀察到目標保留來源,調查加入操作
來源與目標皆有中間狀態,或其他編輯者的改動核實目前意圖,再移除來源
只有目標已觀察到預期歸屬模式本地指派仍一致時記錄完成
皆無,或讀取不完整狀態未釐清保留本地工作並調查,不猜測完成

復原時不要重送過期意圖

在應用程式中依序處理同一對話的改動,送出前拒絕過期的排隊工作。如果另一位客服已更改指派,不要盲目完成舊交接。本地依序處理不能鎖住所有已連結用戶端,因此要核對外部改動,不能聲稱獨佔控制。

加入逾時後,保留來源,先檢查目標再決定下一步。移除結果未確定時,先核對兩個檢視,再考慮重送。不要自動移除目標來「回復」:其他操作員可能已依賴該標籤。

公開參考沒有承諾兩次呼叫之間的原子性、整批全部成功或失敗、版本前置條件,或專用的標籤變更 webhook。批次處理應逐對話保存進度,不要視整批請求為一個已完成的指派。set_label_members_failed 對應文件所述的伺服器端或上游失敗;unsupported_by_provider 是功能支援邊界,不是無限重試的理由。

常見問題

加入新標籤會自動移除舊標籤嗎?

不會。API 分別提供加入和移除動作,應獨立處理每個標籤成員關係。

標籤可以強制只有一位客服負責嗎?

此契約沒有這種保證。將負責人和權限保存在應用程式,標籤只是渠道端的投影。

conversation.updated 能確認交接嗎?

不要作此假設。文件列出的設定包括靜音、封存、置頂及已讀狀態,並沒有保證提供標籤歸屬回執。

這是 WhatsApp Cloud API 官方操作嗎?

不是。這些是 UnifyPort 面向已連結帳戶的非官方接口端點。WhatsApp 應用程式說明只解釋用戶端概念,不定義此 API 契約。

下一步及參考資料

先閱讀為對話加入或移除標籤。在受控帳戶測試正常交接、目標加入失敗、移除逾時、競爭編輯、分頁及保留無關標籤,再啟用批次轉移。這些是建議驗收項目,不是已執行的測試結果。

資料核對日期:2026-10-14。

UnifyPort API

令訊息接入變成一條穩定嘅產品管線。

先用統一嘅 API 跑通發送,再用標準事件將所有入站訊息接返去業務系統。