企业微信开发常用接口

老铁们,搞企业微信开发,跟咱们在市场里炒期货一样,得抓住核心,把常用的“招数”练熟了,才能在实战中游刃有余。

企业微信(WeCom)的接口那叫一个海量,但平时咱们用得多的,也就是那么一些关键的。今天,我就以一个过来人的身份,把企业微信开发里那些最常用、最核心的接口给你们扒拉出来,详细讲解它们的功能、用法、数据结构,再给你们上几个“实战案例”,让你们看得明明白白,拿来就能用!

记住,这是“常用接口”,不是全部,但掌握了这些,你就能搭起一个像模像样、解决实际问题的企业微信应用了!


企业微信开发:常用接口实战手册

概述:企业微信开发的核心逻辑

企业微信应用开发,说白了就是你的服务器(或你的应用)和企业微信服务器之间的数据交换。它主要围绕以下几个核心任务展开:

  1. 身份认证:让你的应用能“合法”地访问企业微信的数据。

  2. 获取信息:从企业微信获取企业成员、部门、外部联系人等数据。

  3. 消息互动:你的应用给成员发消息,成员给你的应用发消息。

  4. 网页能力:在企业微信内部打开网页,调用手机硬件能力(如扫码、拍照)。

  5. 文件管理:上传下载媒体文件。

所有的接口调用,几乎都离不开一个东西——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)

  • 功能:在企业微信内部打开的网页,可以调用手机的各种原生能力,如扫码、拍照、获取地理位置等。

  • 使用流程

    1. 你的后端服务器获取 access_token

    2. 根据 access_token 获取 jsapi_ticket

    3. 前端网页通过 jsapi_ticketnoncestr(随机字符串)、timestamp(时间戳)和当前页面的 url 进行签名计算,并通过 wx.config 配置JS-SDK。

    4. 配置成功后,即可在前端调用 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_tokenaccess_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')}")
    
  • 用途:发送图片/语音/视频/文件消息,或者在网页中需要临时展示或提交用户上传的媒体文件时使用。

七、最佳实践与温馨提示

  1. access_token 缓存与刷新必须缓存! 避免每次请求都去获取,同时也避免过期导致调用失败。一般提前几分钟刷新即可。

  2. 错误处理:所有接口都会返回 errcodeerrmsg。务必对 errcode 进行判断,非0则表示失败,根据错误码进行相应的处理(如 access_token 失效时重新获取)。

  3. 异步处理回调消息:接收消息回调时,企业微信服务器等待你的响应时间有限。如果你的业务逻辑耗时较长,请务必将消息处理放到异步队列中,立即返回 success 或空字符串给企业微信,避免超时导致重复推送。

  4. SDK 优先:对于消息加解密、JS-SDK签名计算等复杂流程,强烈推荐使用官方或成熟的第三方SDK(如 Python 的 wechatpywecom-sdk,Java 的 WxJava 等),它们已经封装好了底层的复杂逻辑和安全校验,能大大提高开发效率和安全性。

  5. 安全性:回调URL验证、消息加解密、敏感信息保护(如 corpsecret 绝不能暴露在前端或版本控制中)。

  6. 频率限制:留意每个接口的调用频率限制,合理设计你的系统,避免触发限流。

  7. 阅读官方文档:本文仅为常用接口的概览,企业微信官方文档(https://developer.work.weixin.qq.com/document/path/90000)才是最全面、最权威的参考。

掌握了这些常用接口和其背后的逻辑,你就能在企业微信开发这条路上,像个老练的期货交易员一样,抓住核心,规避风险,稳步前行!祝你开发顺利,应用大卖!