Appearance
快速开始
接入前请准备 App Token(应用凭证)、接入地址与代理配置。三步发出消息:获取登录二维码 → 轮询直至登录成功 → 发送一条测试消息,第 4 步收到回调。
开始之前
| 你需要 | 说明 |
|---|---|
| App Token(应用凭证) | 在企业微信控制台自助开通并获取,可以先试用。形如 eyk_xxxx,整串填进 <你的 App Token> |
{BASE_URL} | 接入地址在企业微信控制台应用凭证页查看 |
| 一个企业微信账号 | 需要账号持有人本人扫码 |
| 代理 | 登录时三选一:region 省份编号 1-31、socks5 自定义代理、aid 6 位本地代理标识。代理地区必须与手机企微常用登录省份一致,怎么选见实例与代理 |
先验证凭证
正式取码前,先调只读的查询当前回调配置:body 传 {},不需要 appid,也不会创建实例。响应 code 为 0,说明 App Token 和接入地址都没问题。
bash
curl -X POST "{BASE_URL}/wx-api/webhook/get" \
-H "Authorization: Bearer <你的 App Token>" \
-H "Content-Type: application/json" \
-d '{}'通用请求结构
http
POST {BASE_URL}/wx-api/api/<模块>/<动作>
Authorization: Bearer <你的 App Token>
Content-Type: application/json
{ "appid": "we_xxxxxxxxxxxxxxx", … }响应统一封套:{ "code": 0, "data": {}, "detail": "", "message": "ok", "time": "2026-09-11 10:00:00" },code 为数字 0 表示成功。
鉴权与网关失败时,code 是字符串(如 invalid_token);业务失败时,code 为数字 -1,message 形如 -3004|参数错误。处理方法见鉴权与网关错误。
回调配置接口例外:路径是 /wx-api/webhook/<动作>,body 不带 appid。
用 Apifox 调试
- 在 Apifox 里导入 openapi.json。
- 在环境里把前置 URL 设为「接入地址 +
/wx-api」:openapi.json 里的BASE_URL变量是占位,替换成接入地址(在企业微信控制台应用凭证页查看)。 - 全局 Auth 选 Bearer Token,填入你的 App Token。
- 先调只读的查询当前回调配置,响应
code为0说明凭证可用,再调其他接口。
第 1 步 · 获取登录二维码
首次调用 getQr 时无需传入 appid,系统将自动创建实例,并在响应 data.appid 中返回实例 ID。
appid 丢失时,可以在企业微信控制台的实例页查到。
bash
curl -X POST "{BASE_URL}/wx-api/api/login/getQr" \
-H "Authorization: Bearer <你的 App Token>" \
-H "Content-Type: application/json" \
-d '{ "region": "<你的省份编号>" }'region 填账号持有人手机企微常用登录省份的编号(例如江苏是 7),编号表见实例与代理。
json
{
"code": 0,
"data": {
"imageBase64": "/9j/4AAQSkZJRgABAQEASABIAAD…",
"uuid": "61AC3F0E49D4A74A3CF5A3D4A53C6099",
"refreshInterval": 600,
"appid": "we_xxxxxxxxxxxxxxx"
},
"message": "ok"
}imageBase64是 JPEG,用data:image/jpeg;base64,<该串>渲染成二维码给账号持有人扫。uuid是本次扫码会话的票据,后面两步都要带。appid就是这台登录设备的 ID,存进你的数据库,后续所有业务接口和之后每次取码都要带上它。- 二维码 600 秒过期,过期后
checkQr返回-12007,回到本步重新取码。 - 实例在线时不要再取码。
用命令行调试时,在上面的 curl 末尾加上 > getqr.json 把响应存下来,再取出 appid 并把二维码存成图片(需要安装 jq):
bash
jq -r .data.appid getqr.json
cat getqr.json | jq -r .data.imageBase64 | base64 --decode > qr.jpg第一行输出的 appid 先存进数据库,再打开 qr.jpg 给账号持有人扫码。
一个企微账号只用一个 appid
拿到响应后先把 appid 存进数据库,再展示二维码。只有第一次取码不传 appid;之后每次取码都必须带上原来的 appid。一个企微账号只对应一个 appid:不要给同一个账号换 appid,也不要把账号登到别的 appid 上,乱换或绑错有封号风险。
接口详情:获取二维码。
第 2 步 · 轮询扫码状态
bash
curl -X POST "{BASE_URL}/wx-api/api/login/checkQr" \
-H "Authorization: Bearer <你的 App Token>" \
-H "Content-Type: application/json" \
-d '{
"appid": "we_xxxxxxxxxxxxxxx",
"uuid": "61AC3F0E49D4A74A3CF5A3D4A53C6099",
"pushHistory": false
}'命令行调试时,可以用下面的循环代替手动重复调用(需要安装 jq):每 3 秒调一次,打印 status,遇到 2 / 3 / 4 / -1 或报错时退出。status 为 10 时循环不会退出,另开一个终端按 2.1 提交验证码即可。
bash
while true; do
resp=$(curl -s -X POST "{BASE_URL}/wx-api/api/login/checkQr" \
-H "Authorization: Bearer <你的 App Token>" \
-H "Content-Type: application/json" \
-d '{
"appid": "we_xxxxxxxxxxxxxxx",
"uuid": "61AC3F0E49D4A74A3CF5A3D4A53C6099",
"pushHistory": false
}')
code=$(printf '%s' "$resp" | jq -r .code)
[ "$code" = "0" ] || { printf '%s\n' "$resp"; break; }
st=$(printf '%s' "$resp" | jq -r .data.status)
echo "status: $st"
case "$st" in 2|3|4|-1) break ;; esac
sleep 3
done每 2 到 3 秒轮询一次,读 data.status:
status | 含义 | 你该做什么 |
|---|---|---|
0 | 未扫码 | 继续轮询 |
1 / 6 | 已扫,待手机端确认 | 继续轮询 |
10 | 需要输入验证码 | 进入 2.1 |
2 | 登录成功 | 进入第 3 步 |
-1 | 登录状态失效 | 回到第 1 步重新取码 |
3 | 登录失败 | 回到第 1 步重新取码 |
4 | 用户取消登录 | 回到第 1 步重新取码 |
轮询业务失败时,顶层 code=-1;从 message 的 | 前读取企微错误码,按下表处理。鉴权与网关错误的 code 是字符串,见鉴权与网关错误。
| 企微错误码 | 含义 | 你该做什么 |
|---|---|---|
-12007 | 二维码过期 | 回到第 1 步重新 getQr |
-12006 | 请求没带 uuid | 检查请求体 |
-11002 | 账号在别处登录 | 置为离线并提示,由用户决定是否重新扫码;不要自动重连 |
更多见错误码。
2.1 提交 6 位验证码(status = 10 时)
验证码显示在账号持有人的手机企微上;持有人不在你身边时,你的系统需要提供输入框让他把验证码告诉你。
bash
curl -X POST "{BASE_URL}/wx-api/api/login/submitQrCode" \
-H "Authorization: Bearer <你的 App Token>" \
-H "Content-Type: application/json" \
-d '{
"appid": "we_xxxxxxxxxxxxxxx",
"uuid": "61AC3F0E49D4A74A3CF5A3D4A53C6099",
"code": "993416"
}'提交成功后必须再次调用 checkQr,约 6 秒后 status 由 10 变为 2 才算登录成功。
第 3 步 · 发出第一条消息
先取当前账号的 uin,给自己发一条测试消息最安全。uin、conversationId 等标识的区别见核心标识。
bash
curl -X POST "{BASE_URL}/wx-api/api/personal/getInfo" \
-H "Authorization: Bearer <你的 App Token>" \
-H "Content-Type: application/json" \
-d '{ "appid": "we_xxxxxxxxxxxxxxx" }'把上一步响应里的 data.uin 原样填进 conversationId(JSON number):
bash
curl -X POST "{BASE_URL}/wx-api/api/message/sendText" \
-H "Authorization: Bearer <你的 App Token>" \
-H "Content-Type: application/json" \
-d '{
"appid": "we_xxxxxxxxxxxxxxx",
"conversationId": 1688850000000001,
"content": "第一条测试消息"
}'响应 data.id 是消息 id,撤回消息要用它。
conversationId 必须是 JSON number
传字符串会报 cannot unmarshal string into uint64。单聊传对方的 userId,群聊传 roomId;给自己发只能用当前账号的 uin。使用错误或已失效的 uin 作为 conversationId 将返回 -4014,请先调用 personal/getInfo 获取当前 uin。
第 4 步 · 收到第一条回调
- 调设置或更新回调地址,
url填你公网可访问的地址;events不填表示订阅全部事件。仅首次创建时返回data.secret,存到服务端供验签使用;更新已有地址不返回也不改密钥,继续用已保存的值。密钥丢失的处理见回调说明。开发阶段没有公网地址,见本地联调。 - 调测试投递,你的地址收到
webhook.test,验签并可靠入队后返回 HTTP 2xx(建议返回{})。确认测试响应里的data.ok=true且data.httpStatus为 2xx;不能只看测试接口的 HTTP 200 或code=0。 - 用另一个企微账号给这个账号发一句话。
- 你的地址收到请求头
X-Eyun-Event: message.received的推送,报文里contentType为0或2,正文在content[].text。
用接口发出的消息不会推送正文
只会推一条 contentType 2001 已读回执,所以测试回调要用客户端手动发消息。
跑通的标准
- 每一步的响应
code都是0;测试推送还需确认data.ok=true且data.httpStatus为 2xx。 - 企微客户端的自聊或文件传输助手里能看到这条测试消息。
- 回调地址收到一条
contentType为0或2的message.received推送。
跑通之后
| 下一步 | 去哪 |
|---|---|
| 拉客户与同事 | 联系人 |
| 发图片、文件、链接 | 先看CDN 文件,再看消息 |
| 建群、拉人、发公告 | 群 |
| 收消息与事件 | 回调说明 |
| 排查调用失败 | 错误码 |
| 查常见问题 | 常见问题 |
上线前
- App Token 只放服务端,不要下发到客户端。
- 数字 id 一律 JSON number,解析时不要经过浮点数。
- 同一个
appid的发送进队列,避免并发直发。 - 掉线要能感知:只有
-11001可以自动调断线重连;-11002置为离线并提示,由用户决定是否重新登录;-2007带原appid重新扫码。完整做法见实例与代理 · 掉线检测与恢复。 - 要接收消息与事件,先按 回调说明 设置回调地址并测试投递通过。