版本 v1 · 适用于企业系统(CRM / 数据平台 / 内部 IM)与 TelegramBotHub 的双向打通:出方向通过事件订阅(Webhook)实时接收群事件,入方向通过 REST API 管理规则、发送消息。
在控制台 设置 → API 密钥 中创建 Key(格式 tbh_sk_<64位hex>)。完整 Key 仅在创建时展示一次,平台只保存哈希,请妥善保管。
每次请求通过以下任一方式携带:
# 方式一:X-API-Key 头(推荐)
curl -H "X-API-Key: tbh_sk_xxxx" https://<your-host>/api/public/bots
# 方式二:Bearer Token
curl -H "Authorization: Bearer tbh_sk_xxxx" https://<your-host>/api/public/bots
创建 Key 时勾选所需权限,最小授权原则。未勾选默认仅 read:bots + read:skills。
| Scope | 说明 |
|---|---|
read:bots | 读取机器人列表及其群/会话列表 |
read:groups | 读取名下所有群组(跨机器人) |
read:skills | 读取可用技能清单 |
read:rules | 读取自动化规则 |
write:rules | 创建 / 启停 / 删除自动化规则 |
write:messages | 通过机器人向群组发送消息 |
read:subscriptions | 读取事件订阅配置 |
write:subscriptions | 创建 / 修改 / 删除事件订阅 |
Base URL:https://<your-host>/api/public,所有请求与响应均为 JSON(UTF-8)。
列出当前租户的机器人。返回 id / username / name / status / created_at。
列出指定机器人加入的群/会话。返回 id(Telegram chat id)/ title / type / member_count。
跨机器人列出名下全部群组(含所属 bot 信息)。
列出平台技能清单(id / 名称 / 描述 / 等级)。
查询规则列表,支持 ?bot_id= / ?chat_id= 过滤。
创建规则。Body 与控制台一致:
{
"bot_id": "<uuid>",
"chat_id": -100123456789,
"name": "关键词自动回复",
"trigger": { "type": "message", "config": { "keywords": ["价格"] } },
"conditions": [],
"actions": [ { "type": "reply", "config": { "text": "请查看置顶报价单" } } ],
"enabled": true
}
触发器:message / member_join / member_leave / scheduled(interval 或 daily)。动作:reply / delete_message / send_to_chat / mute / warn / kick / ban / forward / webhook。
启停规则。Body:{"enabled": true}
删除规则。
{
"bot_id": "<uuid>", // 必填,须为本租户机器人
"chat_id": -100123456789, // 必填,须为该机器人已加入的群
"text": "Hello from ERP", // 必填,≤ 4000 字符
"parse_mode": "HTML" // 可选:HTML / MarkdownV2
}
成功返回 {"ok": true, "message_id": 123}。
列出订阅(secret 不回显,返回 has_secret)。
{
"name": "同步到 CRM",
"url": "https://erp.example.com/tbh/webhook",
"secret": "your-shared-secret", // 可选,用于 HMAC 签名
"bot_id": "<uuid>", // 可选,不填 = 全部机器人
"events": ["member_join", "member_leave", "rule_matched", "message"]
}
每租户最多 10 条订阅。URL 须为公网 http(s) 地址(禁止内网/环回地址)。
局部更新(name/url/secret/events/enabled 任意字段)。
删除订阅。
订阅生效后,平台将事件以 POST application/json 异步推送到你的 URL(5 秒超时)。连续失败 20 次订阅将自动停用,修复后可在控制台或 API 重新启用。
| 事件 | 触发时机 | 主要字段 |
|---|---|---|
member_join | 成员加入群组 | chat_id, user{id,username,first_name,last_name} |
member_leave | 成员离开群组 | chat_id, user{...} |
rule_matched | 自动化规则命中 | chat_id, rule_id, rule_name, action_taken, user, text |
message | 群消息(量大,慎订阅) | chat_id, message_id, text, user |
公共字段:每个推送体都含 event(事件类型)、bot_id、timestamp(Unix 秒)。示例:
{
"event": "member_join",
"bot_id": "8b2f...c1",
"timestamp": 1753872000,
"chat_id": -100123456789,
"user": { "id": 123456, "username": "alice", "first_name": "Alice", "last_name": "" }
}
若订阅配置了 secret,每个推送带请求头:
X-Signature: sha256=<hex(HMAC-SHA256(secret, rawBody))>
User-Agent: TelegramBotHub-Events/1.0
接收端必须用原始请求体字节(勿先 JSON 解析再序列化)计算 HMAC 并常量时间比较。规则引擎的 webhook 动作使用相同的签名方式。
const express = require("express");
const crypto = require("crypto");
const SECRET = process.env.TBH_SECRET || "your-shared-secret";
const app = express();
// 关键:保留原始 body 用于验签
app.use(express.json({ verify: (req, _res, buf) => { req.rawBody = buf; } }));
app.post("/tbh/webhook", (req, res) => {
const sig = req.get("X-Signature") || "";
const expect = "sha256=" +
crypto.createHmac("sha256", SECRET).update(req.rawBody).digest("hex");
if (!sig || !crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expect))) {
return res.status(401).json({ error: "bad signature" });
}
const ev = req.body;
switch (ev.event) {
case "member_join":
console.log(`[入群] chat=${ev.chat_id} user=@${ev.user?.username}`);
// TODO: 写入 CRM / 发欢迎工单
break;
case "rule_matched":
console.log(`[规则命中] ${ev.rule_name} -> ${ev.action_taken}`);
break;
default:
console.log("[事件]", ev.event, ev);
}
res.json({ ok: true }); // 2xx 即视为投递成功
});
app.listen(9000, () => console.log("TBH webhook receiver on :9000"));
import hmac, hashlib, os
from flask import Flask, request, jsonify
SECRET = os.environ.get("TBH_SECRET", "your-shared-secret").encode()
app = Flask(__name__)
@app.post("/tbh/webhook")
def tbh_webhook():
raw = request.get_data() # 原始字节
expect = "sha256=" + hmac.new(SECRET, raw, hashlib.sha256).hexdigest()
if not hmac.compare_digest(request.headers.get("X-Signature", ""), expect):
return jsonify(error="bad signature"), 401
ev = request.get_json()
print("event:", ev.get("event"), ev)
return jsonify(ok=True)
app.run(port=9000)
curl -X POST https://<your-host>/api/public/messages \
-H "X-API-Key: tbh_sk_xxxx" -H "Content-Type: application/json" \
-d '{"bot_id":"<uuid>","chat_id":-100123456789,"text":"<b>工单 #1024 已处理</b>","parse_mode":"HTML"}'
POST /subscriptions。event: test 且验签通过。message 事件做好吞吐评估。| HTTP | 含义 | 处理建议 |
|---|---|---|
| 401 | Key 缺失 / 无效 / 已过期 / 已停用 | 检查 Key 与有效期 |
| 403 | 缺少所需 scope | 重建 Key 并勾选对应权限 |
| 404 | 资源不存在或不属于当前租户 | 核对 id 归属 |
| 429 | 超出每分钟限流 | 按 Key 的 rate_limit 退避重试 |
| 400 | 参数错误(如 text 超长、URL 非法) | 参照响应 error 字段修正 |
错误响应统一为 {"error": "描述"}。
TelegramBotHub Open API v1 · 如有疑问请联系平台管理员