企业微信API开发入门:核心参数解析与消息发送实战 做企业微信二次开发第一次把一个 API 调通其实是有一道隐形门槛的。文档翻来覆去都是 access_token、corpid、secret、agentid、userid 这些参数但没人告诉你这些值从后台哪个菜单里点出来也没人告诉你它们各自负责干什么。我前后接了好几个企业的应用从内部告警机器人到客户消息推送都做过第一次同样在这个参数准备上卡了两天。现在回头看第一次调用 API 真正要准备的不是代码而是四类参数企业身份参数、应用密钥、用户/部门参数、回调相关参数。把它们理清楚后面的 API 调用基本就是填填字段的事。1. 首次调用前必须搞清的四类参数很多人一上来就急着跑接口结果连“参数从哪来”都没搞清楚。企业微信 API 的鉴权链路和微信公众平台类似但细节有不少差异。我习惯把参数分成四组分别回答“你是谁”“属于哪个应用”“发给谁”“怎么处理事件回调”这四个问题。1.1 企业身份参数corpid 与 agentid 从哪拿corpid 是整个企业在企业微信体系里的身份证号所有 API 请求基本都要带上它。这个值不是开发者自己生成的它是企业微信后台自动分配的一串字符串常见格式以ww开头。打开企业微信管理后台在“我的企业”-“企业信息”页面最下方可以看到“企业ID”复制出来就是 corpid。注意这里要看的是企业微信管理后台不是企业微信客户端很多新手会找错地方。agentid 是自建应用的唯一编号。你在“应用管理”-“应用”-“自建”里创建一个应用后点进应用详情页能看到 AgentId 和 Secret 两个关键字段。AgentId 是一个纯数字比如1000002。它用来告诉企业微信服务端“这次请求来自哪个应用”。为什么要区分这个因为一个企业可能同时有多个自建应用比如一个是告警机器人一个是知识库查询助手它们各自有不同的权限和可见范围。如果请求里不带上 agentid企微就不知道用哪个应用的权限来响应你自然也没法做精细化的权限控制。我在实际对接中还遇到过一种情况公司买了服务商的第三方应用或者用了“通讯录同步”这类系统应用。这类应用的 agentid 获取方式会稍有不同有些在服务商后台有些是固定值。如果你第一次拿到的 agentid 在应用详情里看不到先确认是不是自建应用再去看通讯录同步助手或者服务商管理端。还有一些接口需要用到“企业微信 corpid”和“外部联系人 corpid”如果是做客户联系、微信客户群相关功能可能还要区分“企业的 corpid”和“微信开放平台账号”。第一次开发时不建议碰这部分先把基础的消息发送链路跑通再去扩展高级 API。1.2 应用密钥secret 的获取与使用规则secret 可能是新手最容易搞混的参数。它是应用级别的密钥和 corpid 配套使用用来获取访问令牌 access_token。每个自建应用都有一个独立的 secret在应用详情页的 Secret 字段旁边点击“查看”就能拿到需要管理员权限。这里有一个很容易踩的坑同一个企业下的多个应用 secret 不能混用。我见过有人把「应用A」的 secret 拿去调「应用B」的接口结果一直报 60011 权限不足排查了半天才发现是密钥对不上应用。secret 的使用规则说起来很简单调用gettoken接口时把 corpid 和 corpsecret 通过 URL 参数传过去换取 access_token。官方接口地址是https://qyapi.weixin.qq.com/cgi-bin/gettoken。这里要特别强调secret 是敏感信息绝对不要写在前端页面、小程序代码或者 GitHub 仓库里。哪怕只是内网项目也应该放到后端环境变量或配置中心。企业微信的密钥管理里有一个“重置Secret”的按钮一旦发现 secret 泄露立刻重置。但重置后之前用旧 secret 获取的 access_token 会全部失效所有相关服务都需要重新获取 token所以生产环境要谨慎操作。另外我强烈建议在应用详情页里开启“可信IP”限制只允许公司服务器出口 IP 访问。这样就算 secret 被泄露攻击者拿着它也无法从其他 IP 换取 token。不过开了白名单之后如果服务器出口 IP 发生变化API 调用会突然报60020错误到时候先检查是不是 IP 变了。还有一点要说清楚企业微信回调配置里的 Token这个和 access_token 完全是两码事。回调 Token 是用来做签名校验的不是用来调用 API 的。新手拿回调 Token 去请求接口百分百会失败。1.3 通讯录与用户参数userid 和部门id 的设计逻辑如果只是获取 access_token那你只需要 corpid 和 secret。但第一次调用 API大概率不止获取 token还要尝试发一条消息或者读取部门列表这时候就避不开 userid 和部门 id。userid 是成员在企业微信内部使用的账号区别于手机号、邮箱和微信号。管理员在后台添加成员时可以自定义 userid也可以由系统自动生成。同一个企业内userid 是唯一的。在调用通讯录相关接口时系统不认姓名只认 userid。比如发送应用消息给某个员工touser字段填的就是 userid不是“张三”。很多人第一次测试时填了员工的姓名结果报60111用户不存在这就是典型参数理解错误。部门 id 则对应通讯录里的组织架构节点。在管理后台“通讯录”里每个部门都有一个数字 id。部门 id 可以通过 API 获取也可以直接在后台的组织架构详情里看到。发送消息时toparty字段就是部门 id用来给整个部门的人推送消息。部门 id 不是随便填的必须是应用可见范围内的部门否则会报权限错误。关于 userid 的规划我个人的建议是别用姓名拼音也别用随机字符串。最好采用工号或者邮箱前缀因为这类标识跨系统一致后期做“企业微信与内部 OA 系统同步”时省很多事。如果一开始没规划好后面几百个员工的 userid 不好统一调整。1.4 回调与请求基础参数Token、EncodingAESKey、URL第一次做企业微信 API可能只用到主动调用接口也就是“我们主动请求企业微信服务端”。但如果你的应用需要接收用户消息、接收事件通知比如“成员扫码进入应用”“接收到用户发送的文本消息”那就必须配置回调。回调配置里有三个核心参数URL、Token、EncodingAESKey。URL 是你在公网能够访问到的 HTTP 服务地址企业微信服务器会把事件推送给你。Token 是你自己生成的一串随机字符串用来做签名验证。EncodingAESKey 可以理解为加解密密钥用于解密企业微信推送过来的加密消息。这三个参数都在企业微信后台的“接收消息”设置页面里配置。配置回调时最容易出问题的是“URL 验证”。企业微信会在你保存配置时向 URL 发送一个GET请求带上了msg_signature、timestamp、nonce、echostr四个参数。你的服务器需要验证签名后将解密后的 echostr 原样返回配置才算成功。很多人在这里卡住以为是代码逻辑问题其实是没有正确理解回调 API 的加解密协议。回调里的 token 和 EncodingAESKey和调用 API 的 access_token 没有任何关系。回调参数虽然不是第一次调用“主动 API”所必需的但如果你准备做的应用涉及用户互动建议首次开发时就把回调接口搭起来。哪怕只是先接收text消息后面扩展机器人的时候会方便很多。2. 最常用的消息发送接口参数拆解企业微信 API 中第一次落地最有成就感的事情就是“让一个应用给指定成员发消息”。这个场景覆盖了告警通知、日常提醒、报表推送、AI 机器人对话等大量需求。而消息发送接口也最能体现参数准备是否充分。2.1 从“发送应用消息”接口看参数分工接口路径是POST https://qyapi.weixin.qq.com/cgi-bin/message/send?access_tokenACCESS_TOKEN。这个接口的请求体是一个 JSON 对象核心字段包括{ touser: zhangsan|lisi, toparty: 2|3, totag: 1|2, msgtype: text, agentid: 1000002, text: { content: 这是一条测试消息 }, safe: 0 }看到这个结构就明白为什么第一步要先把 corpid、agentid、userid 准备好。touser是你想发给的成员toparty是你想发给的部门totag是标签agentid表示由哪个应用发送text.content就是消息正文。这里注意touser、toparty、totag这三个字段不是都要填但至少要有一个否则不知道发给谁。多个收件人用|分隔一次性最多 1000 个。safe字段很容易被忽略。0 表示消息在客户端正常展示1 表示保密消息收到后不能复制转发、不能截图外传。如果企业有信息安全要求发送工资单、合同信息时建议用safe: 1。发送消息后企业微信会返回一个 JSON{ errcode: 0, errmsg: ok, invaliduser: }当errcode为 0 时不代表所有人都收到了。invaliduser字段里如果出现了 userid说明部分用户不存在或不可用需要进一步处理。2.2 文本卡片与 Markdown 消息体写法要点文本消息虽然简单但实际项目中更多用的是文本卡片和 Markdown 消息因为可读性更好。文本卡片消息体长这样{ touser: zhangsan, msgtype: textcard, agentid: 1000002, textcard: { title: 巡检异常通知, description: 服务器 CPU 使用率超过 90%, url: https://ops.example.com/alarm/123, btntxt: 查看详情 } }这里最容易忽略的一点是url必须是应用配置的“可信域名”。企业微信出于安全考虑限制了应用中可跳转的域名。如果你在后台没有配置可信域名或者 url 的域名不在可信范围内消息虽然能发出去但用户点击卡片时无法在企业微信内打开页面。配置可信域名需要在应用详情里上传域名校验文件或通过回调方式验证这个步骤容易被当成“网络问题”而漏掉。Markdown 消息体长这样{ touser: wangwu, msgtype: markdown, agentid: 1000002, markdown: { content: ## 日报已生成\n 今日新增客户 **12** 个\nfont color\info\待跟进 3 个/font } }企业微信的 Markdown 并不是完整的 Markdown 语法它只支持标题、加粗、引用、字体颜色、链接等部分标签。不支持嵌入图片不支持 HTML 表格也不支持 JavaScript。所以不要搬一套通用的 Markdown 渲染器到这个消息体里内容会被原样展示成普通文本。我个人的经验是告警通知类消息优先用文本卡片因为卡片可以带一个明确的跳转链接数据简报类消息用 Markdown因为排版紧凑能在一个屏幕里展示更多信息。给普通用户发消息时不要用 Markdown微信客户端不一定支持还是用文本或卡片更稳。2.3 参数校验规则与边界限制第一次写参数时最烦的就是“为什么我按文档填了还是报错”。大部分情况不是傻是文档里藏了一些边界限制。文本消息content字段最大长度是 2048 字节不是 2048 个字符。中文一个字占 3 个字节UTF-8 编码所以 2048 字节大概能装 680 个汉字左右。如果你的告警消息很长超长会被截断或报错。建议业务上控制在 600 字以内既安全又便于阅读。touser支持的成员数量上限是 1000toparty上限是 100totag上限是 100。一次给全员发消息时可以直接填all但这样做权限要求高而且容易打扰别人要慎用。所有字符串都必须是 UTF-8 编码。如果你的服务端用的是 GBK 或 GB2312发送中文消息会出现乱码或者直接失败。JSON 里字符串必须加引号布尔值、数字不能加引号。agentid是数字类型如果你传成字符串1000002部分接口可能也能接受但官方推荐严格按类型来。还有一个容易忽略的字段是enable_duplicate_check它用来控制幂等。当消息发送超时你无法确定刚才那条是否发成功了如果重试可能造成用户收到多条重复消息。开启幂等后相同内容在指定时间内不会重复发送这个参数在正式环境非常有用但是第一次开发时先别加不然排查问题会多一重干扰。3. 第一次拉取 access_token 的实操步骤前面准备了这么多参数真正跑起来其实就两大步拿 token调业务接口。第一次建议从小接口开始比如获取部门列表因为你不用构造复杂 JSON只要在 URL 里带一个 token 就能验证链路通不通。3.1 用 corpid secret 获取 token 的完整示例最简单的调用方式就是浏览器直接访问一个 URL或者用 curl。拿 curl 举例curl https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpidww1234567890abcdefcorpsecretyour-secret返回内容一般是{ errcode: 0, errmsg: ok, access_token: xxxxxx, expires_in: 7200 }这里的expires_in是 7200 秒也就是 2 小时。遇到errcode不等于 0 的情况先看返回的errmsg常见的是invalid corpid或者invalid secret多半是参数复制多了空格或者 secret 看错了。用 Python 写一个完整流程也很简单import requests corpid ww1234567890abcdef secret your-secret def get_token(): url https://qyapi.weixin.qq.com/cgi-bin/gettoken resp requests.get(url, params{corpid: corpid, corpsecret: secret}, timeout5) data resp.json() if data[errcode] 0: return data[access_token] raise RuntimeError(fget token failed: {data}) token get_token() print(token)拿到 token 之后可以立刻拿“获取部门列表”接口测试curl https://qyapi.weixin.qq.com/cgi-bin/department/list?access_tokenACCESS_TOKEN如果返回的errcode是 0说明你的 corpid、secret、token 链路都是通的。这一步跑通后面的消息发送基本就成功了一半。3.2 token 的缓存策略与过期处理有些人图省事每次调用 API 都重新获取一次 token。在小流量场景没问题但企业微信对gettoken接口有频率限制而且频繁获取 token 还会导致旧的 token 失效。如果多个进程同时获取可能互相把对方的 token 顶掉于是出现“刚获取的 token 过一会儿就报 40014”的问题。正确的做法是把 token 缓存起来在过期前复用。最简单的一种实现是用内存import time token_cache { token: None, expire_at: 0 } def get_cached_token(): if token_cache[token] and tc[expire_at] time.time() 300: return token_cache[token] token get_token() token_cache[token] token token_cache[expire_at] time.time() 7200 return token这里我预留了 300 秒的提前量避免 token 刚好在请求过程中过期。多实例部署时建议把 token 放进 Redis用expire命令设置 7000 秒过期比内存缓存更可靠。如果某次请求返回了40014或42001说明 access_token 已经失效。这时候应该重新获取 token并重试当前 API 一次。注意不要在同一请求里无限循环重试最多重试一次就够了。3.3 常见鉴权报错错误码含义与排查方法我第一次调企业微信 API 时看到一长串数字错误码第一反应是去搜索引擎翻帖子。后来发现官方维护了一份“全局错误码表”但每次都翻很累。这里把第一次调用最常见的几个错误码整理成一张速查表错误码含义排查方向40001access_token 无效或过期重新获取 token检查 secret 是否被重置40003userid 不合法确认 touser 是 userid 而不是姓名40014不合法的 access_token检查缓存 token 是否过期或是否多个服务互相覆盖42001access_token 过期同 40014重新获取 token 后重试60011没有管理权限或成员不在可见范围检查应用可见范围、通讯录权限、管理员权限60020访问来源 IP 不在白名单在应用可信 IP 里添加当前出口 IP或暂时关闭限制60111用户不存在确认 userid 是否属于当前企业是否拼写错误301002通讯录权限不足在应用详情里申请“通讯录同步”或相关权限这里想单独说一下 60011。它不只是指你没有管理员权限还有一种可能是你要操作的对象不在当前应用的可见范围内。比如你把应用可见范围设成了“研发部”但touser填的是销售部的人就会报 60011。所以改权限之前先看看应用可见范围是否覆盖了你要操作的用户。另外很多错误码是权限相关而不是参数错误的。不要一看到报错就去改代码先对照错误码表定位到“参数格式”还是“权限范围”能省很多时间。4. 我踩过的坑与参数排查清单这部分算是我个人最想分享的内容。参数这个东西文档写得再详细也不如自己亲手踩一次坑来得深刻。我把这几年实战中遇到的高频问题整理出来希望能帮你少走点弯路。4.1 参数顺序、编码方式与中文乱码问题有一次线上告警机器人突然发消息乱码排查了半天发现不是企微的问题是服务器终端把 Python 脚本输出编码改了。很多灵异问题都出现在“看着是程序问题其实是编码问题”上。第一个常见问题是从后台复制 secret 或 corpid 时复制内容前后可能带了不可见字符比如换行符或空格。直接把这种内容拼进 URL就会报invalid corpid或invalid secret。解决办法很简单拿到参数后在代码里strip()一下或者在终端里用| cat -A检查不可见字符。第二个问题是中文乱码。调用消息接口时如果 JSON 文件保存的编码不是 UTF-8或者代码里resp.encoding被错误设置中文字符就会变成乱码。企业微信 API 收发的所有内容都是 UTF-8 编码。Windows 自带的记事本保存文件时默认可能是 GBK一定要另存为 UTF-8。用 Python 的requests库时通常不用手动设置编码但如果遇到乱码可以显式指定resp.encoding utf-8。第三个问题是 URL 编码。secret本身可能出现、、/这类特殊字符。当它出现在 URL 查询参数里时这些字符需要被正确转义。用requests.get(params...)会自动处理但如果你是自己拿字符串拼接 URL就要用urllib.parse.quote_plus()对 secret 进行编码。我是建议所有测试阶段都用现成的 HTTP 库别手拼 URL。4.2 如何判断是参数问题还是权限问题当接口报错时先分类。我自己的排查顺序是看errcode是否在40001、40003、40014、42001这类区间。如果是问题集中在“参数格式、token 有效期、userid 拼写”上。看errcode是否在60011、60020、301002这类区间。如果是问题集中在“可见范围、IP 白名单、通讯录权限”上。看errcode是否为0但返回里有invaliduser或invalidparty。这种情况是部分收件人参数不合法可能需要到后台逐一核对。有个技巧在企业微信管理后台的“应用管理”里每个应用下有一个API 接口调试工具你可以选择具体接口用真实的 corpid、secret 和参数进行调试。它会直接显示请求详情和返回结果。这样能帮你判断“是不是我的代码把参数搞坏了”。权限配置改完后企业微信不一定马上生效。我遇到过改完可见范围等了一两分钟才恢复正常的情况。所以如果你刚配置完就调用报错别急着怀疑代码等几分钟再试一次。4.3 一套最小可用的调试脚本最后送上一套我常用的最小脚本用 Python 实现“获取 token - 获取部门列表 - 发送文本消息”三步走。你可以直接复制到本地填上自己的参数跑一遍。import requests corpid ww1234567890abcdef secret your-secret agentid 1000002 userid zhangsan s requests.Session() # 第一步获取 access_token token_resp s.get( https://qyapi.weixin.qq.com/cgi-bin/gettoken, params{corpid: corpid, corpsecret: secret}, timeout5, ).json() if token_resp.get(errcode) ! 0: print(获取 token 失败, token_resp) exit() token token_resp[access_token] print(token 获取成功, token[:20], ...) # 第二步获取部门列表 dept_resp s.get( https://qyapi.weixin.qq.com/cgi-bin/department/list, params{access_token: token, id: 1}, timeout5, ).json() print(部门列表接口返回, dept_resp) # 第三步发送应用消息 send_resp s.post( https://qyapi.weixin.qq.com/cgi-bin/message/send, params{access_token: token}, json{ touser: userid, msgtype: text, agentid: agentid, text: {content: 第一次调用企业微信 API 成功}, safe: 0, }, timeout5, ).json() print(消息发送结果, send_resp)如果你不用 Python用 curl 验证也一样TOKEN$(curl -s https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpidww1234567890abcdefcorpsecretyour-secret | jq -r .access_token) curl https://qyapi.weixin.qq.com/cgi-bin/department/list?access_token$TOKENid1跑通这个流程后你就已经掌握企业微信 API 最核心的“骨架”了。后面的 JS-SDK 签名、网页授权、消息回调、素材上传都是在这个基础上叠加不同类型的参数。我在实际项目里发现企业微信 API 参数最难的部分不是记住它们而是搞懂每个参数在哪个后台界面产生、会被哪个接口消费。只要按本文准备的四类参数逐一梳理再配合最小脚本跑通一次之后面对通讯录同步、客户联系、消息推送这些复杂场景都会有底气。最后给一个实用建议把 corpid、agentid、userid 这类固定值整理成一份环境配置清单放到项目的 README 里后面新同事接手时能少走很多弯路。