salesmartly_ai_employee
    • 自定义机器人对接文档

    自定义机器人对接文档

    Webhook AI 员工 — 消息推送与回写对接文档#

    适用读者:负责实现 webhook AI 员工服务端(接收平台推送、回写消息)的工程师
    协议版本:v1(2026-05-21)

    1. 概述#

    webhook AI 员工与其他类型 AI 员工的差异仅在消息流转:消息推送和回写都通过你自己的服务端进行,由你决定如何回复。
    访客
      │  ① 发消息
      ▼
    平台
      │  ② event POST  (Bearer 鉴权)
      ▼
    你的 Webhook URL
      │  ③ AI 计算
      ▼
    你的服务端
      │  ④ POST /ai-employee/send-message  (Bearer 鉴权)
      ▼
    平台
      │  ⑤ 推送回复
      ▼
    访客
    两条链路都通过同一个 access_token 做双向 Bearer 鉴权。
    你需要从平台运维拿到两个值:
    webhook_url:你的服务端入口(HTTPS,接收平台 POST 事件)
    access_token:随机字符串(建议 ≥ 32 字节),双向鉴权凭据
    随后实现两件事:
    接收:解析平台 POST 过来的事件
    回写:调用平台 /ai-employee/send-message 接口推送 AI 的回复

    2. 推送事件(平台 → 你的 Webhook URL)#

    2.1 请求格式#

    项值
    MethodPOST
    Content-Typeapplication/json
    AuthorizationBearer {access_token}
    Body 编码UTF-8 JSON(JSON_UNESCAPED_UNICODE)
    超时10 秒

    2.2 公共字段(所有事件都有)#

    字段类型说明
    event_typestringnew_message / assign / reassign
    project_idint项目 ID
    chat_user_idstring访客 ID(24 位 ObjectId)
    channelint渠道枚举,见 附录 A
    session_idstring会话 ID(已混淆编码)
    current_assign_sys_user_idint当前接待人 sys_user_id(即你这个 webhook AI 员工的 sys_user_id)
    chat_user_infoobject访客资料快照(昵称/手机/邮箱等,结构按渠道不同)
    msg_listarray仅 new_message 事件携带,见 2.4

    2.3 事件类型#

    new_message — 访客发了新消息#

    触发时机:当前会话由 webhook AI 员工接待,访客发送了一条或多条消息
    独有字段:msg_list
    异步队列消费,可能存在几百毫秒到秒级延迟

    assign — 首次分配#

    触发时机:会话第一次分配给你
    默认延迟 3 秒投递(可在 Redis 配置 STRING_AI_EMPLOYEE_ASSIGN_EVENT_DELAY 调整)
    无 msg_list

    reassign — 转派到本员工#

    触发时机:会话从其他成员/机器人转派到你
    无 msg_list

    2.4 msg_list 子结构#

    每条消息固定结构:
    {
      "msg_type": "text",
      "msg": { ... },
      "sequence_id": "1695799154673000"
    }
    sequence_id 是消息在平台内的唯一递增序列(字符串数字)
    msg 内字段取决于 msg_type:
    msg_typemsg 字段说明
    texttext纯文本
    imageurl图片 URL
    videourl视频 URL
    audiourl音频 URL
    fileurl文件 URL
    stickerurl表情/贴纸 URL
    at_usertext, is_at_success@人,is_at_success 1/0 表示是否成功 @ 到
    emailtitle, content, attachment[]邮件(标题/正文/附件 URL 列表)
    commenttext, file[], video[], photo[]评论消息,支持 Facebook、Instagram、TikTok App 评论、TikTok 商业号评论、YouTube;file[] 只包含文件附件,video[]/photo[] 为分类附件
    templatetemplate_type, title, fields[]聊天插件留资消息;template_type 固定为 profile_collect
    unknown空字符串平台无法识别的 UNDEFINED 消息
    undecryptablereason, decrypt_fail_mode, is_unavailable, unavailable_type, original_msg_type, original_media_type个人 WhatsApp 无法解密消息,字段说明见下表
    template 消息结构说明:
    场景msg 结构说明
    聊天插件留资template_type, title, fields[]template_type 固定为 profile_collect;fields[] 每项包含 key(留资字段标识)和 value(用户填写值)
    undecryptable 字段说明:
    字段类型说明
    reasonstring无法解密原因,当前固定/默认值为 decrypt_failed
    decrypt_fail_modestringWhatsApp 上游返回的解密失败模式,对应 DecryptFailMode,无值时为空字符串
    is_unavailableint是否为上游标记的不可用消息,1 表示不可用,0 表示未标记不可用
    unavailable_typestring不可用类型,对应 UnavailableType,无值时为空字符串
    original_msg_typestring原始消息类型,对应上游 Type
    original_media_typestring原始媒体类型,对应上游 MediaType
    当用户消息引用了原消息时,消息项会额外带 quote_msg:
    {
      "msg_type": "comment",
      "msg": {
        "text": "回复内容",
        "file": [],
        "video": [],
        "photo": []
      },
      "sequence_id": "1695799154673000",
      "quote_msg": {
        "msg_type": "text",
        "msg": {
          "text": "你好"
        },
        "sequence_id": "1783496606590000"
      }
    }
    profile_collect 留资模板示例:
    {
      "msg_type": "template",
      "msg": {
        "template_type": "profile_collect",
        "title": "请介绍一下自己",
        "fields": [
          {
            "key": "email",
            "value": "101@qq.com"
          },
          {
            "key": "custom_field_76",
            "value": "123123"
          }
        ]
      },
      "sequence_id": "1695799154673000"
    }

    2.5 渠道与消息类型对应关系#

    渠道(int)支持的 msg_type
    MESSENGER(1)、INSTAGRAM(5)、TELEGRAM(4)、TELEGRAM_APP(15)、WHATSAPP(7)、LINE(6)、LINE_APP(24)、SLACK(10)、WORK_WEIXIN(11)、WORK_WEIXIN_BOT(14)、WECHAT(23)、VKONTAKTE(18)、TIKTOK_APP(16)、TIKTOK_BUSINESS(20)、ZALO_APP(19)text / image / video / audio / file / sticker / at_user / unknown
    INDIVIDUAL_WHATSAPP(12)text / image / video / audio / file / sticker / at_user / undecryptable / unknown
    CHAT_PLUGIN(2)text / image / video / audio / file / sticker / at_user / template / unknown
    CHAT_EMAIL(3)email
    FB_PAGE_COMMENT(8)、INS_COMMENT(13)、TIKTOK_APP_COMMENT(17)、TIKTOK_BUSINESS_COMMENT(21)、YOUTUBE(22)comment
    不在此表中的渠道不会触发推送事件。

    2.6 推送响应要求#

    2xx:视为接收成功
    4xx/5xx 或网络/超时异常:平台记日志,可能触发异步队列重试
    返回体内容:平台不解析正文,但建议返回 JSON {"ok": true} 以便排障

    2.7 完整 payload 示例#

    下面示例为了展示所有 msg_type 的结构,把不同渠道可能出现的消息合并在同一个 msg_list 中;真实推送时会按 channel 支持的类型发送。
    {
      "event_type": "new_message",
      "project_id": 1001,
      "chat_user_id": "65094291e106072b7e40ff21",
      "channel": 7,
      "session_id": "abc1234",
      "current_assign_sys_user_id": 1140,
      "chat_user_info": {
        "name": "Jane",
        "phone": "+8613800000000",
        "email": "jane@example.com"
      },
      "msg_list": [
        {
          "msg_type": "text",
          "msg": {
            "text": "你们的退货政策是什么?"
          },
          "sequence_id": "1695799154673000"
        },
        {
          "msg_type": "image",
          "msg": {
            "url": "https://cdn.example.com/image.jpg"
          },
          "sequence_id": "1695799154673001"
        },
        {
          "msg_type": "video",
          "msg": {
            "url": "https://cdn.example.com/video.mp4"
          },
          "sequence_id": "1695799154673002"
        },
        {
          "msg_type": "audio",
          "msg": {
            "url": "https://cdn.example.com/audio.mp3"
          },
          "sequence_id": "1695799154673003"
        },
        {
          "msg_type": "file",
          "msg": {
            "url": "https://cdn.example.com/file.pdf"
          },
          "sequence_id": "1695799154673004"
        },
        {
          "msg_type": "sticker",
          "msg": {
            "url": "https://cdn.example.com/sticker.webp"
          },
          "sequence_id": "1695799154673005"
        },
        {
          "msg_type": "at_user",
          "msg": {
            "text": "@张三 请看一下",
            "is_at_success": 1
          },
          "sequence_id": "1695799154673006"
        },
        {
          "msg_type": "email",
          "msg": {
            "title": "询盘邮件标题",
            "content": "邮件正文内容",
            "attachment": [
              "https://cdn.example.com/attachment.pdf"
            ]
          },
          "sequence_id": "1695799154673007"
        },
        {
          "msg_type": "comment",
          "msg": {
            "text": "这条帖子还有货吗?",
            "file": [
              "https://cdn.example.com/comment-file.pdf"
            ],
            "video": [
              "https://cdn.example.com/comment-video.mp4"
            ],
            "photo": [
              "https://cdn.example.com/comment-image.jpg"
            ]
          },
          "sequence_id": "1695799154673008",
          "quote_msg": {
            "msg_type": "text",
            "msg": { "text": "你好" },
            "sequence_id": "1783496606590000"
          }
        },
        {
          "msg_type": "template",
          "msg": {
            "template_type": "profile_collect",
            "title": "请介绍一下自己",
            "fields": [
              {
                "key": "email",
                "value": "101@qq.com"
              },
              {
                "key": "custom_field_76",
                "value": "123123"
              }
            ]
          },
          "sequence_id": "1695799154673010"
        },
        {
          "msg_type": "unknown",
          "msg": "",
          "sequence_id": "1695799154673011"
        },
        {
          "msg_type": "undecryptable",
          "msg": {
            "reason": "decrypt_failed",
            "decrypt_fail_mode": "device_not_available",
            "is_unavailable": 1,
            "unavailable_type": "history_message",
            "original_msg_type": "image",
            "original_media_type": "image"
          },
          "sequence_id": "1695799154673012"
        }
      ]
    }

    3. 回写消息(你的服务端 → 平台)#

    3.1 接口#

    项值
    URLPOST {平台域名}/ai-employee/send-message
    Content-Typeapplication/json
    AuthorizationBearer {access_token}

    3.2 请求体#

    {
      "sys_user_id": 1140,
      "project_id": 1001,
      "chat_user_id": "65094291e106072b7e40ff21",
      "request_id": "req_20260521_0001",
      "msg_list": [
        {
          "msg_type": "text",
          "msg": { "text": "您好,我们的退货政策是 7 天无理由退货" }
        },
        {
          "msg_type": "image",
          "msg": { "url": "https://your-cdn.com/policy.jpg" }
        }
      ]
    }
    字段类型必填说明
    sys_user_idint是当前 webhook AI 员工的 sys_user_id(必须与你在推送事件中收到的 current_assign_sys_user_id 一致)
    project_idint是项目 ID
    chat_user_idstring是访客 ID
    request_idstring是业务方生成的请求 ID,用于 5 分钟幂等
    msg_listarray是至少一条消息

    3.3 当前支持的 msg_type#

    回写接口目前支持以下消息类型:
    msg_typemsg 字段说明
    texttext纯文本
    imageurl图片 URL(建议 HTTPS)
    其他类型(video/audio/file 等)暂未在回写链路实现,发送会触发 unsupported msg type 错误。

    3.4 响应#

    {
      "code": 0,
      "msg": "success",
      "data": { "task_id": "a1b2c3..." }
    }
    code含义
    0成功(消息已入队,异步发送)
    2AUTH_ERROR:鉴权失败
    3PARAMS_ERROR:参数错误
    10018当前会话不存在,或已被非 AI 员工接待
    10019请求传入的 sys_user_id 与当前 AI 接待人不匹配
    500SERVER_ERROR:服务端异常(如入队失败)

    3.5 鉴权与接待人校验#

    鉴权#

    1.
    Authorization 头必须以 Bearer 开头
    2.
    提取 token,与该 sys_user_id 在平台配置的 access_token 通过 hash_equals 比对
    3.
    不通过返回 code=2, msg="Invalid Access Token"

    接待人匹配(重要)#

    sys_user_id 必须等于当前会话实际接待人。
    不一致时返回 code=10019,消息不会入队。
    强烈建议:在收到推送事件时记录其 current_assign_sys_user_id,回写时直接用同一个值,避免出现会话已转派但你仍在用旧 sys_user_id 的情况。

    3.6 幂等#

    同一 chat_user_id + request_id 组合在 5 分钟内视为重复请求
    重复请求会复用同一 task_id 返回 success,但不会重复入队
    业务方应保证每条独立消息的 request_id 唯一(建议格式:时间戳_业务前缀_随机)

    3.7 错误排查#

    现象排查方向
    永远返回 Invalid Access Token检查 token 是否与平台配置一致;header 是否真的有 Bearer 前缀(注意空格)
    返回 code=10019检查 sys_user_id 是否与当前会话接待人一致
    返回 Invalid request parameters检查 project_id、sys_user_id 是否 > 0
    返回 PARAMS_ERROR msg_list ...检查 msg_list 非空、每条含 msg_type 和 msg
    返回 SERVER_ERROR push send-message job ...平台异步队列异常,建议指数退避用同 request_id 重试

    4. 附录#

    A. 渠道枚举表#

    ID常量名含义
    1MESSENGERFacebook Messenger
    2CHAT_PLUGIN网站聊天插件
    3CHAT_EMAIL邮件
    4TELEGRAMTelegram 群组/频道
    5INSTAGRAMInstagram 私信
    6LINELINE
    7WHATSAPPWhatsApp 商业
    8FB_PAGE_COMMENTFacebook 主页评论
    10SLACKSlack
    11WORK_WEIXIN企业微信
    12INDIVIDUAL_WHATSAPPWhatsApp 个人号
    13INS_COMMENTInstagram 评论
    14WORK_WEIXIN_BOT企业微信群机器人
    15TELEGRAM_APPTelegram 个人号
    16TIKTOK_APPTikTok 个人号
    17TIKTOK_APP_COMMENTTikTok 个人号评论
    18VKONTAKTEVKontakte
    19ZALO_APPZalo 个人号
    20TIKTOK_BUSINESSTikTok 商业
    21TIKTOK_BUSINESS_COMMENTTikTok 商业号评论
    22YOUTUBEYouTube
    23WECHAT微信
    24LINE_APPLINE 个人号

    B. 错误码#

    code含义
    0SUCCESS
    2AUTH_ERROR
    3PARAMS_ERROR
    10018AI_EMPLOYEE_SYS_USER_ID_ERROR
    10019AI_EMPLOYEE_SYS_USER_ID_MISMATCHING_ERROR
    500SERVER_ERROR

    C. 端到端示例(最小可运行)#

    C.1 接收事件(Python/Flask 示例)#

    C.2 回写消息(Python 示例)#


    文档维护:实现细节如有调整,以代码与本文档版本号为准。
    修改于 2026-07-09 06:37:40
    Built with