WhatsApp共有受信箱で既読・未読状態を同期する方法
WhatsAppの共有受信箱では、Webhookを受信しただけで会話を既読にするべきではありません。担当者が実際に引き受けた時点、または対応を完了した時点で更新します。UnifyPortでは、conversation_idを指定して会話を既読にできます。特定メッセージまで開封扱いにする場合は、メッセージIDと送信者IDを必ずセットで渡します。再対応が必要なら未読に戻します。
要点
- 会話の既読・未読アクションは、現時点ではWhatsAppのみ対応しています。非対応のプロバイダーとアクションの組み合わせは
501 unsupported_by_providerになります。 POST /v1/accounts/{account_id}/conversations/readにはconversation_idが必要です。任意で特定メッセージまで既読にできます。up_to_message_idとup_to_message_sender_idはペアです。片方だけを送ると400 invalid_requestになります。- 未読に戻す操作に必要なのは
conversation_idだけです。 - 担当、保留、解決といった業務状態は自社システムに保存します。WhatsApp側の既読状態は、サポートキュー全体そのものではありません。
3種類の「既読」を分ける
安定した共有受信箱では、次の3つを別の状態として扱います。
- 自社キューの状態:新規、担当済み、保留、解決など、アプリケーションが定義する状態です。
- 接続したWhatsAppアカウントのチャット一覧状態:既読または未読です。会話を既読にするAPIと未読にするAPIで変更します。
- 受信者の開封イベント:
message.readWebhookは、アカウントから送ったメッセージを相手が読んだことを示します。担当者が受信チケットを開いたという意味ではありません。
ローカルな会話設定が変わると、UnifyPortはconversation.updatedイベントをマッピングできる場合があります。data.conversation.idがチャットを識別し、既読状態の変更はdata.readに現れます。このイベントは照合用のシグナルとして扱い、誰がいつ担当し、なぜ再オープンしたかは自社データベースに残してください。
イベントを適用する前に、raw bodyの署名を検証し、再送を冪等に処理します。受信処理の境界はWebhook HMAC・リプレイ対策・再送ガイドで確認できます。受信箱関連だけが必要なら、Webhookイベントフィルターのチュートリアルを使い、必要なイベントだけを明示的に購読します。
プロバイダー側の状態を変えるタイミング
すべての受信Webhookを自動で既読にすると、未対応のキューまで空に見えてしまいます。次のような明示的なルールを設定します。
| チームの操作 | 自社キュー | WhatsAppの操作 |
|---|---|---|
| 受信メッセージを保存 | new | なし |
| 担当者が引き受ける | assigned | 必要に応じて対象メッセージまで既読 |
| 対応を完了する | resolved | 会話全体を既読 |
| 後で対応する | waiting | 会話を未読 |
| 割り当て前に自動処理が失敗 | new | なし |
この分離により、ブラウザーの再読み込み、Webhookの再送、バックグラウンドのプレビューで未対応案件が消えることも防げます。
WhatsApp会話を既読にする
プロバイダーIDには@や:が含まれることがあるため、conversation_idはURLではなくJSON bodyに入れます。
会話全体を既読にするリクエストです。
curl -X POST "https://api.unifyport.ai/v1/accounts/$UNIFYPORT_ACCOUNT_ID/conversations/read" \
-H "X-Api-Key: $UNIFYPORT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"conversation_id": "8613912345678@s.whatsapp.net"
}'
特定の受信メッセージまでWhatsAppの開封扱いにする場合は、同じmessage.receivedイベントから3つのIDを取得します。
{
"conversation_id": "120363041234567890@g.us",
"up_to_message_id": "CURRENT-MESSAGE-ID",
"up_to_message_sender_id": "8613912345678@lid"
}
グループでは、up_to_message_sender_idに一致するdata.sender.idを指定します。会話IDから推測してはいけません。メッセージ単位の処理が不要なら、2つのup_to_message_*フィールドを両方とも省略します。
次のNode.js helperは、フィールドのペアを確認してからAPIを呼び出します。
const apiBase = 'https://api.unifyport.ai/v1';
async function setWhatsAppReadState({ accountId, conversationId, unread, message }) {
const action = unread ? 'unread' : 'read';
const body = { conversation_id: conversationId };
if (!unread && message) {
if (!message.id || !message.senderId) {
throw new Error('message.id and message.senderId must be supplied together');
}
body.up_to_message_id = message.id;
body.up_to_message_sender_id = message.senderId;
}
const response = await fetch(
`${apiBase}/accounts/${encodeURIComponent(accountId)}/conversations/${action}`,
{
method: 'POST',
headers: {
'X-Api-Key': process.env.UNIFYPORT_API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify(body)
}
);
if (!response.ok) {
const failure = await response.json();
throw new Error(`${response.status} ${failure.error?.code ?? 'unknown_error'}`);
}
return response.json();
}
署名検証済みのイベントハンドラーでは、ドキュメントのフィールドをそのまま使います。
await setWhatsAppReadState({
accountId: event.account_id,
conversationId: event.data.conversation.id,
unread: false,
message: {
id: event.data.message.id,
senderId: event.data.sender.id
}
});
フォローアップする会話を未読に戻す
未読アクションはより単純です。
await setWhatsAppReadState({
accountId: event.account_id,
conversationId: event.data.conversation.id,
unread: true
});
チームが明示的に案件を再オープンしたときに使います。プロバイダーの未読状態だけをリマインダーにせず、担当者、期限状態、理由を自社キューに保存してください。
同期ループを作らずに照合する
アプリケーションが会話アクションを実行すると、対応するconversation.updatedがWebhookに届くことがあります。自社から開始した操作を内部レコードに残し、受信イベントは確認に使います。同じアクションを再び呼び出すトリガーにはしません。
安全な流れは次のとおりです。
message.receivedを冪等に保存する。- トランザクション内で自社チケット状態を更新する。
- プロバイダー状態のアクションを呼び出す。
- APIが
{ "data": { "ok": true } }を返してから成功を記録する。 conversation.updatedを確認、または接続アカウント側からの外部変更として処理する。- 不明な場合は会話取得APIで対象会話を取得し、
unread_countを比較する。
別のチャネルで同じUIを有効にする前に、プロバイダー別アクション対応表を確認してください。統一されたルートがあっても、全プロバイダーが同じアクションに対応するとは限りません。
制限と選択基準
認証済みビジネス機能、公式テンプレート送信、プロバイダー固有のガバナンスが必要なら、公式の接続方法が適しています。UnifyPortの非公式インターフェースは通常アカウントのメッセージ運用に使えますが、各チャネルの機能を完全に同一にはしません。
この既読・未読アクションは現時点ではWhatsAppのみです。日本の共有受信箱でLINEも扱う場合、LINE側の対応状況は自社キューで管理し、このWhatsApp専用コントロールは表示しないでください。501 unsupported_by_providerを一時障害として繰り返し再試行するべきではありません。
よくある質問
message.receivedを受信すると自動的に既読になりますか?
いいえ。イベントの受信と保存だけでキューを消してはいけません。チームが定義した業務タイミングで既読APIを呼び出します。
message.readと会話を既読にする操作は何が違いますか?
message.readは相手が送信済みメッセージを読んだことを示すイベントです。会話既読アクションは、接続アカウントのローカルなチャット一覧状態を変えます。
up_to_message_idだけ送れますか?
送れません。up_to_message_sender_idと一緒に送るか、両方を省略して会話全体を既読にします。
Telegram、LINE、TikTok、Zalo、Xでも同じ操作を使えますか?
現時点では使えません。対応表では、会話の既読・未読アクションはWhatsAppのみです。非対応の組み合わせは501 unsupported_by_providerになります。
次のステップ
まず会話を既読にするAPI Referenceを確認し、自社の再オープンルールを決めてから未読アクションを追加してください。
一次情報
2026年8月21日に確認: