slack

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese
There is no first-party Slack CLI fit for daily use, so we drive the Slack Web API with
curl + jq
. The user's OAuth bearer token is in
$SLACK_TOKEN
; every call needs it as
Authorization: Bearer $SLACK_TOKEN
.
The Slack API ALWAYS returns 200 — check the JSON
ok
field for success. A failed call has
{"ok": false, "error": "<reason>"}
. Surface the
error
value verbatim to the user when it occurs.
Always start with
auth.test
to confirm the connection works AND to learn what bot user / team you're posting as. Many subsequent calls need the bot's user id (
auth.test
returns
user_id
).
目前没有适合日常使用的官方Slack CLI,因此我们通过
curl + jq
调用Slack Web API。用户的OAuth bearer token存储在
$SLACK_TOKEN
中;每次调用都需要将其作为
Authorization: Bearer $SLACK_TOKEN
参数传入。
Slack API始终返回200状态码——需检查JSON中的
ok
字段来判断请求是否成功。失败的请求会返回
{"ok": false, "error": "<reason>"}
。当出现错误时,直接将
error
的值展示给用户。
必须首先执行
auth.test
,确认连接可用,同时了解当前发送消息的机器人账号/团队信息。后续许多调用都需要机器人的用户ID(
auth.test
会返回
user_id
)。

Recipes

操作示例

Verify auth (always run first)

验证权限(必须首先执行)

sh
curl -sS -H "Authorization: Bearer $SLACK_TOKEN" \
  https://slack.com/api/auth.test
sh
curl -sS -H "Authorization: Bearer $SLACK_TOKEN" \
  https://slack.com/api/auth.test

{"ok": true, "team": "...", "team_id": "...", "user": "<bot>", "user_id": "U..."}

{"ok": true, "team": "...", "team_id": "...", "user": "<bot>", "user_id": "U..."}

undefined
undefined

