Reactive CRM 网站线索集成指南 ← 集成指南

从您的网站获取线索

将您的网站表单与 ReactiveCRM 集成的说明:将表单提交捕获为线索、发送营销归因事件并验证结果。

1. 概述

推荐流程由两个请求组成:

  1. 网站将表单数据发送到自己的后端。
  2. 网站后端通过 POST /api/leads/create 在 CRM 中创建线索。
  3. 创建成功后,后端通过 POST /api/dashboard/marketing/events 发送 lead_submitted 营销事件,并传递收到的 leadId。
  4. CRM 存储 UTM 标签、广告标识符和引荐来源以用于营销归因。
文本
网站表单
    |
    v
网站后端 / 服务端代理
    |  POST /api/leads/create
    v
ReactiveCRM -> leadId
    |  POST /api/dashboard/marketing/events
    v
营销归因与仪表板

不要从浏览器直接发送 CRM JWT 和机密信息。使用网站后端或 Serverless 函数,以确保 CRM 令牌和服务标识符永远不会暴露给访客。

2. 认证与基础 URL

所有请求均在相关租户的上下文中运行,并需要 CRM 授权:

http
Authorization: Bearer <CRM_ACCESS_TOKEN>
Content-Type: application/json

示例中使用:

文本
CRM_BASE_URL=https://crm.example.com

请将其替换为您环境的 URL。

3. 在网站上收集的数据

线索数据

要创建线索,API 支持:

字段必填描述
message否表单中的咨询消息或文本
ownerId是负责该线索的 CRM 用户 UUID
authorId是创建该线索的 CRM 用户 UUID
clientId否现有客户 UUID
contactId否现有联系人 UUID
leadSourceId否线索来源树中的节点 UUID
statusId否初始状态 UUID
quality否HOT、WARM、COOL 或 COLD

ownerId 和 authorId 是 CRM 用户的 UUID。对于公开的网站表单,不要让访客自行设置这些值:后端必须从集成配置中提供它们。

营销访问数据

在表单提交之前,将以下内容存储在 cookie、会话存储或后端中:

在首次访问时保存这些值,并在网站内导航时不要用空参数覆盖它们。

4. 创建线索

端点

http
POST /api/leads/create

请求示例

bash
curl -X POST "$CRM_BASE_URL/api/leads/create" \
  -H "Authorization: Bearer $CRM_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "message": "网站咨询:咨询请求",
    "ownerId": "11111111-1111-1111-1111-111111111111",
    "authorId": "11111111-1111-1111-1111-111111111111",
    "quality": "WARM"
  }'

201 Created 响应示例

json
{
  "id": "22222222-2222-2222-2222-222222222222",
  "message": "网站咨询:咨询请求",
  "quality": "WARM",
  "dealId": null,
  "createdAt": "2026-09-05T20:00:00Z",
  "updatedAt": "2026-09-05T20:00:00Z",
  "version": 0,
  "author": {
    "id": "11111111-1111-1111-1111-111111111111",
    "firstName": "CRM",
    "lastName": "机器人"
  },
  "owner": {
    "id": "11111111-1111-1111-1111-111111111111",
    "firstName": "CRM",
    "lastName": "机器人"
  }
}

保存响应中的 id:该值将传递到营销事件的 leadId 字段中。

5. 发送线索提交事件

端点

http
POST /api/dashboard/marketing/events

请求示例

bash
curl -X POST "$CRM_BASE_URL/api/dashboard/marketing/events" \
  -H "Authorization: Bearer $CRM_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "eventType": "lead_submitted",
    "occurredAt": "2026-09-05T20:00:00Z",
    "visitorId": "visitor-8b7f",
    "sessionId": "session-31ac",
    "leadId": "22222222-2222-2222-2222-222222222222",
    "externalId": "site-form-submit-20260905-000123",
    "source": "website",
    "channel": "paid",
    "utmSource": "google",
    "utmMedium": "cpc",
    "utmCampaign": "summer-consulting",
    "utmContent": "banner-a",
    "utmTerm": "crm consultation",
    "gclid": "EAIaIQobChMI-example",
    "landingUrl": "https://www.example.com/consultation",
    "referrer": "https://www.google.com/",
    "metadata": {
      "formName": "consultation",
      "pageType": "landing"
    }
  }'

响应示例

json
{
  "accepted": true,
  "duplicate": false,
  "eventId": "33333333-3333-3333-3333-333333333333"
}

