X Chat 私訊疑難排解:登入狀態、金鑰版本與訊息簽章
X 帳號可以登入,不代表每個加密對話都已經能正常使用。帳號存取權限、正確的對話金鑰,以及有效的訊息簽章,是不同的條件。排查時應先確認問題出在驗證、加密訊息準備、傳送請求,還是訊息進入應用程式的過程。單靠「傳送失敗」無法判斷是簽章錯誤、流量限制或帳號受到限制。
先確認四件事
- 問題只影響一個對話,還是整個帳號?發生在傳送、接收,或兩者都有?
- 加密訊息需要對應版本的對話金鑰,不能只檢查快取裡是否有金鑰。
- X Chat 訊息簽章與 UnifyPort Webhook 簽章驗證屬於不同環節。
- 重試或調整帳號連線之前,先保留請求識別碼和發生時間。
登入狀態與聊天金鑰的分工
X 官方加密說明區分身分金鑰、簽章金鑰,以及有版本的對話金鑰。以下模型有助於定位問題:
| 材料 | 用途 | 應確認的事項 |
|---|---|---|
| 帳號工作階段 | 存取帳號 | 是否為預期的帳號,工作階段是否有效? |
| 身分私密金鑰 | 解開傳給該使用者的對話金鑰 | 是否有相符的身分金鑰材料? |
| 簽章私密金鑰 | 簽署訊息及支援的狀態變更 | 選用的簽章金鑰和版本是否正確? |
| 對話金鑰 | 加密或解密對話內容 | 是否有這則訊息所需版本的金鑰? |
這些檢查由不同層負責。使用代管連接器的開發者通常先看公開帳號狀態和錯誤回應,再由連接器維護者檢查協定層的金鑰。API 驗證成功並不能證明後面的條件也已滿足。
用來還原聊天金鑰的 Chat 通行碼,也不等同於 API key 或帳號登入憑證。還原失敗時,應沿用帳號擁有者原本的 Chat 設定,不要把重設通行碼當作一般重試。X 的 Chat 說明列出了無法取得通行碼時,加密歷史紀錄的還原限制。
變更設定前,先縮小問題範圍
保留一次失敗請求,與已知可用的操作比較。例如,個人資料查詢正常,只有某個對話無法傳送,應先調查該對話,不能直接判定整個服務無法連線。比較能縮小範圍,但還不是根因證明。
| 症狀 | 蒐集的資訊 | 下一步 |
|---|---|---|
| 帳號無法存取 | 驗證回應、帳號與執行狀態 | 依目前的授權文件處理存取問題。 |
| 單一對話傳送失敗 | 請求 ID、對話 ID、確切錯誤類別 | 請維護者檢查對話狀態、金鑰版本、token 和簽章輸入。 |
| 部分訊息無法解密 | 受影響的訊息 ID,以及能取得的金鑰版本 | 確認所需的歷史版本金鑰是否存在。 |
| 無法確定是否送出 | 請求時間、回應或逾時,以及接收端結果 | 核對這次操作後再決定是否重送;逾時可能留下未知結果。 |
| X 收到訊息,應用程式卻沒收到 | Webhook 設定、傳遞嘗試和接收端回應 | 分開檢查事件傳遞與 Chat 加密。 |
直接使用 X Chat SDK 時,可參閱 X 官方疑難排解,其中包含金鑰初始化、對話缺少金鑰、解密及簽章錯誤。該頁的 SDK 方法和錯誤訊息不等同於 UnifyPort 公開 API 契約。
缺少金鑰時,明確定義還原與失敗處理
連接器可以採用以下還原流程:
- 確定對話,以及事件指定的精確金鑰版本。
- 查詢該版本的快取。
- 透過整合方案支援的還原途徑,取得封裝後的金鑰材料。
- 驗證材料,以相應的身分私密金鑰解開,再寫入版本快取。
- 重新讀取快取,並在有限的重試策略內繼續原操作。
這是設計模式,並不保證所有已連接帳號都能還原全部歷史訊息。如果請求成功,但指定金鑰仍然不存在,就不能認定還原完成。同一把金鑰的並行請求可以共用還原工作,但每則訊息的結果仍須獨立記錄。舊金鑰應保留供歷史訊息使用,不應覆蓋較新的預設金鑰。
接收與傳送也需要不同的失敗決策。接收端應在支援的重試期間保留原始事件,不能把密文視為已解密的訊息。傳送端則必須明確決定,是回報錯誤,還是允許既有的替代傳送路徑。如果替代路徑改變了加密性質,就不能宣稱與加密傳送等效。兩種情況都不應無限重試。
簽章問題需要協定層的證據
當上游回應明確指出簽章失敗,維護者應檢查簽章金鑰選擇、傳送者身分、金鑰版本,以及實際參與簽署的位元組。再次送出相同的無效內容,不會修正輸入;停用簽章驗證也無法解決根因。
單一 HTTP 錯誤或籠統的 Provider 錯誤,不能證明簽章失敗。同樣,連接器修正簽章實作,不代表 X 修改了推薦演算法,也不能據此判定 X 最近更新過協定。
透過 UnifyPort 公開 API 排查
UnifyPort 為已連接的訊息帳號提供非官方介面。先核對目前的 X 授權指南,再查看 GET /v1/accounts/{account_id}/auth 和 GET /v1/accounts/{account_id}。驗證狀態與 runtime_status 用來判斷連線狀態,不是各個對話的加密健康檢查。
對既有的 POST /v1/messages 操作,可保留精簡的診斷摘要。以下函式接收已取得的 Response,不會傳送或重試訊息:
async function recordMessageAttempt(response) {
const body = await response.clone().json().catch(() => null);
console.info({
observed_at: new Date().toISOString(),
http_status: response.status,
request_id: body?.request_id ?? response.headers.get('X-Request-Id'),
code: body?.error?.code,
numeric_code: body?.error?.numeric_code,
});
}
訊息帳號 ID、相關對話及訊息 ID 應放在限制存取的事件紀錄中。公開的 code 和 numeric_code 以錯誤參考為準。provider_unavailable 這類概括回應不會揭示特定的 X 簽章錯誤,不能自行建立內部錯誤與公開錯誤碼的一對一對應。
函式刻意不記錄訊息本文、cookies、工作階段 URL、PIN 或金鑰。如果沒有收到 HTTP 回應,請記錄用戶端失敗、操作和時間;此時可能沒有伺服器請求 ID。不要自行產生 ID,再把它當作伺服器證據。
Webhook 簽章保護另一段連線
| 簽章 | 驗證對象 | 排查位置 |
|---|---|---|
| X Chat 訊息簽章 | 簽署過的 Chat 事件 | X Chat 用戶端或連接器協定實作 |
X-Device-Signature | UnifyPort 傳到接收端的請求 | Webhook 接收端及其 signing_secret |
後者使用 HMAC-SHA256 計算「時間戳記、一個句點、原始請求本文」,詳見 Webhook 傳遞文件。修正 HMAC 驗證不能補上 X 對話金鑰;HMAC 驗證成功,也不表示對方已收到某則傳出訊息。
可用 Webhook 優先的整合檢查清單核對接收設定,下游應用則可參考 X 私訊與提及監聽器實作。驗證收到的事件後先儲存,再進行較慢的路由工作。
常見問題
重新登入一定能取得缺少的金鑰嗎?
不能保證。更新工作階段不代表指定的身分金鑰或對話金鑰版本已可用。先確認缺少什麼,再決定是否重做帳號設定。
還原金鑰成功,就是訊息已送達嗎?
不是。金鑰可用、提交被接受、接收方收到訊息,以及 Webhook 服務完成處理,是不同的觀察結果。應驗證工作流程真正需要的結果。
可以呼叫 UnifyPort 公開端點還原 Chat 金鑰嗎?
本文沒有新增這類公開端點。請使用文件列出的公開 API,並將診斷識別碼提供給支援團隊。內部連接器操作不能直接當作公開 API 路由。
所有 X 私訊都可以稱為加密訊息嗎?
不可以。X 的 Chat 文件說明了未加密訊息請求的情境。請先確認實際的對話和傳送路徑,再說明其加密性質。
下一步
測試需要的訊息類型前,先查看目前的訊息支援矩陣。若直接串接 X 官方 Chat API,請使用其 SDK 和還原文件;它的驗證方式與事件契約和 UnifyPort 不同。
一手來源
核對日期:2026 年 9 月 10 日。
讓訊息接入變成一條穩定的產品管線。
先用統一 API 跑通傳送,再用標準事件把所有入站訊息接回業務系統。