老铁们,搞企业微信开发,跟咱们在市场里炒期货一样,得抓住核心,把常用的“招数”练熟了,才能在实战中游刃有余。
企业微信(WeCom)的接口那叫一个海量,但平时咱们用得多的,也就是那么一些关键的。今天,我就以一个过来人的身份,把企业微信开发里那些最常用、最核心的接口给你们扒拉出来,详细讲解它们的功能、用法、数据结构,再给你们上几个“实战案例”,让你们看得明明白白,拿来就能用!
记住,这是“常用接口”,不是全部,但掌握了这些,你就能搭起一个像模像样、解决实际问题的企业微信应用了!
企业微信开发:常用接口实战手册
概述:企业微信开发的核心逻辑
企业微信应用开发,说白了就是你的服务器(或你的应用)和企业微信服务器之间的数据交换。它主要围绕以下几个核心任务展开:
-
身份认证:让你的应用能“合法”地访问企业微信的数据。
-
获取信息:从企业微信获取企业成员、部门、外部联系人等数据。
-
消息互动:你的应用给成员发消息,成员给你的应用发消息。
-
网页能力:在企业微信内部打开网页,调用手机硬件能力(如扫码、拍照)。
-
文件管理:上传下载媒体文件。
所有的接口调用,几乎都离不开一个东西——access_token。它是你应用和企业微信服务器之间的“通行证”,所以,咱们就从它开始。
一、核心基础接口
1. 获取 access_token (通行证)
-
功能:这是企业微信API调用的最基础,也是最核心的一步。所有其他需要认证的接口,都需要携带这个
access_token。 -
接口:
GET https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=ID&corpsecret=SECRET -
调用频率限制:每个应用每2小时只能获取一次
access_token。强烈建议缓存! -
请求参数:
-
corpid:企业ID(在企业微信管理后台“我的企业”页面可查看)。 -
corpsecret:应用的Secret(在企业微信管理后台“应用管理”页面,选择你的应用,即可看到其Secret)。
-
-
返回数据结构 (JSON):
{ "errcode": 0, "errmsg": "ok", "access_token": "ACCESS_TOKEN", // 获取到的access_token "expires_in": 7200 // access_token的有效期,单位秒。目前是7200秒(2小时) } -
示例 (Python):
import requests corpid = "YOUR_CORP_ID" corpsecret = "YOUR_APP_SECRET" # 对应具体应用的Secret url = f"https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={corpid}&corpsecret={corpsecret}" response = requests.get(url).json() if response.get("errcode") == 0: access_token = response["access_token"] expires_in = response["expires_in"] print(f"成功获取access_token: {access_token}, 有效期: {expires_in}秒") # 实际项目中应缓存此token,并在过期前刷新 else: print(f"获取access_token失败: {response.get('errmsg')}") -
注意事项:
access_token有效期2小时,但建议在获取时立即使用并缓存,并在每次调用接口时检查其是否临近过期(比如剩余10分钟就刷新),避免频繁获取和过期失效。
二、用户与组织架构管理
1. 获取部门列表
-
功能:获取企业微信组织架构中的部门信息。
-
接口:
GET https://qyapi.weixin.qq.com/cgi-bin/department/list?access_token=ACCESS_TOKEN&id=ID -
调用频率限制:无。
-
请求参数:
-
access_token:通过gettoken获取的access_token。 -
id(可选):部门ID。如果指定,则获取该部门及其子部门,不指定则获取全量部门列表。
-
-
返回数据结构 (JSON):
{ "errcode": 0, "errmsg": "ok", "department": [ { "id": 2, // 部门ID "name": "广州研发中心", // 部门名称 "parentid": 1, // 父部门ID "order": 10 // 在父部门中的排序 }, { "id": 3, "name": "产品部", "parentid": 2, "order": 20 } ] } -
示例:获取所有部门列表。
# 假设 access_token 已获取 url = f"https://qyapi.weixin.qq.com/cgi-bin/department/list?access_token={access_token}" response = requests.get(url).json() if response.get("errcode") == 0: departments = response["department"] print("所有部门列表:") for dept in departments: print(f"- ID: {dept['id']}, 名称: {dept['name']}, 父部门: {dept['parentid']}")
2. 获取部门成员详情
-
功能:获取指定部门的成员详细信息,包括姓名、手机号、职位等。
-
接口:
GET https://qyapi.weixin.qq.com/cgi-bin/user/list?access_token=ACCESS_TOKEN&department_id=ID&fetch_child=FETCH_CHILD -
调用频率限制:无。
-
请求参数:
-
access_token:通过gettoken获取的access_token。 -
department_id:部门ID。 -
fetch_child(可选,默认0):是否递归获取子部门下的成员。0表示不递归,1表示递归。
-
-
返回数据结构 (JSON):
{ "errcode": 0, "errmsg": "ok", "userlist": [ { "userid": "zhangsan", // 成员UserID "name": "张三", // 成员名称 "department": [1, 2], // 成员所属部门ID列表 "position": "产品经理", // 职位 "mobile": "13800000000", // 手机号 "gender": "1", // 性别,1男2女 "email": "zhangsan@example.com", // 邮箱 "avatar": "http://......", // 头像url "status": 1, // 状态,1=已激活,2=已禁用,4=未激活 "is_leader_in_dept": [0, 1], // 表示在所在部门内是否是领导,0否1是 // ... 更多字段 ... } ] } -
示例:获取部门ID为2的所有成员(不递归)。
# 假设 access_token 已获取 dept_id = 2 url = f"https://qyapi.weixin.qq.com/cgi-bin/user/list?access_token={access_token}&department_id={dept_id}&fetch_child=0" response = requests.get(url).json() if response.get("errcode") == 0: userlist = response["userlist"] print(f"部门ID {dept_id} 的成员列表:") for user in userlist: print(f"- UserID: {user['userid']}, 姓名: {user['name']}, 手机: {user.get('mobile', '无')}") -
用途:管理企业通讯录、同步员工信息到你的应用数据库、构建基于组织架构的审批流或通知系统。
三、消息发送
1. 发送应用消息
-
功能:你的应用主动向企业成员、部门或标签发送各类消息(文本、图片、文件、图文等)。
-
接口:
POST https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=ACCESS_TOKEN -
调用频率限制:每个应用对同一个成员或群发消息有次数限制,具体以官方文档为准。
-
请求参数 (JSON Body):
{ "touser" : "UserID1|UserID2|UserID3", // 成员ID列表,用|分隔,为空则默认为全体成员,不能与toparty同时为空 "toparty" : "PartyID1|PartyID2", // 部门ID列表,用|分隔 "totag" : "TagID1|TagID2", // 标签ID列表,用|分隔 "msgtype" : "text", // 消息类型,如 text, image, file, textcard, news, markdown等 "agentid" : 1000001, // 应用ID " "text" : { // 根据msgtype不同,对应不同的消息体 "content" : "你的会议室预定成功,时间:2024年8月15日 10:00,地点:公司大会议室。" }, "safe": 0, // 表示是否是保密消息,0表示否,1表示是,保密消息无需保存在微信服务器,不能在手机端进行二次分享 "enable_id_trans": 0, // 表示是否开启id转译,0表示否,1表示是 "enable_duplicate_check": 0, // 表示是否开启重复消息检查,0表示否,1表示是 "duplicate_check_interval": 180 // 表示重复消息检查的时间间隔,单位秒 }-
不同
msgtype对应的消息体示例:-
text:{"content": "文本消息内容"} -
image:{"media_id": "MEDIA_ID"}(MEDIA_ID需先通过媒体文件上传接口获取) -
file:{"media_id": "MEDIA_ID"} -
textcard: 用于发送卡片消息,标题、描述、URL等字段。"textcard": { "title": "会议通知", "description": "<div class=\"gray\">2024年8月15日</div> <div class=\"normal\">你收到了一份会议通知,请准时参加</div><div class=\"highlight\">点击查看详情</div>", "url": "URL_TO_YOUR_PAGE", "btntxt": "详情" } -
markdown: 支持Markdown语法。"markdown": { "content": "### 会议纪要\n* **主题**:产品季度复盘\n* **时间**:<font color=\"info\">2024年8月15日 14:00</font>\n* **地点**:<font color=\"comment\">远程会议</font>\n>请提前准备汇报材料" }
-
-
-
返回数据结构 (JSON):
{ "errcode": 0, "errmsg": "ok", "invaliduser": "UserID1|UserID2", // 无效的成员列表 "invalidparty": "PartyID1|PartyID2", // 无效的部门列表 "invalidtag": "TagID1|TagID2" // 无效的标签列表 } -
示例:向指定成员发送文本卡片消息。
# 假设 access_token 已获取 target_user = "USERID_OF_RECIPIENT" # 替换为实际的企业微信成员ID agent_id = YOUR_APP_AGENTID # 替换为你的应用ID message_data = { "touser": target_user, "msgtype": "textcard", "agentid": agent_id, "textcard": { "title": "系统通知", "description": "<div class=\"gray\">2024年8月15日</div> <div class=\"normal\">你的报销单已审批通过,请前往财务部领取。</div><div class=\"highlight\">点击查看详情</div>", "url": "https://your.domain.com/reimbursement/detail/123", "btntxt": "查看详情" }, "safe": 0 } url = f"https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={access_token}" response = requests.post(url, json=message_data).json() if response.get("errcode") == 0: print(f"消息发送成功,无效用户: {response.get('invaliduser', '无')}") else: print(f"消息发送失败: {response.get('errmsg')}") -
用途:实现工作通知、审批提醒、系统告警、日报周报推送、智能客服等一切需要应用主动向成员发送信息的场景。
四、消息接收 (回调模式)
-
功能:当企业微信用户向你的应用发送消息,或触发某些事件时(如关注/取消关注、点击菜单等),企业微信服务器会主动将这些消息或事件推送到你预设的URL(即回调URL)。
-
实现方式:需要你在企业微信管理后台设置回调URL和Token/EncodingAESKey。你的服务器需要实现一套消息验证和加解密机制来接收和处理这些POST请求。
-
调用频率限制:无上限(取决于用户互动量)。
-
请求参数 (HTTP GET for URL验证 / HTTP POST for message push):
-
URL验证阶段 (GET):
msg_signature(签名),timestamp(时间戳),nonce(随机数),echostr(随机字符串)。你需要根据规则计算签名,验证通过后原样返回echostr。 -
消息推送阶段 (POST):HTTP Body中包含XML格式的加密消息内容。
-
-
返回数据结构 (XML):企业微信推送过来的消息是加密的XML格式。解密后通常包含:
<!-- 文本消息示例 --> <xml> <ToUserName><![CDATA[wx2488d5e87a2a7a40]]></ToUserName> <!-- 企业微信CorpID --> <FromUserName><![CDATA[zhangsan]]></FromUserName> <!-- 发送消息的成员UserID --> <CreateTime>1400000000</CreateTime> <!-- 消息创建时间 --> <MsgType><![CDATA[text]]></MsgType> <!-- 消息类型 --> <Content><![CDATA[你好]]></Content> <!-- 文本消息内容 --> <MsgId>1234567890123456</MsgId> <!-- 消息ID --> <AgentID>1000001</AgentID> <!-- 应用ID --> </xml> <!-- 事件推送示例 (关注事件) --> <xml> <ToUserName><![CDATA[wx2488d5e87a2a7a40]]></ToUserName> <FromUserName><![CDATA[zhangsan]]></FromUserName> <CreateTime>1400000000</CreateTime> <MsgType><![CDATA[event]]></MsgType> <AgentID>1000001</AgentID> <Event><![CDATA[subscribe]]></Event> <!-- 事件类型 --> <EventKey><![CDATA[qrscene_123]]></EventKey> <!-- 事件Key值,如扫码场景值 --> </xml> -
示例 (Python Flask 伪代码):
from flask import Flask, request, make_response from wecom_sdk.crypto import WeChatCrypto # 假设你用了官方或第三方SDK app = Flask(__name__) # 从企业微信管理后台获取 TOKEN = "YOUR_TOKEN" ENCODING_AES_KEY = "YOUR_ENCODING_AES_KEY" CORP_ID = "YOUR_CORP_ID" crypto = WeChatCrypto(TOKEN, ENCODING_AES_KEY, CORP_ID) @app.route('/wecom/callback', methods=['GET', 'POST']) def wecom_callback(): if request.method == 'GET': # URL 验证 msg_signature = request.args.get('msg_signature') timestamp = request.args.get('timestamp') nonce = request.args.get('nonce') echostr = request.args.get('echostr') try: # 验证签名并解密echostr echo_str = crypto.check_signature(msg_signature, timestamp, nonce, echostr) return echo_str except Exception as e: print(f"URL验证失败: {e}") return "非法请求", 403 else: # 消息和事件推送 msg_signature = request.args.get('msg_signature') timestamp = request.args.get('timestamp') nonce = request.args.get('nonce') # 获取加密的XML内容 encrypted_xml = request.data try: # 解密消息 decrypted_msg = crypto.decrypt_message(encrypted_xml, msg_signature, timestamp, nonce) # decrypted_msg 是一个字典,包含ToUserName, FromUserName, MsgType, Content等 # 假设是文本消息,进行简单回复 if decrypted_msg.get('MsgType') == 'text': user_id = decrypted_msg['FromUserName'] agent_id = decrypted_msg['AgentID'] content = decrypted_msg['Content'] reply_content = f"你对我说: {content}" # 构造回复消息XML(这里为了简化,直接构造,实际应用中建议用SDK或模板) # 注意:回复消息也需要加密并带上时间戳和随机数 # 这里直接返回明文XML,实际应加密返回 reply_xml = f""" <xml> <ToUserName><![CDATA[{user_id}]]></ToUserName> <FromUserName><![CDATA[{CORP_ID}]]></FromUserName> <CreateTime>{int(timestamp)}</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><![CDATA[{reply_content}]]></Content> <AgentID>{agent_id}</AgentID> </xml> """ # 需要通过 crypto.encrypt_message() 进行加密处理 encrypted_reply_xml = crypto.encrypt_message(reply_xml, nonce, timestamp) return encrypted_reply_xml return "" # 其他类型消息或事件可以不回复 except Exception as e: print(f"消息解密或处理失败: {e}") return "", 200 # 即使失败也要返回200,避免企业微信重试 -
用途:实现智能问答机器人、自动化业务流程触发、用户行为分析、菜单点击事件响应等。这是构建真正“智能”和“互动”应用的关键。
五、网页应用接口 (JS-SDK)
-
功能:在企业微信内部打开的网页,可以调用手机的各种原生能力,如扫码、拍照、获取地理位置等。
-
使用流程:
-
你的后端服务器获取
access_token。 -
根据
access_token获取jsapi_ticket。 -
前端网页通过
jsapi_ticket、noncestr(随机字符串)、timestamp(时间戳)和当前页面的url进行签名计算,并通过wx.config配置JS-SDK。 -
配置成功后,即可在前端调用
wx.ready回调中的JS-SDK接口。
-
1. 获取 jsapi_ticket
-
功能:用于前端JS-SDK签名。
-
接口:
GET https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token=ACCESS_TOKEN -
调用频率限制:与
access_token类似,建议缓存。 -
返回数据结构 (JSON):
{ "errcode": 0, "errmsg": "ok", "ticket": "JSAPI_TICKET", // 获取到的jsapi_ticket "expires_in": 7200 // jsapi_ticket的有效期,单位秒 }
2. 前端JS-SDK配置和常用接口
-
JS-SDK配置 (前端):
// 在后端获取到 jsapi_ticket, nonceStr, timestamp, signature 后传给前端 wx.config({ beta: true, // 开启测试模式,可以调试某些新功能 debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印 appId: 'YOUR_CORP_ID', // 企业微信的CorpID timestamp: '<?php echo $timestamp;?>', // 必填,生成签名的时间戳 nonceStr: '<?php echo $nonceStr;?>', // 必填,生成签名的随机串 signature: '<?php echo $signature;?>', // 必填,签名 jsApiList: [ // 必填,需要使用的JS接口列表 'scanQRCode', 'chooseImage', 'getLocation', 'closeWindow' // ... 更多接口 ... ] }); wx.ready(function(){ // config信息验证成功后会执行ready方法,所有接口都可以使用 // 如:调用扫一扫 document.getElementById('scanBtn').onclick = function() { wx.scanQRCode({ desc: 'scanQRCode desc', needResult: 1, // 默认为0,扫描结果由企业微信处理,1则直接返回扫描结果, scanType: ["qrCode","barCode"], // 可以指定扫二维码还是一维码,默认二者都有 success: function (res) { var result = res.resultStr; // 当 needResult 为 1 时,扫码结果会从 res.resultStr 中返回 alert('扫码结果:' + result); } }); }; }); wx.error(function(res){ // config信息验证失败会执行error方法,如签名过期导致验证失败,具体错误信息可以打开debug模式查看 alert("JS-SDK配置失败:" + res.errMsg); }); -
常用JS-SDK接口举例:
-
wx.scanQRCode(OBJECT):调起微信扫一扫。-
needResult: 0 (微信处理) / 1 (返回结果)。 -
scanType:["qrCode", "barCode"]。
-
-
wx.chooseImage(OBJECT):拍照或从手机相册中选图。-
count: 最多可选图片张数。 -
sizeType:['original', 'compressed'](原图/压缩图)。 -
sourceType:['album', 'camera'](相册/相机)。 -
success回调返回localIds(本地图片ID)。
-
-
wx.uploadImage(OBJECT):上传图片到微信服务器。-
localId:chooseImage返回的本地图片ID。 -
isShowProgressTips: 是否显示进度提示。 -
success回调返回serverId(微信服务器媒体ID,可用于后端下载)。
-
-
wx.getLocation(OBJECT):获取地理位置。-
type:wgs84(标准GPS坐标) /gcj02(国测局坐标)。 -
success回调返回latitude(纬度),longitude(经度) 等。
-
-
wx.closeWindow():关闭当前企业微信网页窗口。
-
-
用途:实现网页签到、拍照上传报销单据、扫码核销、位置打卡、企业内部移动审批流、自定义表单等,极大地增强网页的交互性和功能性。
六、媒体文件管理
1. 上传临时素材
-
功能:上传图片、语音、视频等临时文件到企业微信服务器,获取
media_id,用于在消息发送、朋友圈等场景使用。 -
接口:
POST https://qyapi.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE -
调用频率限制:每天有上限,单个文件大小有限制,
media_id有效期3天。 -
请求参数:
-
access_token:access_token。 -
type:媒体文件类型,如image(图片),voice(语音),video(视频),file(文件)。 -
文件内容:通过
multipart/form-data方式上传文件二进制内容。
-
-
返回数据结构 (JSON):
{ "errcode": 0, "errmsg": "ok", "type": "image", // 媒体文件类型 "media_id": "MEDIA_ID", // 媒体文件ID "created_at": "1391307685" // 媒体文件上传时间戳 } -
示例 (Python):
# 假设 access_token 已获取,并有一个本地图片文件 'test.jpg' file_path = 'test.jpg' media_type = 'image' url = f"https://qyapi.weixin.qq.com/cgi-bin/media/upload?access_token={access_token}&type={media_type}" with open(file_path, 'rb') as f: files = {'media': (file_path, f, 'image/jpeg')} # ('文件名', 文件对象, 'Content-Type') response = requests.post(url, files=files).json() if response.get("errcode") == 0: media_id = response["media_id"] print(f"媒体文件上传成功,media_id: {media_id}") # 这个 media_id 就可以用于发送图片消息了 else: print(f"媒体文件上传失败: {response.get('errmsg')}") -
用途:发送图片/语音/视频/文件消息,或者在网页中需要临时展示或提交用户上传的媒体文件时使用。
七、最佳实践与温馨提示
-
access_token缓存与刷新:必须缓存! 避免每次请求都去获取,同时也避免过期导致调用失败。一般提前几分钟刷新即可。 -
错误处理:所有接口都会返回
errcode和errmsg。务必对errcode进行判断,非0则表示失败,根据错误码进行相应的处理(如access_token失效时重新获取)。 -
异步处理回调消息:接收消息回调时,企业微信服务器等待你的响应时间有限。如果你的业务逻辑耗时较长,请务必将消息处理放到异步队列中,立即返回
success或空字符串给企业微信,避免超时导致重复推送。 -
SDK 优先:对于消息加解密、JS-SDK签名计算等复杂流程,强烈推荐使用官方或成熟的第三方SDK(如 Python 的
wechatpy、wecom-sdk,Java 的WxJava等),它们已经封装好了底层的复杂逻辑和安全校验,能大大提高开发效率和安全性。 -
安全性:回调URL验证、消息加解密、敏感信息保护(如
corpsecret绝不能暴露在前端或版本控制中)。 -
频率限制:留意每个接口的调用频率限制,合理设计你的系统,避免触发限流。
-
阅读官方文档:本文仅为常用接口的概览,企业微信官方文档(https://developer.work.weixin.qq.com/document/path/90000)才是最全面、最权威的参考。
掌握了这些常用接口和其背后的逻辑,你就能在企业微信开发这条路上,像个老练的期货交易员一样,抓住核心,规避风险,稳步前行!祝你开发顺利,应用大卖!