☰
企业微信二次开发:通讯录成员和部门怎么批量增删改,同步 HR 系统?
2026/10/27 5:53:10 网站建设 项目流程

HR 系统里建了新员工、改了部门归属、标记了离职,企微那边能不能自动跟上?很多团队第一步就卡在"API 到底能不能写通讯录"这个问题上。先讲清楚边界,再给方案。

先回答一个关键问题:API 能直接改通讯录吗?

不能。

企业微信的通讯录接口设计里,所有写入操作(创建、删除、修改成员和部门)都不开放给三方 API。Eyun 的 App Token 体系下也一样,没有createMember、deleteMember、updateMember这类接口。

这件事必须绕路——要么走企微管理后台的批量导入,要么接企业微信官方通讯录 API(鉴权体系完全不同)。而你能通过 Eyun API 做的,是高效地把企微的通讯录数据同步回来,让自有系统和企微保持一致。

换句话说:企微是通讯录的"真源",API 是"读通道"。HR 系统要同步企微,方向是"企微 → 你的系统",不是反过来。

整体架构:三种规模的选型

团队规模

推荐方案

成本

复杂度

50 人以内

HR 改企微后台,API 拉数据

零

低

50-500 人

HR 批量导入 + API 增量同步

低

中

500 人以上

官方通讯录 API 双向同步

中高

高

中小团队选前两种足够了,不需要为了"一步到位"硬接官方接口。下面重点讲第二种的实现。

核心流程:管理后台改企微,API 自动感知变化

HR 系统改了 ↓ 管理员在企微管理后台批量导入 Excel ↓(企业微信内部同步) 企微服务端通讯录更新 ↓ Eyun API:contact/getSyncList 游标增量拉取 ↓ 你的系统:比对差异、更新数据库、触发后续动作

整个链条里,写入动作由管理后台完成,API 只负责"读回来"。关键是把拉取、比对、落库、游标持久化这几步做扎实。

第一步:用 getSyncList 拉增量

contact/getSyncList是核心接口,支持游标增量。传上次存的 cursor,只返回变化的数据。

def sync_contacts(cursor=None): """拉取通讯录增量,自动分页""" headers = {"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"} payload = {"appid": APPID, "type": 2} # type=1 部门, 2 成员 if cursor: payload["cursor"] = cursor resp = requests.post( f"{BASE}/wx-api/api/contact/getSyncList", headers=headers, json=payload, timeout=10 ).json() if resp["code"] != 0: logger.error(f"同步失败: code={resp['code']}, msg={resp.get('message')}") return None data = resp["data"] items = data.get("items", []) next_cursor = data.get("nextCursor") process_items(items) if next_cursor and data.get("hasMore"): # 还有下一页,递归拉 sync_contacts(next_cursor) return next_cursor

type必须分开调:先传 1 拉部门树,再传 2 拉成员。两类数据要分别存游标。

第二步:补全成员详情

getSyncList返回的成员只有基础字段(uin、name、deptIds、isDeleted)。要拿手机号、邮箱、头像、外部联系人等完整信息,需要批量调详情接口:

def enrich_profiles(uins): """批量拉成员详情,每批最多 50 个""" profiles = {} for i in range(0, len(uins), 50): batch = uins[i:i + 50] resp = requests.post( f"{BASE}/wx-api/api/contact/fetchUsersProfileBatch", headers=HEADERS, json={ "appid": APPID, "uinList": batch, "fetchFields": ["basic", "contactInfo", "external"] } ).json() if resp["code"] == 0: profiles.update(resp["data"]) return profiles

fetchFields按需传,减少不必要的传输。uinList必须是 int64 数组,不能传字符串。

第三步:比对差异,更新数据库

拿到增量 items 后,和本地数据库比对,分三种情况处理:

