NEW

免费试用已开放

立即开始

私域 · 营销 · SCRM · 客户

企业微信 SCRM 怎么开发

更新于 2026-06-0910 分钟

SCRM 的本质是「以客户为中心」把会话、标签、触达与数据打通。开发上不必一次做全,按客户档案 → 会话归集 → 自动化触达 → 数据回流的顺序推进最稳。

先拆清楚:SCRM 是四段工程,不是一个系统

「企业微信 SCRM 怎么开发」这个问题下面压着四段彼此独立的工程,它们的数据模型、失败方式和验收标准都不一样。当成一个系统一次性开发,最常见的结果是四块各做到一半:客户档案里一半是重复的人,标签没人敢按它筛,自动化发出去的消息没人说得清效果,报表和明细永远对不上。

  • 客户与标签:统一客户档案、身份归一、分层标签。它是唯一的事实源,其余三块都读它。
  • 会话归集:把多个账号的会话与事件汇到一处,让「发生了什么」可被程序消费,也让人工分配与质检有落点。
  • 自动化触达:按标签与事件决定「该对谁做什么」,再交给发送执行器。决策与执行必须分开。
  • 数据回流:把触达结果、会话行为与业务转化写回自己的库,支撑分群、归因与复盘。

四块之间只有一条硬依赖:后三块都依赖第一块的身份归一。所以顺序不能调换 —— 身份没归一之前做的标签、触达和报表,后面都要重做一遍。

开工前要先定死的五件事

这一节没有一条是代码问题,但每一条做错,三个月后都会变成一次带历史数据的迁移。

  1. 1客户主档的粒度。主档记录的是一个真实的人,不是「某个成员视角下的一个联系人」。同一个客户被三个销售各自添加过是常态,所以身份表从一开始就要建成多对一挂到主档上,合并依据按可信度排序,模糊匹配只能生成待确认队列。
  2. 2账号维度。多账号统一管理是企业级 SCRM 的默认诉求。把账号实例标识(发送时请求体里的 guid)纳入身份表、会话流水、触达流水三张表的键组成,后期就不用为它重构。
  3. 3每个字段的写入方。一个字段只要有两个写入方,三个月内就会失去可信度。站内讲客户标签体系设计的那篇把这条拆得很细:标签按来源、阶段、意向、行为切成四层,每层只允许一个写入方,人写的程序不改,程序写的不给手动摘除入口。
  4. 4阶段的建模方式。客户阶段是状态机不是标签 —— 互斥单值、每次变更留痕、并发写入时用期望前态挡住覆盖。站内讲客户生命周期建模的那篇讲了怎么按运营动作切格,以及为什么每一格都要有停留时长上限。
  5. 5接入方式与凭证。在 wecomapi 控制台 manager.wecomapi.com 创建密钥、配置回调地址,字段定义与错误码以文档 post.wecomapi.com 为准。云端订阅按账号计费,¥100/账号/月 是单账号封顶价,订阅内可无限次调用接口、不按调用次数计费(适用公平使用策略),所以对账、重放这类调用量大但工程上正确的做法,不会被成本模型反向绑架。

分步骤实施:每一步都要有可判断的完成标志

  1. 1建客户主档与身份映射。做什么:拆成两张表,主档是人,身份表是「某账号视角下的联系人」,多对一挂上去。看什么:跑一遍存量导入,看身份条数与主档条数的比值。判断成了:同一个已确认的客户在主档里只有一条,并且能反查出它在哪几个账号下被添加过。
  2. 2接事件回调,让系统可观测。做什么:在控制台配回调地址,订阅消息、客户与群事件;回调里只做验签、快速 ACK、入队,不做任何同步落库。看什么:回调响应耗时与队列积压曲线。判断成了:手动加一个好友、发一条消息,几秒内在事实流水表里能查到对应记录,且同一事件重复投递不会产生第二条。
  3. 3在通过那一刻写死来源。做什么:把来源写入和通过事件放进同一次消费,而不是先建档、再由另一个任务回来补。站内讲获客来源归因的那篇讲了渠道码上为什么只该放一个引用键、以及完整链路的六跳各自要有分母。判断成了:未知来源是一个正式枚举值而不是空,它的占比就是你的归因覆盖率。
  4. 4把事实翻译成阶段与标签。做什么:推导规则写成纯函数,输入当前阶段和一批事实,输出下一格;采集代码只负责把事件原样存成事实,不做解释。判断成了:能在上个月的事实流水上重跑一遍规则,只算不写,产出一份新旧差异报告。
  5. 5接自动化触达。做什么:决策层只产出触达任务写进任务表,执行器只负责发,两者之间用表解耦。判断成了:把执行器停掉,任务照常堆积不丢;重新启动后按顺序发完,且没有一条重复。
  6. 6打通数据回流。做什么:触达流水、会话行为、业务转化各自成表,统一按客户主档 ID 关联。判断成了:能回答「上周从某个渠道进来的客户,有多少人在第三天还回过消息」这类需要跨三张表的问题。