Resolve a channel name to its ID (you'll need this a lot)

将频道名称解析为频道ID(高频操作)

sh
curl -sS -H "Authorization: Bearer $SLACK_TOKEN" \
  "https://slack.com/api/conversations.list?limit=1000&types=public_channel,private_channel" \
  | jq -r --arg name "general" '.channels[] | select(.name == $name) | .id'
sh
curl -sS -H "Authorization: Bearer $SLACK_TOKEN" \
  "https://slack.com/api/conversations.list?limit=1000&types=public_channel,private_channel" \
  | jq -r --arg name "general" '.channels[] | select(.name == $name) | .id'

Post a message

发送消息

sh
curl -sS -X POST https://slack.com/api/chat.postMessage \
  -H "Authorization: Bearer $SLACK_TOKEN" \
  -H "Content-Type: application/json; charset=utf-8" \
  -d "$(jq -nc \
        --arg ch "C0123456789" \
        --arg text "Deploy complete." \
        '{channel:$ch, text:$text}')"
sh
curl -sS -X POST https://slack.com/api/chat.postMessage \
  -H "Authorization: Bearer $SLACK_TOKEN" \
  -H "Content-Type: application/json; charset=utf-8" \
  -d "$(jq -nc \
        --arg ch "C0123456789" \
        --arg text "Deploy complete." \
        '{channel:$ch, text:$text}')"

Reply in a thread

在线程中回复

sh
curl -sS -X POST https://slack.com/api/chat.postMessage \
  -H "Authorization: Bearer $SLACK_TOKEN" \
  -H "Content-Type: application/json; charset=utf-8" \
  -d "$(jq -nc \
        --arg ch "C0123456789" \
        --arg ts "1777656720.123456" \
        --arg text "Thanks!" \
        '{channel:$ch, thread_ts:$ts, text:$text}')"
sh
curl -sS -X POST https://slack.com/api/chat.postMessage \
  -H "Authorization: Bearer $SLACK_TOKEN" \
  -H "Content-Type: application/json; charset=utf-8" \
  -d "$(jq -nc \
        --arg ch "C0123456789" \
        --arg ts "1777656720.123456" \
        --arg text "Thanks!" \
        '{channel:$ch, thread_ts:$ts, text:$text}')"

Search messages

搜索消息

sh
curl -sS -G \
  -H "Authorization: Bearer $SLACK_TOKEN" \
  "https://slack.com/api/search.messages" \
  --data-urlencode "query=in:#engineering deploy" \
  --data-urlencode "count=20"
sh
curl -sS -G \
  -H "Authorization: Bearer $SLACK_TOKEN" \
  "https://slack.com/api/search.messages" \
  --data-urlencode "query=in:#engineering deploy" \
  --data-urlencode "count=20"

Send a DM to a user (by email)

向用户发送私信(通过邮箱)

sh
USER_ID=$(curl -sS -G -H "Authorization: Bearer $SLACK_TOKEN" \
  "https://slack.com/api/users.lookupByEmail" \
  --data-urlencode "email=alice@example.com" \
  | jq -r '.user.id')
sh
USER_ID=$(curl -sS -G -H "Authorization: Bearer $SLACK_TOKEN" \
  "https://slack.com/api/users.lookupByEmail" \
  --data-urlencode "email=alice@example.com" \
  | jq -r '.user.id')

DM channels are auto-created the first time you postMessage to a user id.

首次向用户ID发送消息时会自动创建私信频道。

curl -sS -X POST https://slack.com/api/chat.postMessage
-H "Authorization: Bearer $SLACK_TOKEN"
-H "Content-Type: application/json; charset=utf-8"
-d "$(jq -nc --arg ch "$USER_ID" --arg text "Hi from the bot." '{channel:$ch, text:$text}')"
undefined
curl -sS -X POST https://slack.com/api/chat.postMessage
-H "Authorization: Bearer $SLACK_TOKEN"
-H "Content-Type: application/json; charset=utf-8"
-d "$(jq -nc --arg ch "$USER_ID" --arg text "Hi from the bot." '{channel:$ch, text:$text}')"
undefined

Upload a file to a channel

向频道上传文件

Two-step: create an upload URL, then complete.
sh
UPLOAD=$(curl -sS -G -H "Authorization: Bearer $SLACK_TOKEN" \
  "https://slack.com/api/files.getUploadURLExternal" \
  --data-urlencode "filename=report.pdf" \
  --data-urlencode "length=$(wc -c < report.pdf)")
URL=$(echo "$UPLOAD" | jq -r '.upload_url')
ID=$(echo "$UPLOAD" | jq -r '.file_id')

curl -sS -T report.pdf "$URL"

curl -sS -X POST https://slack.com/api/files.completeUploadExternal \
  -H "Authorization: Bearer $SLACK_TOKEN" \
  -H "Content-Type: application/json; charset=utf-8" \
  -d "$(jq -nc --arg fid "$ID" --arg ch "C0123456789" \
        '{files:[{id:$fid, title:"report.pdf"}], channel_id:$ch}')"
分为两步:创建上传URL,然后完成上传。
sh
UPLOAD=$(curl -sS -G -H "Authorization: Bearer $SLACK_TOKEN" \
  "https://slack.com/api/files.getUploadURLExternal" \
  --data-urlencode "filename=report.pdf" \
  --data-urlencode "length=$(wc -c < report.pdf)")
URL=$(echo "$UPLOAD" | jq -r '.upload_url')
ID=$(echo "$UPLOAD" | jq -r '.file_id')

curl -sS -T report.pdf "$URL"

curl -sS -X POST https://slack.com/api/files.completeUploadExternal \
  -H "Authorization: Bearer $SLACK_TOKEN" \
  -H "Content-Type: application/json; charset=utf-8" \
  -d "$(jq -nc --arg fid "$ID" --arg ch "C0123456789" \
        '{files:[{id:$fid, title:"report.pdf"}], channel_id:$ch}')"

Notes

注意事项

  • chat.postMessage
    to a public channel requires the bot to be a member of that channel.
    If you get
    not_in_channel
    , call
    conversations.join
    first (which also takes the channel id), then retry. Private channels and DMs need a manual invite — ask the user.
  • Always check
    .ok
    on the JSON response.
    not_authed
    /
    invalid_auth
    → ask the user to re-authorize at
    auth.acedata.cloud/user/connections
    .
  • Channel ids start with
    C
    (channels),
    D
    (DMs),
    G
    (private). Don't invent ids — always look them up via
    conversations.list
    or
    users.lookupByEmail
    .
  • Slack rate-limits aggressively;
    Retry-After
    is in the response headers if you get a 429. Sleep and retry rather than parallelizing.
  • 向公开频道发送
    chat.postMessage
    请求要求机器人是该频道的成员。
    如果收到
    not_in_channel
    错误,请先调用
    conversations.join
    (同样需要传入频道ID),然后重试。私有频道和私信需要手动邀请机器人——请告知用户操作。
  • 务必检查JSON响应中的
    .ok
    字段。如果出现
    not_authed
    /
    invalid_auth
    错误,请提示用户前往
    auth.acedata.cloud/user/connections
    重新授权。
  • 频道ID以
    C
    (公开频道)、
    D
    (私信)、
    G
    (私有频道)开头。不要自行编造ID——务必通过
    conversations.list
    users.lookupByEmail
    查询获取。
  • Slack的限流机制非常严格;如果收到429状态码,响应头中会包含
    Retry-After
    参数。请等待指定时间后重试,不要并行发送请求。