Slack API の新メソッドを試してみた【ストリーミング編】
2026 年に入ってから、Slack の Block Kit に新しいブロックが続々と追加されています。本シリーズでは、これらの新ブロックと関連する API を実際に試しながら紹介していきます。
- 第 1 弾: データ編
- 第 2 弾: 汎用表示編
- 第 3 弾: エージェント編
- 第 4 弾: ストリーミング編(本記事)
- 第 5 弾: 検証・CI 編
今回は、第 4 弾としてテキストストリーミング API である chat.startStream / chat.appendStream / chat.stopStream の 3 メソッドを紹介します。LLM アプリでお馴染みの、応答が少しずつ表示されていく表示を Slack アプリで実現するための API です。
これまでも chat.update で同じメッセージを繰り返し編集すればストリーミング風の表示は作れました。しかし、この方式はリクエストごとに全文を再度用意して再送する必要があり、更新頻度を上げるとレート制限にも達しやすいものでした。
これに対して、ストリーミング API では追記分だけを送ればよく、追記を担う appendStream のレート制限は緩めで、ますます扱いやすく改善されています。
ちなみに、第 3 弾で紹介した plan block と task_card block を逐次更新していく仕組みもこの API が担っています。
なお、今回はお馴染みの Block Kit Builder では検証できないため、Slack CLI の slack api コマンドで API を直接呼び出して検証します。
こちらのコマンドについては以下の記事をご参照ください。
メソッドの概要
| メソッド | 役割 | レート制限 |
|---|---|---|
| chat.startStream[1] | ストリーミングメッセージを開始する | Tier 2(毎分 20+) |
| chat.appendStream[2] | ストリーミング中のメッセージに追記する | Tier 4(毎分 100+) |
| chat.stopStream[3] | ストリーミングを終了しメッセージを確定する | Tier 2(毎分 20+) |
3 メソッドとも必要なスコープは chat:write のみです。start のレスポンスで受け取ったタイムスタンプを append と stop に渡すことで、1 つのメッセージに対して追記と確定を行います。
主要なパラメータ
chat.startStream
| 項目 | 内容 |
|---|---|
channel |
必須。チャンネル・スレッド・DM の ID |
markdown_text |
標準 Markdown 形式のテキスト。最大 12,000 文字 |
chunks |
ストリーミングチャンクの配列。markdown_text とは併用不可 |
thread_ts |
返信先のスレッド。通常のチャンネルでは省略すると invalid_thread_ts エラーになる |
recipient_user_id / recipient_team_id |
ストリーミングを受け取るユーザーとチームの ID。チャンネルへのストリーミング時は必須 |
task_display_mode |
タスクの表示方法。timeline(タスクカードをテキストと交互に個別表示)か plan(plan block にまとめて表示)。デフォルトは timeline |
重要なポイントとして、通常のチャンネルではスレッド返信としてしかストリーミングができません。
返信ではない通常投稿としての配信は、チャンネル全体が 1 セッションとなるような特殊な設定のチャンネルでのみ可能です。また、チャンネルへ配信する場合は recipient_user_id と recipient_team_id の指定が必須です。誰に向けたストリーミングかを Slack 側が把握する仕組みになっています。
chat.appendStream
channel と ts が必須で、markdown_text または chunks で内容を渡します。markdown_text は全文の再送ではなく、追記分だけを送る方式です。
chat.stopStream
同じく channel と ts が必須で、markdown_text または chunks で内容を渡す形式です。加えて、以下のような特有の項目があります。
| 項目 | 内容 |
|---|---|
blocks |
確定したメッセージの末尾にレンダリングされるブロックの配列。最大 50 個で、chunks 経由の 50 個とは別枠 |
metadata |
メッセージメタデータ |
session_status |
ストリーミング終了後に設定するセッションのステータス。active / processing / suspended / closed |
markdown_text でテキストをストリーミングする
経費精算の質問に答えるボットを想定して、3 メソッドを順に呼び出してみます。まずはストリーミング開始処理です。
$ slack api chat.startStream --json '{
"channel": "C0123456789",
"thread_ts": "<スレッド元となるメッセージのタイムスタンプ>",
"recipient_team_id": "T0123456789",
"recipient_user_id": "U0123456789",
"markdown_text": "調べています。\n\n"
}'
レスポンスの ts がストリーミングメッセージの識別子になります。この ts を指定して追記します。
$ slack api chat.appendStream --json '{
"channel": "C0123456789",
"ts": "<ストリーミング開始処理レスポンスのタイムスタンプ>",
"markdown_text": "## 出張費の精算期限\n\n**帰着日から 1 週間以内**に申請してください。"
}'
そして最後に停止します。第 3 弾で紹介した context_actions block を blocks に渡して、確定したメッセージの末尾にフィードバックボタンを付けてみます。
$ slack api chat.stopStream --json '{
"channel": "C0123456789",
"ts": "<ストリーミング開始処理レスポンスのタイムスタンプ>",
"blocks": [
{
"type": "context_actions",
"elements": [
{
"type": "feedback_buttons",
"action_id": "answer_feedback",
"positive_button": {
"text": { "type": "plain_text", "text": "👍" },
"value": "positive_feedback"
},
"negative_button": {
"text": { "type": "plain_text", "text": "👎" },
"value": "negative_feedback"
}
}
]
}
]
}'