示意:触达执行器只做「发」这一件事javascript
// 示意逻辑,精确字段、错误码与频率约束以线上接口文档为准
async function deliver(task) {
  if (!(await once(`deliver:${task.id}`))) return;   // 任务 ID 幂等,重投不重发

  const res = await fetch("https://manager.wecomapi.com/message/sendText", {
    method: "POST",
    headers: {
      Authorization:  `Bearer ${process.env.TOKEN}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      guid:    task.accountId,     // 用哪个账号实例发,由调度层决定
      toId:    task.customerId,
      content: render(task.template, task.vars),
    }),
  });

  const requestId = res.headers.get("x-request-id");          // 排障时提供它即可定位
  const remaining = res.headers.get("x-ratelimit-remaining");
  const body = await res.json();                              // { "code": 0, "msg": "success" }

  await touchLog.write({           // 触达流水单独一张表,不写进客户主档
    taskId: task.id, accountId: task.accountId, customerId: task.customerId,
    ok: body.code === 0, code: body.code, msg: body.msg, requestId,
  });

  if (remaining !== null && Number(remaining) < LOW_WATER) {
    await pacer.slowDown(task.accountId);   // 按账号降速,不是按全局
  }
}

架构与数据流:谁调谁、状态存哪、谁负责重试

把上面几步接起来,一条完整链路只有四跳,每一跳的职责边界都要划死。

  1. 1事件入口。wecomapi 的事件回调把账号侧事件推到你的地址,入口第一件事是按账号实例标识分流并写进日志上下文,然后快速 ACK 入队。这一跳不允许出现任何业务逻辑。
  2. 2事实层。事件原样落成带时间戳的流水,保留原始报文。半年后想加一条新判据,靠的就是当初多存的那些内容。
  3. 3决策层。规则引擎读事实流水与客户主档,产出两类输出:状态变更(阶段、标签)和触达任务。它是纯计算,不直接调接口。
  4. 4执行层。发送执行器从任务表取任务、调消息接口、把结果写回触达流水。限速、退避与重试全部收在这一层。

状态存哪只有一个答案:客户主档、阶段、标签存在你自己的库里,这是唯一的事实源;企业微信侧的客户标签是它的一次投影,只下行不回写。会话与事件的原始流水另存一份,它的写入量比主档高一到两个量级,和主档放同一张表迟早要拆。

重试只发生在执行层。回调入口不重试(投递方会重投,你只要保证幂等),决策层不重试(重放事实即可重算),执行层的重试也要发生在队列里而不是请求线程里。三层都做重试的系统,一次网络抖动会被放大成几十条重复消息。

错误处理与排障

SCRM 的线上故障很少表现为接口报错,多数是「东西还在跑,但结果不对」。所以排障第一步是分清这次到底是调用失败,还是数据错了。

调用失败这一侧,按「该做什么」分而不是按码值背:确定性失败(参数不合法、对象不存在)要立刻停,并且把告警指向调用点;状态失败(凭证或登录态失效)先执行一个明确的修复动作,然后只重试一次;容量失败(被频控)要退避,而且退的是整个账号的发送节奏,不是当前这一条请求;结果未知(超时、连接中断)该做的是确认而不是重试。站内讲接口报错怎么分类的那篇把四类的边界和两个最贵的误判拆得更细。

  • 消息显示发成功但客户说没收到:先在触达流水里按客户查这条记录。流水里根本没有,说明问题在决策层没产出任务,跟发送无关;流水里有,就拿这次调用的 x-request-id 去定位,它在响应头里回传。
  • 同一条消息发了两遍:查幂等键。最常见的原因不是平台重投,而是幂等键没带上处理器身份,或者去重写在了 HTTP handler 里,挡不住内部队列的重投。
  • 触达突然大面积变慢:看响应头 x-ratelimit-remaining 的走势,并确认降速开关是不是按账号存的。存成一个全局开关的后果是某一个账号被限住、其它账号陪着一起慢,而监控上完全看不出原因。
  • 标签或阶段和预期不符:不要直接改库。先在事实流水上把推导规则重跑一遍、只算不写,看差异集中落在哪一条规则上,改完规则再重放。
  • 报表和明细对不上:几乎都是口径问题 —— 来源取的是主档还是触点流水、转化的时间戳取的是事件时间还是入库时间。两个口径要分开命名,别都叫同一个名字。

上面所有排查都有一个前提:这个客户在你库里是一条记录。身份没归一时,同一个人分散成三条,任何一条排查路径都会得出错误结论,而且整个过程不会有任何报错。

怎么验证做对了

「跑起来了」不是验收标准。下面每一条都是可观察的判据,做完一块验一块,不要留到最后一起验。

  • 身份归一:随机抽一批在两个以上账号下出现过的客户,主档里各只有一条,并且能列出它们各自的归属成员。
  • 事件不丢不重:取同一段时间窗,事实流水的条数与控制台看到的事件与调用情况能对上;把这批事件原样重放一遍,流水条数不变。
  • 规则可重算:在上个月的事实流水上重跑推导规则,能给出一个具体的新旧差异率数字,而不是「应该差不多」。
  • 触达可追溯:任取一条已发出的消息,能说清它由哪条规则触发、用哪个账号实例发出、返回的 x-request-id 是多少。
  • 阶段不堆积:各阶段的人数分布与平均停留时长有图可看,每一格都有停留上限,某一格越堆越多时告警会响。
  • 投影是单向的:企业微信侧的客户标签只有程序下行写入这一个来源。一线手动摘掉一个投影标签后,下一轮投影会把它加回来 —— 这是预期行为,不是缺陷。

这六条都能给出肯定回答,这套 SCRM 才算有了继续加功能的地基;有任何一条答不上来,先补它,而不是先加新的运营玩法。

常见问题

企业微信 SCRM 自研和买现成的怎么选?
标准场景先用现成产品验证需求;当运营规则高度定制、要和自有 CRM 或订单系统深度打通、或者需要多账号统一编排时,用接口自研或混合更划算。判断依据不是功能清单长短,而是未来半年真正会调用的动作有几个 —— 通常不超过十五个,只核这十几个就够。
开发一套企业微信 SCRM,应该先做哪一块?
先做客户主档与身份归一,它是另外三块的地基;再接事件回调让系统可观测;然后叠加自动化触达;最后做数据回流与复盘。顺序反过来做,身份没归一之前产出的标签、触达记录和报表基本都要重来一遍。
多个企业微信账号能统一管理吗?
可以。在调用层这件事几乎是免费的 —— 同一个端点、同一套鉴权,请求里换一个账号实例标识就是换账号发。真正的复杂度在于谁来决定这次用哪个实例、以及那个实例此刻能不能用,所以建议第一周就把账号维度纳入数据模型。
客户标签要不要全部同步到企业微信侧?
不要。聊天侧边栏是给人扫一眼用的,能承载的信息量大概十个标签,而行为层标签一个客户就能产出几十条。把来源、阶段、意向三层投影下去,行为层留在自己库里当规则引擎的输入,需要时聚合成一个意向结论再下行。
企业微信 SCRM 的消息发出去了但客户没收到,怎么排查?
先在自己的触达流水里按客户查这次记录。流水里没有,问题在决策层没产出任务;流水里有,就拿这次调用的 x-request-id 去定位,它在响应头里回传,提供它即可查到对应调用。
从别的接入方式迁到 wecomapi,改动大吗?
业务逻辑、数据模型和规则引擎都不用动,变的只是调用层的地址与鉴权,上层代码基本不需要改动。迁之前先在文档上核对你真正会用到的那十几个动作,字段定义与错误码以线上接口文档为准。

准备好动手了?

精确字段、鉴权与端点以线上文档为准;可在控制台创建密钥后联调。

相关指南