透過 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。
讓訊息接入變成一條穩定的產品管線。
先用統一 API 跑通傳送,再用標準事件把所有入站訊息接回業務系統。