--- name: feishu-lark description: > Send messages and interactive cards to Feishu (飞书) and Lark channels via webhooks or Bot API. Create rich-text announcements, marketing updates, and team notifications. Trigger phrases: "post to feishu", "feishu message", "lark message", "feishu webhook", "lark webhook", "send to feishu", "send to lark", "feishu bot", "lark bot", "飞书", "飞书机器人". allowed-tools: - Bash - WebFetch - WebSearch --- # Feishu / Lark Messaging Skill You are a messaging specialist for Feishu (飞书, ByteDance's Chinese workplace platform) and Lark (the international version). Your job is to send messages, interactive cards, and marketing content to Feishu/Lark group chats via Custom Bot Webhooks or the App Bot API. ## Prerequisites Check which credentials are available: ```bash echo "FEISHU_WEBHOOK_URL is ${FEISHU_WEBHOOK_URL:+set}" echo "FEISHU_WEBHOOK_SECRET is ${FEISHU_WEBHOOK_SECRET:+set}" echo "FEISHU_APP_ID is ${FEISHU_APP_ID:+set}" echo "FEISHU_APP_SECRET is ${FEISHU_APP_SECRET:+set}" ``` ### Two Integration Modes | Mode | Credentials Required | Capabilities | |------|---------------------|--------------| | **Custom Bot Webhook** (simple) | `FEISHU_WEBHOOK_URL` (+ optional `FEISHU_WEBHOOK_SECRET`) | Send text, rich text, interactive cards to a single group | | **App Bot API** (full featured) | `FEISHU_APP_ID` + `FEISHU_APP_SECRET` | Send to any chat, upload images, at-mention users, manage cards, receive events | If no credentials are set, instruct the user: > **Custom Bot Webhook (quickest setup):** > 1. Open a Feishu/Lark group chat > 2. Click the group name at the top to open Group Settings > 3. Go to **Bots** > **Add Bot** > **Custom Bot** > 4. Name the bot and optionally set a Signature Verification secret > 5. Copy the webhook URL and add to `.env`: > ``` > FEISHU_WEBHOOK_URL=https://open.feishu.cn/open-apis/bot/v2/hook/{webhook_id} > FEISHU_WEBHOOK_SECRET=your_secret_here # optional, for signed webhooks > ``` > > **App Bot API (for advanced use):** > 1. Go to [Feishu Open Platform](https://open.feishu.cn/app) or [Lark Developer Console](https://open.larksuite.com/app) > 2. Create a new app, enable the Bot capability > 3. Add required permissions: `im:message:send_as_bot`, `im:chat:readonly` > 4. Publish and approve the app, then add to `.env`: > ``` > FEISHU_APP_ID=cli_xxxxx > FEISHU_APP_SECRET=xxxxx > ``` ### Webhook URL Formats - **Feishu (China):** `https://open.feishu.cn/open-apis/bot/v2/hook/{webhook_id}` - **Lark (International):** `https://open.larksuite.com/open-apis/bot/v2/hook/{webhook_id}` ### API Base URLs - **Feishu (China):** `https://open.feishu.cn/open-apis` - **Lark (International):** `https://open.larksuite.com/open-apis` --- ## 1. Custom Bot Webhook Messages ### 1.1 Plain Text Message ```bash curl -s -X POST "${FEISHU_WEBHOOK_URL}" \ -H "Content-Type: application/json" \ -d '{ "msg_type": "text", "content": { "text": "Hello from OpenClaudia! This is a test message." } }' ``` **At-mention everyone in the group:** ```bash curl -s -X POST "${FEISHU_WEBHOOK_URL}" \ -H "Content-Type: application/json" \ -d '{ "msg_type": "text", "content": { "text": "Everyone Important announcement: new release is live!" } }' ``` ### 1.2 Rich Text Message (Post) Rich text supports bold, links, at-mentions, and images in a structured format. ```bash curl -s -X POST "${FEISHU_WEBHOOK_URL}" \ -H "Content-Type: application/json" \ -d '{ "msg_type": "post", "content": { "post": { "zh_cn": { "title": "产品更新公告", "content": [ [ {"tag": "text", "text": "我们很高兴地宣布 "}, {"tag": "a", "text": "v2.0 版本", "href": "https://example.com/changelog"}, {"tag": "text", "text": " 已正式发布!"} ], [ {"tag": "text", "text": "主要更新:"} ], [ {"tag": "text", "text": "1. 全新用户界面\n2. 性能提升 50%\n3. 支持暗色模式"} ], [ {"tag": "at", "user_id": "all", "user_name": "所有人"} ] ] } } } }' ``` **English version (for Lark):** ```bash curl -s -X POST "${FEISHU_WEBHOOK_URL}" \ -H "Content-Type: application/json" \ -d '{ "msg_type": "post", "content": { "post": { "en_us": { "title": "Product Update Announcement", "content": [ [ {"tag": "text", "text": "We are excited to announce that "}, {"tag": "a", "text": "v2.0", "href": "https://example.com/changelog"}, {"tag": "text", "text": " is now live!"} ], [ {"tag": "text", "text": "Key updates:"} ], [ {"tag": "text", "text": "1. Brand new UI\n2. 50% performance improvement\n3. Dark mode support"} ], [ {"tag": "at", "user_id": "all", "user_name": "Everyone"} ] ] } } } }' ``` ### Rich Text Tag Reference | Tag | Purpose | Attributes | |-----|---------|------------| | `text` | Plain text | `text`, `un_escape` (boolean, interpret `\n` etc.) | | `a` | Hyperlink | `text`, `href` | | `at` | At-mention | `user_id` (use `"all"` for everyone), `user_name` | | `img` | Image (App Bot only) | `image_key` (requires uploading image first) | | `media` | Video/file (App Bot only) | `file_key`, `image_key` | ### 1.3 Signed Webhook Requests If `FEISHU_WEBHOOK_SECRET` is set, the webhook requires a signature for verification. **Generate a signed request:** ```bash # Calculate timestamp and signature TIMESTAMP=$(date +%s) STRING_TO_SIGN="${TIMESTAMP}\n${FEISHU_WEBHOOK_SECRET}" SIGN=$(printf '%b' "${STRING_TO_SIGN}" | openssl dgst -sha256 -hmac "" -binary | openssl base64) # For proper HMAC-SHA256 signing: SIGN=$(echo -ne "${TIMESTAMP}\n${FEISHU_WEBHOOK_SECRET}" | openssl dgst -sha256 -hmac "" -binary | base64) curl -s -X POST "${FEISHU_WEBHOOK_URL}" \ -H "Content-Type: application/json" \ -d "{ \"timestamp\": \"${TIMESTAMP}\", \"sign\": \"${SIGN}\", \"msg_type\": \"text\", \"content\": { \"text\": \"Signed message from OpenClaudia.\" } }" ``` **Feishu signature algorithm details:** 1. Concatenate `timestamp + "\n" + secret` as the string to sign 2. Compute HMAC-SHA256 with an empty key over that string 3. Base64-encode the result 4. Include both `timestamp` and `sign` in the request JSON body --- ## 2. Interactive Card Messages Interactive cards are the most powerful message format. They support headers, content sections, images, action buttons, and structured layouts. ### 2.1 Basic Card Structure ```json { "msg_type": "interactive", "card": { "header": { "title": { "tag": "plain_text", "content": "Card Title Here" }, "template": "blue" }, "elements": [] } } ``` ### Header Color Templates | Template | Color | Best For | |----------|-------|----------| | `blue` | Blue | General info, updates | | `green` | Green | Success, positive news | | `red` | Red | Urgent, alerts, errors | | `orange` | Orange | Warnings, action needed | | `purple` | Purple | Events, creative | | `indigo` | Indigo | Technical, engineering | | `turquoise` | Teal | Growth, marketing | | `yellow` | Yellow | Highlights, tips | | `grey` | Grey | Neutral, low priority | | `wathet` | Light blue | Default, clean | ### 2.2 Card Elements Reference **Markdown Content Block:** ```json { "tag": "markdown", "content": "**Bold text** and *italic text*\n[Link text](https://example.com)\nList:\n- Item 1\n- Item 2" } ``` **Divider:** ```json { "tag": "hr" } ``` **Note (small gray footer text):** ```json { "tag": "note", "elements": [ {"tag": "plain_text", "content": "Sent via OpenClaudia Marketing Toolkit"} ] } ``` **Image Block:** ```json { "tag": "img", "img_key": "img_v2_xxx", "alt": {"tag": "plain_text", "content": "Image description"}, "title": {"tag": "plain_text", "content": "Image Title"} } ``` **Action Buttons:** ```json { "tag": "action", "actions": [ { "tag": "button", "text": {"tag": "plain_text", "content": "View Details"}, "type": "primary", "url": "https://example.com/details" }, { "tag": "button", "text": {"tag": "plain_text", "content": "Dismiss"}, "type": "default" } ] } ``` **Button types:** `primary` (blue), `danger` (red), `default` (gray) **Multi-column Layout:** ```json { "tag": "column_set", "flex_mode": "bisect", "columns": [ { "tag": "column", "width": "weighted", "weight": 1, "elements": [ {"tag": "markdown", "content": "**Left Column**\nContent here"} ] }, { "tag": "column", "width": "weighted", "weight": 1, "elements": [ {"tag": "markdown", "content": "**Right Column**\nContent here"} ] } ] } ``` ### 2.3 Full Card Example: Product Announcement ```bash curl -s -X POST "${FEISHU_WEBHOOK_URL}" \ -H "Content-Type: application/json" \ -d '{ "msg_type": "interactive", "card": { "header": { "title": { "tag": "plain_text", "content": "New Feature Launch: AI-Powered Analytics" }, "template": "turquoise" }, "elements": [ { "tag": "markdown", "content": "We are thrilled to announce our latest feature!\n\n**AI-Powered Analytics** is now available to all Pro and Enterprise users.\n\nKey highlights:\n- **Smart Insights**: Automatic trend detection and anomaly alerts\n- **Natural Language Queries**: Ask questions in plain English\n- **Predictive Forecasting**: 90-day revenue and growth projections\n- **Custom Dashboards**: Drag-and-drop report builder" }, { "tag": "hr" }, { "tag": "markdown", "content": "**Availability:** Rolling out now, fully live by end of week\n**Documentation:** [View the guide](https://example.com/docs/analytics)\n**Feedback:** Reply in this thread or submit via [feedback form](https://example.com/feedback)" }, { "tag": "action", "actions": [ { "tag": "button", "text": {"tag": "plain_text", "content": "Try It Now"}, "type": "primary", "url": "https://example.com/analytics" }, { "tag": "button", "text": {"tag": "plain_text", "content": "Read Docs"}, "type": "default", "url": "https://example.com/docs/analytics" } ] }, { "tag": "note", "elements": [ {"tag": "plain_text", "content": "Product Team | Released 2025-01-15"} ] } ] } }' ``` --- ## 3. App Bot API (Full Featured) The App Bot API requires `FEISHU_APP_ID` and `FEISHU_APP_SECRET`. It provides full messaging capabilities including sending to any chat, uploading images, and managing messages. ### 3.1 Get Tenant Access Token All App Bot API calls require a `tenant_access_token`. Tokens expire after 2 hours. ```bash # For Feishu (China) FEISHU_API_BASE="https://open.feishu.cn/open-apis" # For Lark (International) # FEISHU_API_BASE="https://open.larksuite.com/open-apis" TENANT_TOKEN=$(curl -s -X POST "${FEISHU_API_BASE}/auth/v3/tenant_access_token/internal" \ -H "Content-Type: application/json" \ -d "{ \"app_id\": \"${FEISHU_APP_ID}\", \"app_secret\": \"${FEISHU_APP_SECRET}\" }" | python3 -c "import json,sys; print(json.load(sys.stdin).get('tenant_access_token',''))") echo "Token: ${TENANT_TOKEN:0:10}..." ``` ### 3.2 List Chats the Bot Belongs To ```bash curl -s "${FEISHU_API_BASE}/im/v1/chats?page_size=20" \ -H "Authorization: Bearer ${TENANT_TOKEN}" | \ python3 -c " import json, sys data = json.load(sys.stdin) for chat in data.get('data', {}).get('items', []): print(f\"Chat ID: {chat['chat_id']} | Name: {chat.get('name', 'N/A')} | Type: {chat.get('chat_type', 'N/A')}\") " ``` ### 3.3 Send Message to a Chat ```bash CHAT_ID="oc_xxxxx" # Replace with actual chat_id # Send a text message curl -s -X POST "${FEISHU_API_BASE}/im/v1/messages?receive_id_type=chat_id" \ -H "Authorization: Bearer ${TENANT_TOKEN}" \ -H "Content-Type: application/json" \ -d "{ \"receive_id\": \"${CHAT_ID}\", \"msg_type\": \"text\", \"content\": \"{\\\"text\\\": \\\"Hello from the App Bot!\\\"}\" }" ``` **Send a rich text message via the API:** ```bash curl -s -X POST "${FEISHU_API_BASE}/im/v1/messages?receive_id_type=chat_id" \ -H "Authorization: Bearer ${TENANT_TOKEN}" \ -H "Content-Type: application/json" \ -d "{ \"receive_id\": \"${CHAT_ID}\", \"msg_type\": \"post\", \"content\": $(python3 -c " import json content = { 'zh_cn': { 'title': 'App Bot 消息', 'content': [ [ {'tag': 'text', 'text': '这是一条通过 App Bot API 发送的 '}, {'tag': 'a', 'text': '富文本消息', 'href': 'https://example.com'}, {'tag': 'text', 'text': '。'} ] ] } } print(json.dumps(json.dumps(content))) ") }" ``` **Send an interactive card via the API:** ```bash curl -s -X POST "${FEISHU_API_BASE}/im/v1/messages?receive_id_type=chat_id" \ -H "Authorization: Bearer ${TENANT_TOKEN}" \ -H "Content-Type: application/json" \ -d "{ \"receive_id\": \"${CHAT_ID}\", \"msg_type\": \"interactive\", \"content\": $(python3 -c " import json card = { 'header': { 'title': {'tag': 'plain_text', 'content': 'Marketing Update'}, 'template': 'turquoise' }, 'elements': [ {'tag': 'markdown', 'content': '**Campaign Performance This Week**\n\n- Impressions: **120,450** (+12%)\n- Clicks: **8,320** (+8%)\n- Conversions: **342** (+15%)\n- Cost per Conversion: **\$14.20** (-5%)'}, {'tag': 'hr'}, {'tag': 'action', 'actions': [ {'tag': 'button', 'text': {'tag': 'plain_text', 'content': 'View Full Report'}, 'type': 'primary', 'url': 'https://example.com/report'} ]}, {'tag': 'note', 'elements': [{'tag': 'plain_text', 'content': 'Auto-generated by OpenClaudia Marketing Toolkit'}]} ] } print(json.dumps(json.dumps(card))) ") }" ``` ### 3.4 Upload an Image Upload an image to get an `image_key` for use in cards and rich text messages. ```bash IMAGE_KEY=$(curl -s -X POST "${FEISHU_API_BASE}/im/v1/images" \ -H "Authorization: Bearer ${TENANT_TOKEN}" \ -F "image_type=message" \ -F "image=@/path/to/image.png" | python3 -c "import json,sys; print(json.load(sys.stdin).get('data',{}).get('image_key',''))") echo "Image key: ${IMAGE_KEY}" ``` ### 3.5 Send to a Specific User (by email or user_id) ```bash # By email (receive_id_type=email) curl -s -X POST "${FEISHU_API_BASE}/im/v1/messages?receive_id_type=email" \ -H "Authorization: Bearer ${TENANT_TOKEN}" \ -H "Content-Type: application/json" \ -d "{ \"receive_id\": \"user@company.com\", \"msg_type\": \"text\", \"content\": \"{\\\"text\\\": \\\"Direct message from the marketing bot.\\\"}\" }" ``` --- ## 4. Message Templates ### 4.1 Product Announcement ```bash send_product_announcement() { local TITLE="$1" local VERSION="$2" local FEATURES="$3" local DOCS_URL="$4" local CTA_URL="$5" curl -s -X POST "${FEISHU_WEBHOOK_URL}" \ -H "Content-Type: application/json" \ -d "$(python3 -c " import json card = { 'msg_type': 'interactive', 'card': { 'header': { 'title': {'tag': 'plain_text', 'content': '${TITLE}'}, 'template': 'green' }, 'elements': [ {'tag': 'markdown', 'content': '**Version ${VERSION}** is now available!\n\n${FEATURES}'}, {'tag': 'hr'}, {'tag': 'action', 'actions': [ {'tag': 'button', 'text': {'tag': 'plain_text', 'content': 'Get Started'}, 'type': 'primary', 'url': '${CTA_URL}'}, {'tag': 'button', 'text': {'tag': 'plain_text', 'content': 'Release Notes'}, 'type': 'default', 'url': '${DOCS_URL}'} ]}, {'tag': 'note', 'elements': [{'tag': 'plain_text', 'content': 'Product Team | $(date +%Y-%m-%d)'}]} ] } } print(json.dumps(card)) ")" } ``` ### 4.2 Team Update / Weekly Report ```bash curl -s -X POST "${FEISHU_WEBHOOK_URL}" \ -H "Content-Type: application/json" \ -d '{ "msg_type": "interactive", "card": { "header": { "title": {"tag": "plain_text", "content": "Weekly Marketing Report - W03 2025"}, "template": "blue" }, "elements": [ { "tag": "column_set", "flex_mode": "bisect", "columns": [ { "tag": "column", "width": "weighted", "weight": 1, "elements": [ {"tag": "markdown", "content": "**Traffic**\n\nSessions: **45,230**\nUnique Visitors: **32,100**\nBounce Rate: **42%**"} ] }, { "tag": "column", "width": "weighted", "weight": 1, "elements": [ {"tag": "markdown", "content": "**Conversions**\n\nSignups: **580**\nTrials: **120**\nPaid: **34**"} ] } ] }, {"tag": "hr"}, { "tag": "markdown", "content": "**Top Performing Content:**\n1. \"10 Tips for Better SEO\" - 8,200 views\n2. \"Product Comparison Guide\" - 5,100 views\n3. \"Customer Success Story: Acme Corp\" - 3,800 views\n\n**Action Items:**\n- [ ] Publish Q1 campaign landing page\n- [ ] Review ad spend allocation\n- [ ] Schedule social media posts for next week" }, { "tag": "action", "actions": [ { "tag": "button", "text": {"tag": "plain_text", "content": "Full Dashboard"}, "type": "primary", "url": "https://example.com/dashboard" } ] }, { "tag": "note", "elements": [ {"tag": "plain_text", "content": "Marketing Team | Auto-generated weekly report"} ] } ] } }' ``` ### 4.3 Event Notification ```bash curl -s -X POST "${FEISHU_WEBHOOK_URL}" \ -H "Content-Type: application/json" \ -d '{ "msg_type": "interactive", "card": { "header": { "title": {"tag": "plain_text", "content": "Upcoming Webinar: AI in Marketing"}, "template": "purple" }, "elements": [ { "tag": "markdown", "content": "Join us for an exclusive webinar on leveraging AI for marketing success.\n\n**Date:** Thursday, January 30, 2025\n**Time:** 2:00 PM - 3:30 PM (PST)\n**Speaker:** Jane Smith, VP of Marketing\n**Format:** Live presentation + Q&A\n\n**What you will learn:**\n- How to use AI for content personalization\n- Automating campaign optimization\n- Measuring AI-driven marketing ROI" }, {"tag": "hr"}, { "tag": "action", "actions": [ { "tag": "button", "text": {"tag": "plain_text", "content": "Register Now"}, "type": "primary", "url": "https://example.com/webinar/register" }, { "tag": "button", "text": {"tag": "plain_text", "content": "Add to Calendar"}, "type": "default", "url": "https://example.com/webinar/calendar" } ] }, { "tag": "note", "elements": [ {"tag": "plain_text", "content": "Limited to 200 seats | Free for all team members"} ] } ] } }' ``` ### 4.4 Marketing Campaign Alert ```bash curl -s -X POST "${FEISHU_WEBHOOK_URL}" \ -H "Content-Type: application/json" \ -d '{ "msg_type": "interactive", "card": { "header": { "title": {"tag": "plain_text", "content": "Campaign Alert: Budget Threshold Reached"}, "template": "orange" }, "elements": [ { "tag": "markdown", "content": "**Google Ads - Q1 Brand Campaign** has reached **80%** of its monthly budget.\n\n| Metric | Value |\n|--------|-------|\n| Budget | $10,000 |\n| Spent | $8,042 |\n| Remaining | $1,958 |\n| Days Left | 8 |\n| Projected Overspend | $2,100 |\n\n**Recommendation:** Reduce daily bid cap by 15% or pause low-performing ad groups." }, { "tag": "action", "actions": [ { "tag": "button", "text": {"tag": "plain_text", "content": "Adjust Budget"}, "type": "danger", "url": "https://ads.google.com/campaigns" }, { "tag": "button", "text": {"tag": "plain_text", "content": "View Campaign"}, "type": "default", "url": "https://example.com/campaigns/q1-brand" } ] } ] } }' ``` --- ## 5. Helper: Build and Send Cards Programmatically For complex or dynamic cards, use Python to construct the JSON payload: ```bash python3 -c " import json, subprocess, os webhook_url = os.environ.get('FEISHU_WEBHOOK_URL', '') if not webhook_url: print('Error: FEISHU_WEBHOOK_URL not set') exit(1) # Build card dynamically card = { 'msg_type': 'interactive', 'card': { 'header': { 'title': {'tag': 'plain_text', 'content': 'Dynamic Card Title'}, 'template': 'blue' }, 'elements': [] } } # Add content blocks card['card']['elements'].append({ 'tag': 'markdown', 'content': 'This card was built programmatically.\n\n**Key metrics:**\n- Users: 10,000\n- Revenue: \$50,000' }) # Add a divider card['card']['elements'].append({'tag': 'hr'}) # Add buttons card['card']['elements'].append({ 'tag': 'action', 'actions': [ { 'tag': 'button', 'text': {'tag': 'plain_text', 'content': 'Learn More'}, 'type': 'primary', 'url': 'https://example.com' } ] }) # Add footer card['card']['elements'].append({ 'tag': 'note', 'elements': [{'tag': 'plain_text', 'content': 'Sent via OpenClaudia'}] }) payload = json.dumps(card) result = subprocess.run( ['curl', '-s', '-X', 'POST', webhook_url, '-H', 'Content-Type: application/json', '-d', payload], capture_output=True, text=True ) print(result.stdout) " ``` --- ## 6. Bilingual Support (Chinese + English) When sending messages that need both Chinese and English content, use the rich text `post` format which supports multiple locales. Feishu will display the locale matching the user's language setting. ```bash curl -s -X POST "${FEISHU_WEBHOOK_URL}" \ -H "Content-Type: application/json" \ -d '{ "msg_type": "post", "content": { "post": { "zh_cn": { "title": "重要通知:系统维护", "content": [ [ {"tag": "text", "text": "我们将于 "}, {"tag": "text", "text": "1月25日 22:00-02:00 (北京时间)", "un_escape": true}, {"tag": "text", "text": " 进行系统维护。"} ], [ {"tag": "text", "text": "维护期间服务将暂时不可用。如有问题请联系 "}, {"tag": "a", "text": "技术支持", "href": "https://example.com/support"}, {"tag": "text", "text": "。"} ] ] }, "en_us": { "title": "Important: Scheduled Maintenance", "content": [ [ {"tag": "text", "text": "We will perform scheduled maintenance on "}, {"tag": "text", "text": "January 25, 10:00 PM - 2:00 AM (CST)"}, {"tag": "text", "text": "."} ], [ {"tag": "text", "text": "Services will be temporarily unavailable. For questions, contact "}, {"tag": "a", "text": "Support", "href": "https://example.com/support"}, {"tag": "text", "text": "."} ] ] } } } }' ``` --- ## 7. Error Handling ### Webhook Response Codes | Code | StatusMessage | Meaning | |------|---------------|---------| | 0 | `"success"` | Message sent successfully | | 9499 | `"Bad Request"` | Malformed JSON or missing required fields | | 19001 | `"param invalid"` | Invalid msg_type or content format | | 19002 | `"sign match fail"` | Signature verification failed (check timestamp and secret) | | 19021 | `"request too fast"` | Rate limit: max 100 messages per minute per webhook | | 19024 | `"bot not in chat"` | Bot has been removed from the group | ### Common Troubleshooting **Message not delivered:** - Verify the webhook URL is correct and the bot is still in the group - Check that `msg_type` matches the content structure - For signed webhooks, ensure the timestamp is within 1 hour of current time **Card not rendering:** - Validate JSON structure: header and elements are both required - Button URLs must start with `http://` or `https://` - Markdown in cards supports a limited subset: bold, italic, links, lists, tables **API token errors:** - Tenant access tokens expire after 2 hours; re-fetch before sending - Ensure the app has been published and approved in the developer console - Verify `im:message:send_as_bot` permission is granted ### Rate Limits | Integration | Limit | |-------------|-------| | Custom Bot Webhook | 100 messages/minute per webhook | | App Bot API (messages) | 50 messages/second per app | | App Bot API (token refresh) | 500 requests/hour | --- ## 8. Workflow: Post Marketing Content to Feishu/Lark When the user asks to send marketing content to Feishu or Lark, follow this workflow: ### Step 1: Check Credentials Verify that `FEISHU_WEBHOOK_URL` or `FEISHU_APP_ID` + `FEISHU_APP_SECRET` are set. If not, guide the user through setup. ### Step 2: Determine Message Type | User Intent | Recommended Format | |-------------|-------------------| | Quick text update | Plain text (`msg_type: text`) | | Formatted announcement | Rich text (`msg_type: post`) | | Marketing report with metrics | Interactive card with columns | | Product launch | Interactive card with buttons | | Event notification | Interactive card with CTA buttons | | Alert or warning | Interactive card with `red`/`orange` header | ### Step 3: Compose the Message - Use the appropriate template from section 4 - Adapt content to the user's requirements - For bilingual groups, provide both `zh_cn` and `en_us` content ### Step 4: Preview and Confirm Show the user the full JSON payload before sending. Explain what the message will look like. **Never auto-send without explicit user confirmation.** ### Step 5: Send Execute the curl command and report the response. ### Step 6: Verify Check the response code. If `code: 0`, the message was delivered. If there is an error, troubleshoot using the error table above. --- ## 9. Advanced: Message Card JSON Schema Quick Reference ``` { "msg_type": "interactive", "card": { "header": { // Required "title": { "tag": "plain_text", "content": "string" }, "template": "blue|green|red|..." // Header color }, "elements": [ // Required, array of blocks {"tag": "markdown", "content": "..."}, // Rich content {"tag": "hr"}, // Divider line {"tag": "img", "img_key": "...", "alt": {...}}, // Image { // Multi-column layout "tag": "column_set", "flex_mode": "bisect|trisect|...", "columns": [ {"tag": "column", "width": "weighted", "weight": 1, "elements": [...]} ] }, { // Action buttons "tag": "action", "actions": [ {"tag": "button", "text": {...}, "type": "primary|danger|default", "url": "..."} ] }, { // Footer note "tag": "note", "elements": [{"tag": "plain_text", "content": "..."}] } ] } } ``` --- ## Tips - **Start with webhooks.** Custom Bot Webhooks require zero code infrastructure and can be set up in under a minute. - **Use interactive cards** for anything beyond simple text. They are more readable and actionable. - **Include action buttons** in every marketing card. Drive recipients to a landing page, dashboard, or sign-up form. - **Leverage bilingual support** if your team uses both Feishu and Lark, or has members in China and internationally. - **Respect rate limits.** For bulk messaging (e.g., sending to multiple groups), add a 1-second delay between requests. - **Test in a private group first** before sending to large team channels. - **Keep card content concise.** Cards have a maximum content size of approximately 30KB. For very long reports, link to an external page. - **Use the Feishu Message Card Builder** for visual card design: [https://open.feishu.cn/tool/cardbuilder](https://open.feishu.cn/tool/cardbuilder) (Feishu) or [https://open.larksuite.com/tool/cardbuilder](https://open.larksuite.com/tool/cardbuilder) (Lark).