send-feishu
npx skills add https://github.com/jssfy/k-skills --skill send-feishu
Agent 安装分布
Skill 文档
Send Feishu Message
Send messages, images, and files to Feishu groups or individuals.
Environment Variables
| Variable | Purpose | Required |
|---|---|---|
FEISHU_WEBHOOK |
Group Webhook URL | For text/card/image to group |
FEISHU_APP_ID |
App credential | For image/file upload & API send |
FEISHU_APP_SECRET |
App credential | For image/file upload & API send |
FEISHU_CHAT_ID |
Group chat ID (oc_xxx) |
For API send to group |
FEISHU_USER_OPEN_ID |
Personal open_id (ou_xxx) |
For send to individual |
Decision Logic
Choose the sending method based on content type and target:
Text/Card to group â Webhook (simple, no auth needed)
Image to group â Get token â Upload image â Webhook send image_key
File to group â Get token â Upload file â API send to chat_id
Image/File to person â Get token â Upload resource â API send to open_id
Text/Card to person â Get token â API send to open_id
Choosing Format
Use text â simple one-liner (status update, quick note).
Use card â content has title + body, structured data, summary, or report.
Use image â user explicitly asks to send an image file, screenshot, or chart.
Use file â user asks to send .html/.md/.pdf/.doc/.xls etc., or content is too long for card display.
Send to individual â user says “åç»æ”, “ç§å”, “åå°æçé£ä¹¦”, or specifies a person.
Step A: Get tenant_access_token
Required for image upload, file upload, and API message sending. Skip this step if only sending text/card via Webhook.
curl -s -X POST 'https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal' \
-H 'Content-Type: application/json' \
-d '{"app_id":"'"$FEISHU_APP_ID"'","app_secret":"'"$FEISHU_APP_SECRET"'"}'
Response: {"code":0,"msg":"ok","tenant_access_token":"t-xxx","expire":7200}
Extract the token and store in a variable for subsequent steps.
Step B: Upload Image (get image_key)
Required when sending an image. Supports JPEG/PNG/WEBP/GIF/TIFF/BMP/ICO, max 10MB.
curl -s -X POST 'https://open.feishu.cn/open-apis/im/v1/images' \
-H "Authorization: Bearer $TOKEN" \
-F 'image_type="message"' \
-F 'image=@"/path/to/image.png"'
Response: {"code":0,"data":{"image_key":"img_xxx"}}
Step C: Upload File (get file_key)
Required when sending a file. Max 30MB.
curl -s -X POST 'https://open.feishu.cn/open-apis/im/v1/files' \
-H "Authorization: Bearer $TOKEN" \
-F 'file_type="stream"' \
-F 'file_name="report.md"' \
-F 'file=@"/path/to/file"'
file_type values: opus (audio), mp4 (video), pdf, doc, xls, ppt, stream (binary, use as default).
Response: {"code":0,"data":{"file_key":"file_xxx"}}
Sending via Webhook
Send Text
curl -s -X POST "$FEISHU_WEBHOOK" -H "Content-Type: application/json" \
-d '{"msg_type":"text","content":{"text":"MESSAGE_HERE"}}'
Send Card
Pick header color by sentiment:
greenâ success, complete, doneorangeâ warning, attentionredâ error, failureblueâ info, neutral (default)purpleâ highlight, special
Short content (no special characters):
curl -s -X POST "$FEISHU_WEBHOOK" -H "Content-Type: application/json" \
-d '{
"msg_type":"interactive",
"card":{
"header":{"title":{"content":"TITLE","tag":"plain_text"},"template":"COLOR"},
"elements":[{"tag":"div","text":{"content":"BODY_LARK_MD","tag":"lark_md"}}]
}
}'
Long content or content with special characters ($, ", \n, etc.) â always use this pattern:
python3 - << 'EOF' | curl -s -X POST "$FEISHU_WEBHOOK" \
-H "Content-Type: application/json" -d @-
import json
card = {
"msg_type": "interactive",
"card": {
"header": {"title": {"content": "TITLE", "tag": "plain_text"}, "template": "COLOR"},
"elements": [
{"tag": "div", "text": {"content": "BODY LINE 1\nBODY LINE 2", "tag": "lark_md"}},
{"tag": "hr"},
{"tag": "div", "text": {"content": "SECTION 2 CONTENT", "tag": "lark_md"}}
]
}
}
print(json.dumps(card))
EOF
Card body supports lark_md: **bold**, *italic*, ~~strike~~, [link](url), \n for newlines.
Send Image via Webhook
After uploading image (Step B) to get image_key:
curl -s -X POST "$FEISHU_WEBHOOK" \
-H "Content-Type: application/json" \
-d '{"msg_type":"image","content":{"image_key":"img_xxx"}}'
Sending via API
Use API when sending files, or sending any content to an individual.
Send to Group (chat_id)
curl -s -X POST "https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=chat_id" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json; charset=utf-8" \
-d '{"receive_id":"'"$FEISHU_CHAT_ID"'","msg_type":"MSG_TYPE","content":"CONTENT_JSON_STRING"}'
Send to Individual (open_id)
curl -s -X POST "https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=open_id" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json; charset=utf-8" \
-d '{"receive_id":"'"$FEISHU_USER_OPEN_ID"'","msg_type":"MSG_TYPE","content":"CONTENT_JSON_STRING"}'
API Content Formats
The content field must be a JSON-encoded string (escaped JSON inside JSON).
Text:
{"receive_id":"ID","msg_type":"text","content":"{\"text\":\"Hello\"}"}
Image (after upload):
{"receive_id":"ID","msg_type":"image","content":"{\"image_key\":\"img_xxx\"}"}
File (after upload):
{"receive_id":"ID","msg_type":"file","content":"{\"file_key\":\"file_xxx\"}"}
After Sending
Check the response JSON:
- Webhook:
{"code":0,"msg":"success"}â success - API:
{"code":0,"msg":"success","data":{...}}â success code!= 0 â report the error:- 19001: webhook URL invalid
- 19021: signature check failed
- 19022: IP not whitelisted
- 19024: keyword check failed
- 99991663: token invalid or expired (re-run Step A)
- 230001: bot not in chat or no permission
Important
- Always escape special characters in JSON (quotes, backslashes, newlines)
- Use
printf '%s'or heredoc to safely pass message content to curl if it contains special characters - If required env vars are not set, tell user which ones to configure
- Keep messages concise â Feishu cards have display limits
- Token from Step A is valid for 2 hours; no need to refresh within a session
- App permissions required:
im:message:send_as_bot(send messages),im:resource(upload images and files)