如果同一个 externalId 已经针对此 source 和租户对处理过,API 会返回一个带有 duplicate: true 的成功响应。请将其视为成功而非错误,并且不要创建第二个线索。

6. 服务端处理程序示例

下面是一个简化的 Node.js 示例。表单数据必须发送到网站后端,而不是从浏览器直接发送到 CRM。

js
async function createWebsiteLead(form, attribution) {
  const headers = {
    Authorization: `Bearer ${process.env.CRM_ACCESS_TOKEN}`,
    'Content-Type': 'application/json',
  };

  const leadResponse = await fetch(
    `${process.env.CRM_BASE_URL}/api/leads/create`,
    {
      method: 'POST',
      headers,
      body: JSON.stringify({
        message: form.message || `网站咨询:${form.subject || '无主题'}`,
        ownerId: process.env.CRM_LEAD_OWNER_ID,
        authorId: process.env.CRM_LEAD_AUTHOR_ID,
        quality: 'WARM',
      }),
    },
  );

  if (!leadResponse.ok) {
    throw new Error(`CRM 线索创建失败:${leadResponse.status}`);
  }

  const lead = await leadResponse.json();
  const externalId = `website-${form.requestId}`;

  const eventResponse = await fetch(
    `${process.env.CRM_BASE_URL}/api/dashboard/marketing/events`,
    {
      method: 'POST',
      headers,
      body: JSON.stringify({
        eventType: 'lead_submitted',
        occurredAt: new Date().toISOString(),
        visitorId: attribution.visitorId,
        sessionId: attribution.sessionId,
        leadId: lead.id,
        externalId,
        source: 'website',
        channel: attribution.channel || 'direct',
        utmSource: attribution.utmSource,
        utmMedium: attribution.utmMedium,
        utmCampaign: attribution.utmCampaign,
        utmContent: attribution.utmContent,
        utmTerm: attribution.utmTerm,
        gclid: attribution.gclid,
        fbclid: attribution.fbclid,
        landingUrl: attribution.landingUrl,
        referrer: attribution.referrer,
        metadata: { formName: form.formName || 'website' },
      }),
    },
  );

  if (!eventResponse.ok) {
    // 线索已创建。将事件加入队列并使用相同的 externalId 重试,
    // 而不是创建第二个线索。
    throw new Error(`CRM 营销事件失败:${eventResponse.status}`);
  }

  return { leadId: lead.id, marketingEvent: await eventResponse.json() };
}

7. 幂等性与重试

8. 个人数据与元数据

禁止在 metadata 中传递个人数据和表单内容:

个人数据只能在其对应的 CRM 实体中传递 — 例如,在预先创建的 contactId/clientId 中。在 metadata 中只保留技术属性:表单名称、页面类型、横幅变体等。

9. 典型响应与错误

HTTP情况处理方法
201线索已创建保存 id 并发送 lead_submitted
200 + duplicate: false事件已接受将 eventId 保存到集成日志中
200 + duplicate: true事件已被接受视为已处理;不要再次发送
400数据无效或 metadata 中包含 PII修复负载;不修改重试无效
401令牌无效或缺失在后端刷新 CRM 令牌
403令牌缺乏操作权限检查角色和租户
5xx / 超时临时 CRM 或网络错误使用相同的 externalId 重试;对于线索,使用队列

10. 在 CRM 中验证结果

集成后,验证:

  1. 线索通过 GET /api/leads/{id} 或在 GET /api/leads/paged 列表中出现。
  2. 线索的所有者、作者和创建时间正确。
  3. 首次发送时营销事件响应的 duplicate 为 false。
  4. 重新发送相同的提交返回 duplicate: true。
  5. 在营销仪表板中,数据显示在正确的时段、渠道和活动中。

获取已创建的线索

bash
curl "$CRM_BASE_URL/api/leads/$LEAD_ID" \
  -H "Authorization: Bearer $CRM_ACCESS_TOKEN"

获取用于列表或对账的线索

bash
curl "$CRM_BASE_URL/api/leads/paged?page=0&size=20&createdAtFrom=2026-09-05T00:00:00Z&createdAtTo=2026-09-05T23:59:59Z&sort=createdAt,desc" \
  -H "Authorization: Bearer $CRM_ACCESS_TOKEN"

page 参数从 0 开始;默认 size 为 20。要获取网站线索,如果相关数据已存储在 CRM 中,请额外使用 message、createdAtFrom/createdAtTo、contactEmail 或 search 过滤器。