← Home Blog 中文版

Feishu bot + self-hosted AI service in 30 minutes

From creating an enterprise app to receiving the first AI reply (with four fix-or-it-fails moments)

2026-07-14 · Leo · 15 min read
TL;DR — Open Feishu Open Platform → create a corporate self-built app → wire up the webhook → plug in your AI service → receive your first reply in IM. The last section lists four errors I hit on every first deploy, with the fix each time.

Step 1: create the Feishu app

📌 Corporate self-built app 5 min
  1. Go to open.feishu.cn and sign in as your corporate admin
  2. Developer console → Create "corporate self-built app" → fill in name / icon / intro
  3. Copy the App ID and App Secret (you won't see the secret again)
  4. Permissions → enable: im:message, im:message.group_at_msg, im:message.p2p_msg
  5. Event subscriptions → add event im.message.receive_v1

Step 2: minimum echo webhook

🐍 Python Flask 30-line echo 5 min

Get connectivity working before you add AI:

from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route("/webhook", methods=["POST"])
def webhook():
    data = request.json
    if data.get("type") == "url_verification":
        return jsonify({"challenge": data["challenge"]})

    event = data.get("header", {}).get("event_type")
    if event == "im.message.receive_v1":
        msg = data["event"]["message"]
        sender = msg["sender"]["sender_id"]["open_id"]
        text = msg["content"]["text"]
        reply_text = f"You said: {text}"
        send_message(sender, reply_text)

    return jsonify({"code": 0})

def send_message(receive_id, text):
    pass  # your existing send impl

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8080)

Step 3: expose it via ngrok

🌐 Public callback URL 2 min
  1. Install ngrok (or bore / cloudflared)
  2. ngrok http 8080
  3. Paste the https://xxx.ngrok.io URL into Feishu Event Subscription → Request URL
  4. Hit "Test connection" — you should see {"code": 0}

Step 4: replace echo with AI

🤖 Plug in your AI service 10 min
import requests

def ask_ai(prompt):
    resp = requests.post(
        "https://your-ai-service/api/chat",
        json={"message": prompt, "max_tokens": 1000},
        timeout=30
    )
    return resp.json()["reply"]

# Inside webhook():
reply_text = ask_ai(text)

Once stable, layer on:

Step 5: ship a version

🚀 Publish 5 min
  1. Feishu console → Version management → create v1.0.0
  2. Release notes: "AI assistant internal beta, scope limited to specific users"
  3. Submit for review → corporate admin approves
  4. After approval: @ the bot in DM or group chat — first message lands

Four errors you will hit on the first run

Error 1: Feishu "Test connection" silently fails

URL verification sends {type: "url_verification", challenge: "..."} and expects the response to include challenge verbatim. Forget this branch and you get a generic failure with no clue.

✅ Always handle type == "url_verification" before business logic.
Error 2: 230001 (App Secret mismatch)

tenant_access_token needs App ID + App Secret. Typo in either and you see a generic "call failed" — no hint where.

✅ Store the secret in an environment variable, not in code. When you rotate, update code and config together.
Error 3: "Send succeeded" but no message in IM

Feishu distinguishes open_id, user_id, email, and chat_id. Mix them up and Feishu returns 200 with nothing delivered.

✅ For DMs use open_id, for groups use chat_id. Pick based on the inbound sender_id fields.
Error 4: rate limit 230020

Feishu's 100 QPS limit is per tenant. A 20-person group @-ing the bot simultaneously brushes past it.

✅ Add a token bucket (per tenant or per bot) in front of your AI service, cap around 80 QPS, return "let me check" when over budget rather than dropping silently.

What you have after 30 minutes

Recommended next steps in order:

  1. Add a knowledge base (solves ~80% of business questions)
  2. Add memory (recalls prior chats per user)
  3. Hook up additional IMs (WeCom / DingTalk)
🤝 Tried it and hit a wall you can't crack?
📧 ricky_so@126.com — replies usually within 24 hours.