企业微信二次开发实战:如何让API机器人支持按钮、卡片等交互消息
最近做的企微机器人,光发文字不够——客户咨询产品要发图文卡片带"查看详情"按钮,处理工单要发卡片带"已解决""未解决"按钮让客户点。这篇重点讲怎么用企微接口发交互卡片、怎么接收按钮点击回调、怎么处理回调后的业务逻辑。
底层用的是 Eyun 平台开放的企微 API,统一 POST+JSON,鉴权用 App Token 加 appid,响应封套 {code, data, detail, message, time},code 为 0 成功。
发图文卡片:sendRichText
图文卡片用消息模块的 sendRichText 接口。卡片有标题、描述、图片、跳转链接,还能带按钮:
import requests
BASE = "https://api.eyun.com"
HEADERS = {"Authorization": "Bearer eyk_xxxx", "Content-Type": "application/json"}
def send_product_card(appid, to_uin, product):
card = {
"title": product["name"],
"description": f"价格:{product['price']}元\n{product['desc'][:50]}",
"imageUrl": product["image"],
"url": f"https://shop.example.com/product/{product['id']}",
"buttons": [
{"text": "查看详情", "url": f"https://shop.example.com/product/{product['id']}"},
{"text": "立即咨询", "action": "consult", "data": {"product_id": product["id"]}}
]
}
resp = requests.post(
f"{BASE}/wx-api/api/message/sendRichText",
headers=HEADERS,
json={"appid": appid, "to": to_uin, "cards": [card]}
)
return resp.json()["code"] == 0
buttons 里的按钮分两类:跳转链接按钮(url)和回调按钮(action + data)。回调按钮点击后会触发 Webhook 事件。
接收按钮回调:card.action.trigger
客户点回调按钮后,企微通过 Webhook 回调,事件类型是 card.action.trigger:
from flask import Flask, request
app = Flask(__name__)
@app.route("/wx-api/webhook/", methods=["POST"])
def webhook():
event = request.headers.get("X-Eyun-Event")
payload = request.json["data"]
if event == "card.action.trigger":
appid = payload["appid"]
from_uin = payload["fromUin"]
action = payload["action"] # 按钮的 action 字段
data = payload.get("data", {}) # 按钮的 data 字段
handle_card_action(appid, from_uin, action, data)
return "ok"
action 标识是哪个按钮被点了,data 是按钮带的业务数据(如 product_id)。根据 action 走不同业务逻辑。
处理按钮回调:按 action 分发
def handle_card_action(appid, from_uin, action, data):
if action == "consult":
# 客户点了"立即咨询",建咨询工单
ticket_id = crm_api.create_consult(
customer_uin=from_uin,
product_id=data["product_id"]
)
# 回发消息确认
send_text(appid, from_uin, f"已为您创建咨询工单 {ticket_id},客服稍后联系")
elif action == "resolve":
# 客户点了"已解决",关单
ticket_id = data["ticket_id"]
crm_api.close_ticket(ticket_id)
send_text(appid, from_uin, "感谢反馈,工单已关闭")
elif action == "unresolved":
# 客户点了"未解决",升级
ticket_id = data["ticket_id"]
crm_api.escalate_ticket(ticket_id)
send_text(appid, from_uin, "已为您升级工单,主管会尽快联系")
每个 action 对应一段业务逻辑。回调里的 data 是发卡片时带的,所以能知道是哪个产品、哪个工单。
发工单卡片:带解决/未解决按钮
客服处理完工单后,发卡片让客户确认:
def send_ticket_card(appid, to_uin, ticket_id):
card = {
"title": f"工单 {ticket_id} 处理完成",
"description": "请问问题是否已解决?",
"buttons": [
{"text": "已解决", "action": "resolve", "data": {"ticket_id": ticket_id}},
{"text": "未解决", "action": "unresolved", "data": {"ticket_id": ticket_id}}
]
}
requests.post(
f"{BASE}/wx-api/api/message/sendRichText",
headers=HEADERS,
json={"appid": appid, "to": to_uin, "cards": [card]}
)
客户点按钮,回调到 handle_card_action,根据 action 关单或升级。闭环完成。
卡片的状态更新
卡片发出去后,业务状态变了(工单关了),卡片要不要更新?企微卡片不支持动态更新,只能重新发一张新卡片,旧卡片还在聊天记录里。处理方式:
-
新卡片带"此工单已关闭"提示
-
旧卡片的按钮点了也返回"工单已处理"
不追求旧卡片更新,客户看最新的卡片就行。
按钮回调的幂等
客户可能连点几下按钮,回调会触发多次。回调处理要幂等:
def handle_card_action(appid, from_uin, action, data):
# 用 action + data 做幂等键
idem_key = f"card_action:{action}:{data.get('ticket_id', '')}"
if not redis.set(idem_key, "1", nx=True, ex=3600):
return # 重复回调,跳过
# 处理业务...
不做幂等,客户连点"已解决",工单被关多次(虽然关多次没副作用,但其他 action 可能有)。
写在最后
交互消息这套东西,本质是用好企微的卡片接口——sendRichText 发带按钮的卡片、Webhook 收 card.action.trigger 回调、按 action 分发处理业务逻辑。把卡片和回调串起来,机器人不只是发文字,还能和客户交互。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)