メッセージの上書き更新と違って追記分だけを送ればよいので、LLM の出力をそのまま送信するだけで済みます。一気にそれらしい表示になりましたね!
chunks で思考過程をストリーミングする
次に chunks パラメータを使って、第 3 弾で紹介した plan block を逐次更新してみます。chunk には 4 種類があります。
| chunk の種類 | 用途 |
|---|---|
markdown_text |
Markdown テキストの追記 |
task_update |
タスクの追加・更新。id が同じものは更新として扱われる |
plan_update |
plan のタイトルの更新 |
blocks |
ブロック配列の追加。1 つの配列につき最大 50 個で、超過分は破棄され API 経由で警告が出る |
task_update chunk の構造は task_card block とほぼ同じですが、details と output が rich_text ではなく文字列である点が異なります。また task_update と plan_update の chunk サイズには 256 文字の制限があります。
task_display_mode に plan を指定してストリーミングを開始し、タスクを順に送信していきます。
$ slack api chat.startStream --json '{
"channel": "C0123456789",
"thread_ts": "<スレッド元となるメッセージのタイムスタンプ>",
"recipient_team_id": "T0123456789",
"recipient_user_id": "U0123456789",
"task_display_mode": "plan",
"chunks": [
{ "type": "plan_update", "title": "経費精算の質問に回答中" },
{ "type": "task_update", "id": "step_1", "title": "社内ドキュメントを検索", "status": "in_progress" }
]
}'
タスクの完了と次のタスクの開始は、同じ id に対する task_update で表現します。ts には先ほどと同様に、開始時のレスポンスの値を指定します。
$ slack api chat.appendStream --json '{
"channel": "C0123456789",
"ts": "<ストリーミング開始処理レスポンスのタイムスタンプ>",
"chunks": [
{ "type": "task_update", "id": "step_1", "title": "社内ドキュメントを検索", "status": "complete", "output": "経費精算ガイドが見つかりました" },
{ "type": "task_update", "id": "step_2", "title": "回答を生成", "status": "in_progress" }
]
}'

第 3 弾では plan block を静的な JSON として貼っていましたが、こちらがより実践的な実装です。
まとめ
本記事では、テキストストリーミング API の 3 メソッドをご紹介しました。
テキストの逐次表示から plan block の更新、フィードバックボタンの設置までをシンプルな実装で実現できるようになっており、エージェント用の表示コンポーネントがどんどん使いやすくなっている印象です。従来の chat.update を使われている方は、これを機に新しいメソッドを試してみてはいかがでしょうか?
次回はいよいよ最終回です。第 5 弾は検証・CI 編として、blocks.validate によるペイロード検証と CI への組み込みを試します。お楽しみに!