def process_items(items): uins = [item["id"] for item in items] profiles = enrich_profiles(uins) for item in items: uin = item["id"] profile = profiles.get(uin, {}) if item.get("isDeleted"): # 员工离职,软删除 mark_inactive(uin) else: # 新增或更新,用 profile 里的最新字段 upsert_member(uin, profile, item.get("deptIds")) def upsert_member(uin, profile, dept_ids): db.execute(""" INSERT INTO members (uin, name, phone, email, dept_ids, updated_at) VALUES (?, ?, ?, ?, ?, datetime('now')) ON CONFLICT(uin) DO UPDATE SET name=excluded.name, phone=excluded.phone, email=excluded.email, dept_ids=excluded.dept_ids, updated_at=datetime('now') """, ( uin, profile.get("nickname", ""), profile.get("phone", ""), profile.get("email", ""), json.dumps(dept_ids or []) ))

用ON CONFLICT ... DO UPDATE一条 SQL 搞定新增和更新,省得先查后写。

第四步:游标持久化 + 定时任务

游标丢了就得全量重拉,必须存下来:

def save_cursor(sync_type, cursor): db.execute( "INSERT OR REPLACE INTO sync_cursors " "(sync_type, cursor, updated_at) VALUES (?, ?, datetime('now'))", (sync_type, cursor) ) def load_cursor(sync_type): row = db.execute( "SELECT cursor FROM sync_cursors WHERE sync_type=?", (sync_type,) ).fetchone() return row[0] if row else None

定时任务建议频率:

任务

频率

说明

成员增量同步

每 5 分钟

员工变动相对频繁

部门增量同步

每 30 分钟

部门变动少

全量核对

每天凌晨 3 点

防止游标增量漏事件

全量核对很重要——游标增量是"假设不丢事件"的,但服务重启、网络故障时可能漏推。每天全量拉一次对比差异,发现问题就修正。

离职处理的正确姿势

成员离职时,企微会推isDeleted: true的 item。不要硬删数据库记录,标记成 inactive 即可:

def mark_inactive(uin): db.execute( "UPDATE members SET is_active=0, left_at=datetime('now') WHERE uin=?", (uin,) ) # 触发后续:清 CRM 分配、解除外部联系人绑定 notify_downstream(uin, "employee_left")

保留历史记录,销售还能查之前跟这个客户的聊天记录。同时触发下游动作:清 CRM 分配、解除外部联系人绑定、通知财务停发工资等。

如果真的需要"API 直接写入"怎么办?

有一条路:接企业微信官方通讯录接口。

官方确实提供了创建成员、删除成员、修改部门等接口(https://qyapi.weixin.qq.com/cgi-bin/user/create这类),鉴权用官方access_token。但有两个前提:

鉴权体系不通用。官方 access_token 和 Eyun App Token 是两套东西,不互通。同时维护两套凭证和刷新逻辑是额外成本。

需要企业微信管理后台授权。官方接口要在管理后台创建"通讯录管理"应用,并分配对应的权限。

如果团队规模超过 500 人、确实需要 HR 系统改了企微自动跟着改,才值得接。中小团队没必要。

最简定时任务实现

import schedule import time def job(): # 先同步部门,再同步成员 dept_cursor = load_cursor("dept") dept_next = sync_contacts(dept_cursor) if dept_next: save_cursor("dept", dept_next) member_cursor = load_cursor("member") member_next = sync_contacts(member_cursor) if member_next: save_cursor("member", member_next) schedule.every(5).minutes.do(job) while True: schedule.run_pending() time.sleep(1)

最后

通讯录同步的关键不是"怎么写",而是"怎么读得准"。先把 API 的只读能力用好,游标增量、差异比对、软删除、定时全量核对都做扎实,覆盖 90% 的团队需求。剩下 10% 的写入诉求,走官方接口或管理后台批量导入即可。

关于企微 API 没有独立写入接口这个边界,在开发文档的 contact 模块里也明确标注了。游标增量的完整参数和返回字段,以及 App Token 的获取方式,都能在 Eyun 控制台和官网上查到。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询