← 所有文章
教學

透過 API 回覆 TikTok 留言:先驗證自有貼文與頂層目標

透過 UnifyPort 回覆 TikTok 留言時,先選擇已驗證屬於連線帳號的貼文,再選擇已確認的頂層留言,最後呼叫 POST /v1/accounts/{account_id}/posts/comments/reply,提交 post_id、comment_id 和 text。這不是私訊傳送介面,也不是操作任意影片留言的工具。accepted 只表示請求已接受,不保證公開顯示、送達或產生 webhook。

重點

  • 將帳號、貼文與留言識別碼一起保存,平台 ID 一律保留為字串。
  • 留言清單只涵蓋自有貼文的頂層留言,不是完整的巢狀回覆歷史。
  • 缺少 parent_comment_id,不能單獨證明目標是頂層留言。
  • 區分可重試的讀取與結果不明的寫入;回覆逾時或回執未確認時,不要自動重送。

先區分留言與私訊介面

TikTok 官方的 Query Video Comments 文件描述 Research API 的讀取能力:用 video_id 查詢留言,用 comment_id 查詢回覆,需要 research.data.basic scope。它與透過已連線帳號發佈回覆是不同契約,不要將其中的數值型 ID、分頁參數或授權標頭複製到 UnifyPort 請求。

同樣,TikTok Business Messaging 與 QR 收件匣比較處理的是私訊架構選擇。公開留言不是通用訊息傳送介面的對話目標。

本文使用 UnifyPort 非官方介面,範圍限定為目前登入 TikTok 帳號自己的貼文。尚未連線時,先完成 TikTok QR 授權流程。執行操作前確認授權完成且 runtime_status: running。工作區 API Key 僅存於後端,並檢查操作人員是否有權存取所選帳號。

啟用回覆按鈕前,先讀取貼文與留言

任務方法與 API 路徑範圍
尋找自有貼文GET /v1/accounts/{account_id}/posts僅目前登入帳號的貼文
查看單一貼文POST /v1/accounts/{account_id}/posts/info在 JSON 傳入 post_id,需要驗證歸屬
查詢留言POST /v1/accounts/{account_id}/posts/comments/list僅頂層留言,分頁參數放在 JSON
回覆留言POST /v1/accounts/{account_id}/posts/comments/reply自有貼文上已確認的頂層目標

先使用列出帳號貼文,再對選定貼文呼叫取得帳號貼文。貼上的影片網址不能當作歸屬證明。

呼叫列出頂層留言時,傳送所選 post_id 與 limit。limit 預設 20,範圍 1–50。第一頁省略 cursor,空字串無效。data.has_more 為 true 時,將 data.next_cursor 原樣作為下一次請求的 cursor;最後一頁不回傳游標。

每條分頁鏈應綁定原帳號與貼文。使用回傳 ID 選擇目標,不要依賴陣列位置或顯示名稱。頁面筆數較少不代表可以忽略 has_more,讀取失敗也不是空留言清單。

內容與作者欄位僅在可用時回傳。省略的 text 表示未知,不等於空留言;缺少 created_at 時,不要填入本地觀察時間。post_id 應保留為沒有前導零的正十進位整數字串,貼文與留言 ID 都不要轉為 JavaScript number。

提交一次經過確認的回覆

送出前,向操作人員顯示所選貼文、留言、帳號身分與草稿。建議在應用程式紀錄中將這些目標與核准文字綁定,避免清單更新後寫入目標改變。

以下示範函式只呼叫一次回覆頂層留言介面。請提供已驗證選擇的真實識別碼與伺服器端 API Key。它不是完整審核系統,不會在本地驗證歸屬,也不自動重試。

async function replyToTikTokComment({
  apiKey, accountId, postId, commentId, text
}) {
  if (typeof postId !== 'string' || !/^[1-9][0-9]*$/.test(postId)) {
    throw new Error('Use the returned post ID string');
  }
  if (typeof commentId !== 'string' || !commentId.trim() ||
      typeof text !== 'string' || !text.trim()) {
    throw new Error('Select a comment and provide reply text');
  }
  if (typeof accountId !== 'string' || !accountId.trim()) {
    throw new Error('Select the connected account');
  }
  const response = await fetch(
    `https://api.unifyport.ai/v1/accounts/${encodeURIComponent(accountId)}/posts/comments/reply`,
    {
      method: 'POST',
      headers: {
        'X-Api-Key': apiKey,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        post_id: postId, comment_id: commentId, text
      })
    }
  );
  const result = await response.json();
  return { httpStatus: response.status, result };
}

空白檢查只拒絕空輸入,不修改核准的文字。請求送出後,若網路呼叫或回應解析失敗,應保留「結果未知」,不要以通用 POST 重試迴圈包住函式。

根據實際結果處理,不製造確定性

結果意義建議處理
200,data.status: accepted請求已接受保存結果,不標示「已公開顯示」
選用的 data.comment取得新留言的可靠回執有則保存,不將其設為接受成功的必要條件
403 post_inaccessible貼文無法存取,原因未確定停止並檢查存取問題,不標記為已刪除
404 post_not_found已驗證貼文不存在更新選擇
404 comment_not_found驗證後找不到目標重新選擇;不代表搜尋過所有巢狀回覆
501 unsupported_by_provider不支援的渠道,或已確認的巢狀目標停止操作,不自行改傳私訊
寫入回執未確認後的 502 reply_post_comment_failed寫入結果未知留待複核,不自動重送

驗證不完整會阻止寫入。讀取端驗證不完整可以重試,但不代表結果未知的回覆也能安全重送。後續讀取沒有看到回覆,不能證明它從未建立,尤其清單只涵蓋頂層留言時。

在應用程式中依序處理同一目標的寫入、防止重複點擊,並將 request_id 與 HTTP 結果一起保存。這些是本地保護措施,不是 API 冪等保證。避免把客戶留言正文或 API Key 寫入一般日誌。

通知是獨立接收層,不是回覆回執

標準事件目錄包含 post.comment.created。只訂閱事件不會開啟留言輪詢:輪詢預設關閉,設定 provider_data.enable_comment: true 後需要啟動或重新連線,線上變更需要重新連線。先確認環境支援且接收端已就緒。啟動成功本身不能證明設定已套用;關閉輪詢也不會撤回已排入佇列的事件。

通知是盡力而為的訊號,可能延遲、重複、亂序或遺漏,不是完整歷史,也不保證每次回覆都有回執。依照webhook 投遞契約驗證簽章,並以事件 ID 去重。即使通知沒有 parent_comment_id,回覆前仍須驗證目標,不能從缺少欄位推論可回覆性。

常見問題

能回覆任意 TikTok 影片的留言嗎?

不能透過本文流程實現。文件要求驗證貼文屬於目前登入帳號,且只能回覆已確認的頂層留言。

accepted 代表回覆已顯示嗎?

不是。接受請求不保證顯示或送達。可靠留言回執是選用欄位,也不保證產生 webhook。

能分頁讀取所有巢狀回覆嗎?

不能。UnifyPort 留言清單只涵蓋頂層留言。TikTok Research API 是另一套讀取契約,不能直接替換。

上線前應測試什麼?

測試自有貼文、無法存取的貼文、多頁清單、字串 ID 保真、巢狀目標、重複點擊與網路結果不明。這些是建議驗收項目,不是已完成的測試結果。

下一步與參考資料

先用列出頂層留言建立唯讀目標選擇,再啟用回覆提交。

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

UnifyPort API

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

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