0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Chatworkシリーズ #12】Chatwork APIの「既読」は自分で制御できる — force=1とread/unread APIの使い分け

0
Last updated at Posted at 2026-03-19

朝の定例処理でChatworkのメッセージを自動取得していたら、ある日チームから言われた。「未読バッジが消えてるんですけど、誰か読みました?」

誰も読んでいない。APIが読んだのだ。

GET /rooms/{room_id}/messages はデフォルトで取得したメッセージを「既読」にする。自動化スクリプトが朝6時に走って、人間が起きる前に全部既読になっていた。未読をアテにして仕事の優先順位を決めていた人にとっては、これは事故だ。

ここから「APIで既読を汚さずにメッセージを取得する方法」を調べ始めた。結論として、Chatwork APIには既読を制御する3つの手段がある。

既読制御の3つの手段

1. force パラメータ(GET /rooms/{room_id}/messages)

# force=0(デフォルト): 未読メッセージのみ取得 → 取得したら既読になる
curl -s -H "X-ChatWorkToken: $TOKEN" \
  "https://api.chatwork.com/v2/rooms/${ROOM_ID}/messages"

# force=1: 既読含めて最新100件取得 → 既読状態を変えない
curl -s -H "X-ChatWorkToken: $TOKEN" \
  "https://api.chatwork.com/v2/rooms/${ROOM_ID}/messages?force=1"

force=0force=1 は挙動が全く違う。

パラメータ 取得範囲 既読への影響
force=0(デフォルト) 未読メッセージのみ 取得すると既読になる
force=1 最新100件(既読含む) 既読状態を変えない

正直、最初は「forceって何を強制してるんだ?」と思った。ドキュメントには「未読にかかわらず最新の100件を取得する」とだけ書いてある。既読を汚さないという副作用が自動化では一番重要なのに、そこは明記されていない。

2. PUT /rooms/{room_id}/messages/read — 既読にする

特定のメッセージまでを既読にするAPI。

# message_id を指定して、そこまでを既読にする
curl -s -X PUT \
  -H "X-ChatWorkToken: $TOKEN" \
  -d "message_id=12345" \
  "https://api.chatwork.com/v2/rooms/${ROOM_ID}/messages/read"

レスポンス:

{
  "unread_num": 0,
  "mention_num": 0
}

message_id を省略すると、そのルームの全メッセージが既読になる。部分的に既読にしたいときは message_id を指定する。

3. PUT /rooms/{room_id}/messages/unread — 未読に戻す

既読にしたメッセージを未読に戻すAPI。これが地味に使える。

# message_id を指定して、そこから未読に戻す
curl -s -X PUT \
  -H "X-ChatWorkToken: $TOKEN" \
  -d "message_id=12345" \
  "https://api.chatwork.com/v2/rooms/${ROOM_ID}/messages/unread"

レスポンス:

{
  "unread_num": 3,
  "mention_num": 1
}

指定した message_id 以降のメッセージが未読に戻る。

force=1 の5分制限という罠

force=1 は既読を汚さない便利なパラメータだが、レート制限が厳しい。公式ドキュメントには明記されていないが、実際に叩いてみると 5分に1回 程度の制限がかかる。

# 1回目: OK
curl -s -H "X-ChatWorkToken: $TOKEN" \
  "https://api.chatwork.com/v2/rooms/${ROOM_ID}/messages?force=1"
# → 200 OK, メッセージ返る

# 直後にもう一回: NG
curl -s -H "X-ChatWorkToken: $TOKEN" \
  "https://api.chatwork.com/v2/rooms/${ROOM_ID}/messages?force=1"
# → 200 OK だが空配列 []

ここが厄介なのは、429(Too Many Requests)が返るわけではないこと。ステータスコードは200で、ボディが空配列。エラーに見えない。「メッセージないのかな?」と誤解する。

複数ルームを順に取得するときは、ルーム間に5分以上のインターバルを入れるか、後述するread/unreadを組み合わせる方が現実的だ。

実践パターン: 自動取得で既読を汚さない

毎朝メッセージを吸い上げるスクリプトで、既読状態を保全するパターンは2つある。

パターンA: force=1 で取得(シンプル)

#!/bin/bash
TOKEN="$CHATWORK_API_TOKEN"
ROOM_ID="$TARGET_ROOM_ID"

# force=1 で既読を汚さず取得
messages=$(curl -s -H "X-ChatWorkToken: $TOKEN" \
  "https://api.chatwork.com/v2/rooms/${ROOM_ID}/messages?force=1")

# 取得したメッセージを処理
echo "$messages" | python3 -c "
import json, sys
msgs = json.load(sys.stdin)
for m in msgs:
    print(f\"[{m['account']['name']}] {m['body'][:80]}\")
"

1ルームだけならこれで十分。5分制限に引っかからない。

パターンB: force=0 + unread で復元(複数ルーム向け)

#!/bin/bash
TOKEN="$CHATWORK_API_TOKEN"
ROOM_IDS=("$ROOM_A" "$ROOM_B" "$ROOM_C")

for ROOM_ID in "${ROOM_IDS[@]}"; do
  # force=0 で未読メッセージを取得(既読になる)
  messages=$(curl -s -H "X-ChatWorkToken: $TOKEN" \
    "https://api.chatwork.com/v2/rooms/${ROOM_ID}/messages")

  if [ -z "$messages" ] || [ "$messages" = "[]" ]; then
    continue
  fi

  # 最初のメッセージIDを取得
  first_id=$(echo "$messages" | python3 -c "
import json, sys
msgs = json.load(sys.stdin)
if msgs:
    print(msgs[0]['message_id'])
")

  # 取得したメッセージを処理
  echo "$messages" | python3 -c "
import json, sys
msgs = json.load(sys.stdin)
for m in msgs:
    print(f\"[{m['account']['name']}] {m['body'][:80]}\")
"

  # 未読に戻す
  if [ -n "$first_id" ]; then
    curl -s -X PUT \
      -H "X-ChatWorkToken: $TOKEN" \
      -d "message_id=${first_id}" \
      "https://api.chatwork.com/v2/rooms/${ROOM_ID}/messages/unread" > /dev/null
  fi
done

force=0 で取って即 unread で戻す。5分制限を気にせず複数ルームを連続処理できる。

ただし注意点がある。force=0 で取得した瞬間に既読になるので、unread を呼ぶまでの数秒間は既読状態になる。その間にChatworkアプリを開いていると、一瞬バッジが消えて戻るという挙動になる。実用上は問題ないが、気持ち悪いと感じる人もいるかもしれない。

read/unread APIの活用シーン

既読制御が役に立つ場面をいくつか。

1. 自動既読マーク: ボットが処理済みのメッセージを既読にする。人間が見なくていいメッセージ(ログ通知など)を自動で既読にして、重要なメッセージだけ未読で残す。

# ボット自身のメッセージだけ既読にする
last_bot_msg_id=$(echo "$messages" | python3 -c "
import json, sys
msgs = json.load(sys.stdin)
bot_msgs = [m for m in msgs if m['account']['account_id'] == BOT_ACCOUNT_ID]
if bot_msgs:
    print(bot_msgs[-1]['message_id'])
")

curl -s -X PUT \
  -H "X-ChatWorkToken: $TOKEN" \
  -d "message_id=${last_bot_msg_id}" \
  "https://api.chatwork.com/v2/rooms/${ROOM_ID}/messages/read"

2. 未読リマインダー: 特定のメッセージを未読に戻して、後で対応するためのリマインダーにする。

3. 監視系の読み取り: ルームのメッセージを監視するが、既読は人間の判断に任せたい。force=1 で覗くだけ。

まとめ

手段 用途 レート制限
force=1 既読を汚さず取得 5分に1回
force=0 未読のみ取得(既読化する) 通常のAPI制限
read API 指定メッセージまで既読化 通常のAPI制限
unread API 指定メッセージ以降を未読に戻す 通常のAPI制限

自動化では force=1 を基本にして、複数ルームの連続取得が必要なら force=0 + unread を組み合わせる。この2パターンを押さえておけば、既読事故は起きない。

APIでメッセージを取得するだけなら5分で書ける。だが「既読を壊さない」という地味な要件を満たそうとすると、仕様の裏側を知る必要がある。ドキュメントに書いてあることと、実際に叩いて初めてわかることの差は、このAPIでは結構大きい。


Chatworkシリーズ

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?