慧企星助 开放平台文档

慧企星助 开放平台面向企业三方系统提供标准 HTTP API,支持员工、绑定关系、任务、标签、贡献点和附件上传能力。 所有接口默认只作用于当前 API Key 所属企业,权限由后端统一控制并在请求时强校验。

接入概览

开放平台使用 API Key + HMAC-SHA256 签名鉴权。请求必须携带标准请求头,部分接口还要求通过 X-Employee-Virtual-Id 明确当前访问员工。

基础规则

  • 所有接口根路径为 /api/openplatform
  • 所有返回体统一为 statusCodemsgdata 结构。
  • 接口只作用于当前 API Key 所属企业,不支持跨企业访问。
  • 权限项由后端统一返回并在请求时强校验,空权限不会默认放行。

统一员工识别规则

  • /employees 会为当前 API Key 下的每个企业成员实时返回唯一且稳定的 virtualId,不需要预先分配或额外落库。
  • 需要识别“当前访问用户/操作人/创建人”的接口,统一通过 X-Employee-Virtual-Id 传当前员工的 virtualId
  • 如果接口要求当前员工身份但未传该请求头,服务端会直接返回 403
  • 绑定接口用于建立第三方账号与当前 API Key 下员工 virtualId 的映射关系。
贡献单位统一说明:开放平台中的贡献单位统一为“点”。任务关联贡献和贡献点变更接口都使用“点”,不使用“分”。

鉴权签名

每次请求都必须携带以下请求头:

请求头 必填 说明
X-API-Key 企业后台 API Key 管理中生成的 Key。
X-Timestamp Unix 秒级时间戳,允许与服务端有 5 分钟内时钟偏差。
X-Nonce 每次请求唯一随机串,用于防重放。推荐直接使用 UUID/GUID 等高强度随机值,禁止使用固定前缀 + 秒级时间戳这类易重复方案。
X-Signature 按本文档规范拼接原文后,用 API Secret 做 HMAC-SHA256,结果转 16 进制小写。
X-Employee-Virtual-Id 按接口要求 当前访问员工的 virtualId。只有需要识别当前员工身份的接口才必须传。

签名原文格式

METHOD
PATH_LOWERCASE
QUERY_STRING
API_KEY
TIMESTAMP
NONCE
EMPLOYEE_VIRTUAL_ID
BODY
拼接规则:
  • METHOD 必须转为大写,例如 GETPOST
  • PATH 必须使用实际请求路径,并统一转为小写,例如 /api/openplatform/employees
  • QUERY_STRING 必须与实际请求 URL 完全一致;有查询串时必须包含前导 ?,没有时传空字符串。重要:如果查询参数包含中文或特殊字符,必须先进行 URL 编码(例如 Uri.EscapeDataStringencodeURIComponent),签名原文中的查询串必须与实际发送的 URL 中的查询串完全一致。
  • 如果本次请求带了 X-Employee-Virtual-Id,则 EMPLOYEE_VIRTUAL_ID 必须传该请求头的原始值;没有该请求头时传空字符串。
  • BODY 必须与实际发送的请求体完全一致;GET 请求 body 为空字符串;multipart/form-data 上传附件时固定传 [multipart/form-data]
  • 签名原文内部统一使用 \n 作为换行符,不使用 \r\n
  • X-Nonce 必须为每次 HTTP 请求重新生成的唯一随机串;同一个 API Key 下,已通过鉴权的 X-Nonce 不可再次使用。
  • 如果客户端需要重试请求,必须同时重新生成 X-TimestampX-NonceX-Signature,禁止复用上一次请求头。
防重放说明:
  • 开放平台会按 API Key + X-Nonce 记录已通过鉴权的请求,防止请求被重复使用。
  • 同一个 API Key 下,只要请求仍处于 5 分钟有效时间窗内,重复使用同一个 X-Nonce 就会被判定为重放请求。
  • 无论业务处理最终成功还是失败,只要客户端再次发起 HTTP 请求,都必须视为一次全新的签名请求。
  • 如果重复使用同一个 X-Nonce,服务端会直接返回 401,错误信息为“请求已被重复使用”。
  • X-Nonce 只用于请求防重放,不是业务幂等键。若三方需要“安全重试但不能重复创建业务数据”,请在业务参数里自行携带独立的幂等标识。
请求体兼容性说明:
  • 开放平台网关会尽量兼容三方常见的弱类型 JSON 传参,例如把数字传成数字字符串、把布尔值传成 "true"/"false""1"/"0"
  • 可选字段没有值时,推荐直接省略字段,或显式传 null;不要依赖空字符串 "" 表示“空”。当前仅对少量高频场景做了兼容,非法值仍会按参数错误处理。
  • 为保证联调稳定,三方仍应优先按字段声明的标准 JSON 类型传值,不要把所有字段统一转成字符串。

签名示例(GET - 无查询参数)

GET
/api/openplatform/labels

sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
1718515200
f4f7ec0b3d574c27a5d1c32f5d4d6e90
emp_T7dQ2mYk8rLp4cN1sVx3bH9wAe6fJuKz

签名示例(GET - 带中文查询参数)

GET
/api/openplatform/employees
?page=1&pageSize=100&keyword=%E5%BC%A0%E6%96%87%E6%B6%9B
sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
1718515200
f4f7ec0b3d574c27a5d1c32f5d4d6e90
emp_T7dQ2mYk8rLp4cN1sVx3bH9wAe6fJuKz
URL 编码注意事项:
  • 如果查询参数包含中文、空格、特殊符号(如 &=),必须先进行 URL 编码,再参与签名计算。
  • C# 使用 Uri.EscapeDataString("张文涛"),编码结果为 %E5%BC%A0%E6%96%87%E6%B6%9B
  • JavaScript 使用 encodeURIComponent("张文涛"),编码结果相同。
  • 签名原文中的查询串必须与实际发送的 URL 中的查询串完全一致,否则服务端会返回 401 签名校验失败。
  • RestSharp 的 AddQueryParameter 方法会自动进行 URL 编码,签名时应使用编码后的查询串。

签名示例(POST + JSON Body)

POST
/api/openplatform/tasks

sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
1718515200
f4f7ec0b3d574c27a5d1c32f5d4d6e90
emp_T7dQ2mYk8rLp4cN1sVx3bH9wAe6fJuKz
{"title":"完成季度复盘","assigneeVirtualIds":["emp_T7dQ2mYk8rLp4cN1sVx3bH9wAe6fJuKz"],"closingTime":"2026-06-18T00:00:00+08:00"}

签名示例(POST + multipart/form-data)

POST
/api/openplatform/attachments/upload

sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
1718515200
f4f7ec0b3d574c27a5d1c32f5d4d6e90
emp_T7dQ2mYk8rLp4cN1sVx3bH9wAe6fJuKz
[multipart/form-data]
常见签名错误:
  • GET 请求签名时漏掉 ? 前缀。
  • 签名使用的 QueryString 参数顺序与实际 URL 不一致。
  • 查询参数包含中文但未进行 URL 编码,导致签名原文与实际发送的 URL 不一致。
  • 使用 HTTP 客户端库(如 RestSharp、axios)时,客户端自动编码了查询参数,但签名时使用了未编码的原始值。
  • 请求头里传了 X-Employee-Virtual-Id,但签名原文里的 EMPLOYEE_VIRTUAL_ID 仍然留空,或值不一致。
  • 附件上传签名时误把二进制文件正文参与签名,而不是固定占位 [multipart/form-data]
  • POST 请求签名时 JSON 被格式化过,而实际发送时又重新序列化了一次。
  • 签名时使用了毫秒级时间戳,或者用了大写十六进制签名串。
  • 请求失败后直接复用上一次的 X-TimestampX-NonceX-Signature 重试,导致被判定为重复请求。
  • 客户端并发发送多个请求时错误复用了同一个 X-Nonce

权限说明

当前 API Key 的权限配置只接受字符串数组 JSON,例如 ["employees.read","tasks.write"]。对象结构或空权限都不会被放行。

bindings.read bindings.write employees.read labels.read tasks.read tasks.write scores.read scores.write scoreApplies.read scoreApplies.write attachments.write
权限值 名称 说明
bindings.read 读取绑定关系 允许查询当前 API Key 下的第三方账号绑定列表和绑定详情。
bindings.write 管理绑定关系 允许创建、更新和解绑当前 API Key 下的第三方账号绑定关系。
employees.read 读取员工 允许查询当前企业员工列表和员工详情。
labels.read 读取标签 允许按当前访问员工身份查询当前企业可见标签。
tasks.read 读取任务 允许查询当前企业任务列表和任务详情。
tasks.write 创建任务 允许在当前企业创建任务。
scores.read 读取贡献点 允许查询员工当前贡献点信息。
scores.write 变更贡献点 允许提交贡献点增加或扣减请求。
scoreApplies.read 读取贡献申请 允许查询贡献申请列表和详情。
scoreApplies.write 提交贡献申请 允许提交贡献申请。
attachments.write 上传附件 允许上传任务附件。

员工接口

员工接口用于查询当前企业员工及其开放平台映射信息。返回手机号已脱敏。

GET /api/openplatform/employees

查询当前企业员工分页列表。

查询参数

参数类型必填说明
pageint页码,默认 1。
pageSizeint每页条数,默认 20,最大 100。
keywordstring按员工姓名或拼音模糊查询。

响应示例

{
  "statusCode": 100,
  "msg": "获取成功",
  "data": {
    "total": 1,
    "rows": [
      {
        "virtualId": "emp_T7dQ2mYk8rLp4cN1sVx3bH9wAe6fJuKz",
        "name": "张三",
        "phone": "138****5678",
        "departmentName": "运营部",
        "positionName": "运营经理",
        "isBound": true
      }
    ]
  }
}
字段说明:virtualId 在当前企业 + 当前 API Key 维度唯一且稳定,由平台按算法实时生成;重置 ApiSecret 不会改变同一员工在当前 API Key 下的 virtualIdisBound 表示当前 API Key 下是否已存在第三方账号绑定关系。
GET /api/openplatform/employees/{virtualId}

virtualId 查询员工详情。

响应示例

{
  "statusCode": 100,
  "msg": "获取成功",
  "data": {
    "virtualId": "emp_T7dQ2mYk8rLp4cN1sVx3bH9wAe6fJuKz",
    "name": "张三",
    "phone": "138****5678",
    "departmentName": "运营部",
    "positionName": "运营经理",
    "isBound": true
  }
}

绑定接口

绑定接口是正式公开 API,用于维护第三方账号与当前 API Key 下员工 virtualId 的映射关系。

GET /api/openplatform/bindings

查询当前 API Key 下的绑定列表。

参数类型必填说明
pageint页码,默认 1。
pageSizeint每页条数,默认 20,最大 100。
{
  "statusCode": 100,
  "msg": "获取成功",
  "data": {
    "total": 1,
    "rows": [
      {
        "id": "7e6c92f1-6a34-4f5c-8bcf-faf6db5132a8",
        "thirdPartyUserId": "u_10001",
        "thirdPartyUserName": "张三-外部账号",
        "employeeVirtualId": "emp_T7dQ2mYk8rLp4cN1sVx3bH9wAe6fJuKz",
        "createTime": "2026-06-17T16:00:00+08:00",
        "updateTime": "2026-06-17T16:00:00+08:00"
      }
    ]
  }
}
GET /api/openplatform/bindings/{id}

查询单个绑定详情,返回结构与绑定列表中的单条记录一致。

POST /api/openplatform/bindings

新增或更新绑定关系。

参数类型必填说明
thirdPartyUserIdstring第三方系统用户唯一标识。
thirdPartyUserNamestring第三方系统用户名。
employeeVirtualIdstring当前 API Key 下员工的 virtualId
{
  "thirdPartyUserId": "u_10001",
  "thirdPartyUserName": "张三-外部账号",
  "employeeVirtualId": "emp_T7dQ2mYk8rLp4cN1sVx3bH9wAe6fJuKz"
}
兼容性提示:thirdPartyUserName 为空时建议直接省略或传 null;必填字段 thirdPartyUserIdemployeeVirtualId 仍必须传有效字符串。
DELETE /api/openplatform/bindings?thirdPartyUserId=u_10001

按第三方用户 ID 解绑。

{
  "statusCode": 100,
  "msg": "解绑成功",
  "data": null
}

任务接口

任务接口支持列表、详情和创建。创建任务时必须通过 X-Employee-Virtual-Id 统一指定当前创建人。

当前员工要求:创建任务时如果未提供 X-Employee-Virtual-Id,会直接返回 403,错误信息为“请通过 X-Employee-Virtual-Id 指定当前企业下的创建人”。
GET /api/openplatform/tasks

查询任务列表。

必填请求头:必须提供 X-Employee-Virtual-Id。未传时返回 403,错误信息为"请通过 X-Employee-Virtual-Id 指定当前访问用户"。
参数类型必填说明
pageint页码,默认 1。
pageSizeint每页条数,默认 20,最大 100。
statusint任务状态过滤。
keywordstring任务标题关键字。
{
  "statusCode": 100,
  "msg": "获取成功",
  "data": {
    "total": 1,
    "rows": [
      {
        "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        "title": "完成季度复盘",
        "assigneeVirtualId": "emp_T7dQ2mYk8rLp4cN1sVx3bH9wAe6fJuKz",
        "dueDate": "2026-06-19T00:00:00+08:00",
        "priority": 3,
        "status": 2,
        "createTime": "2026-06-17T18:40:00+08:00"
      }
    ]
  }
}
GET /api/openplatform/tasks/{id}

查询任务详情。

必填请求头:必须提供 X-Employee-Virtual-Id。未传时返回 403,错误信息为"请通过 X-Employee-Virtual-Id 指定当前访问用户"。
{
  "statusCode": 100,
  "msg": "获取成功",
  "data": {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "title": "完成季度复盘",
    "contents": "

整理经营数据并输出总结

", "assigneeVirtualId": "emp_T7dQ2mYk8rLp4cN1sVx3bH9wAe6fJuKz", "dueDate": "2026-06-18T00:00:00+08:00", "priority": 3, "status": 2, "createTime": "2026-06-17T16:00:00+08:00", "apiKeyName": "我的三方应用" } }
字段说明:apiKeyName 表示创建该任务的三方应用名称,非开放平台创建的任务该字段为空字符串。
POST /api/openplatform/tasks

创建任务。

参数类型必填说明
titlestring任务标题。
contentsstring编码后的富文本内容。请按 URL 编码口径提交;开放平台接收后会先做 URL 解码,再做 HTML 解码,最终按原始富文本存储。
assigneeVirtualIdsstring[]条件必填负责人 virtualId 列表。正式发送任务时至少 1 个;保存草稿时可不传。
checkerVirtualIdstring考核人 virtualId
ccVirtualIdsstring[]抄送人 virtualId 列表。
priorityint优先级,默认 3。
closingTimestring条件必填截止时间。正式发送任务时必填;保存草稿时可不传。传值时必须显式带时区信息,例如 2026-06-18T00:00:00+08:002026-06-17T16:00:00Z
scoredecimal关联贡献点,单位为“点”。
labelIdArrguid[]标签 ID 列表。
planIdguid所属项目 ID。不传时请直接省略该字段,或显式传 null;不要传空字符串 ""
isDraftbool是否保存草稿。
sendTimestring发送时间,ISO 8601 标准时间字符串,且必须显式带时区信息,例如 2026-06-17T19:00:00+08:002026-06-17T11:00:00Z
completeAttachmentbool完成任务时是否必须上传附件。
checkItemsstring[]检查项列表。
attachmentUrlsstring[]已上传附件 URL 列表。
{
  "title": "完成季度复盘",
  "contents": "%3Cp%3E%E6%95%B4%E7%90%86%E7%BB%8F%E8%90%A5%E6%95%B0%E6%8D%AE%E5%B9%B6%E8%BE%93%E5%87%BA%3Cstrong%3E%E6%80%BB%E7%BB%93%3C%2Fstrong%3E%3C%2Fp%3E",
  "assigneeVirtualIds": ["emp_T7dQ2mYk8rLp4cN1sVx3bH9wAe6fJuKz"],
  "priority": 3,
  "closingTime": "2026-06-18T00:00:00+08:00",
  "score": 5
}
富文本约定:contents 必须传已做 URL 编码的富文本字符串,例如先把 <p>...</p> 执行 encodeURIComponent 后再提交。开放平台会先做 URL 解码,再补做 HTML 解码,最终按富文本原文存储。
请求体约定:可选的 guid 字段(如 planId)如果没有值,请直接省略或传 null;不要传空字符串 ""closingTimesendTime 传值时必须使用带时区信息的 ISO 8601 标准时间字符串,例如 2026-06-18T00:00:00+08:002026-06-17T16:00:00Z;不接受没有时区的裸时间字符串。scoreisDraftcompleteAttachment 建议按标准 JSON 数字/布尔值传递,不要全部转成字符串。
草稿规则:isDraft=true 时,当前开放平台只强制要求 titleassigneeVirtualIdsclosingTimecheckerVirtualIdccVirtualIdsscorelabelIdArrplanIdsendTimecompleteAttachmentcheckItemsattachmentUrls 都可省略。正式发送任务时,仍至少需要负责人和截止时间。
{
  "statusCode": 100,
  "msg": "创建成功",
  "data": {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "title": "完成季度复盘",
    "createTime": "2026-06-17T16:00:00+08:00"
  }
}
兼容性提示:score 支持按数字提交,也兼容数字字符串;但仍建议三方按标准 JSON 数字传值,避免不同语言序列化差异。
DELETE /api/openplatform/tasks/{id}

撤销任务。只有任务创建人才能撤销,且任务状态必须为进行中、待开始、暂停、待审批、草稿、拒收、新任务、审批不通过、转发中、挂起申请之一。

必填请求头:必须提供 X-Employee-Virtual-Id。未传时返回 403
DELETE /api/openplatform/tasks/a1b2c3d4-e5f6-7890-abcd-ef1234567890
Host: your-domain.com
Content-Type: application/json
X-Employee-Virtual-Id: emp_T7dQ2mYk8rLp4cN1sVx3bH9wAe6fJuKz

路径参数:

参数类型必填说明
idguid任务 ID。
{
  "statusCode": 100,
  "msg": "撤销成功"
}
注意事项:撤销任务是不可逆操作,请谨慎调用。如果任务有子任务,必须先撤销所有子任务。撤销成功后会触发 task.canceled Webhook 事件。

Webhook 事件通知

开放平台支持通过 Webhook 向三方应用主动推送任务事件通知。在 API Key 管理中配置回调地址和订阅的事件类型后,当相关任务发生状态变更时,开放平台会异步发送 HTTP POST 请求到指定的回调地址。

配置入口:企业管理后台 → 开放平台 → API Key 管理 → 编辑 API Key → 填写“三方事件回调地址”并选择需要订阅的事件类型。

事件类型

事件类型分类子分类触发时机
task.created任务类创建与发送任务创建成功(含草稿)。
task.sent任务类创建与发送任务发送。
task.awaitStart任务类创建与发送任务待开始。
task.received任务类执行流程任务接收。
task.refused任务类执行流程任务被拒收。
task.executing任务类执行流程任务执行中。
task.submitted任务类执行流程任务提交完成。
task.completed任务类执行流程任务已完成。
task.audited任务类审核与审批完成审核通过。
task.auditRejected任务类审核与审批完成审核不通过。
task.awaitingApproval任务类审核与审批待审批。
task.approved任务类审核与审批审批通过。
task.approvalRejected任务类审核与审批审批不通过。
task.changed任务类审核与审批任务变更待确认。
task.paused任务类挂起与暂停任务已暂停。
task.hangApply任务类挂起与暂停挂起申请。
task.hangFiringApply任务类挂起与暂停申请挂起启动。
task.suspended任务类挂起与暂停任务已挂起。
task.forwarding任务类转发与申诉转发中。
task.relayRefused任务类转发与申诉转发拒收。
task.relayAwaitingApproval任务类转发与申诉转发任务待审批。
task.relayApprovalRejected任务类转发与申诉转发任务审批不通过。
task.rejected任务类特殊流程完成任务被申诉。
task.canceled任务类特殊流程任务撤销申请。
task.deleted任务类删除任务删除。
score_apply.created贡献类-贡献申请创建成功。
score_apply.approved贡献类-贡献申请审批通过。
score_apply.rejected贡献类-贡献申请审批不通过。
score_apply.complained贡献类-贡献申请被申诉。
score_apply.confirmed贡献类-贡献申请被确认。
common.accountUnbound通用类-三方账号解绑。
任务类事件范围:任务类事件只会推送与当前 API Key 相关的任务(通过该 API Key 创建的任务)。
贡献类事件范围:贡献类事件只会推送与当前 API Key 相关的贡献申请(通过该 API Key 提交的申请)。

查询支持的事件类型

三方应用可以通过接口动态获取开放平台支持的全部事件类型,用于构建事件订阅 UI 或验证配置:

GET /api/openplatform/tasks/webhook-event-types

权限要求:需要有效的 API Key 鉴权(X-API-Key、X-Timestamp、X-Nonce、X-Signature)。

请求示例

GET /api/openplatform/tasks/webhook-event-types HTTP/1.1
Host: your-openplatform-domain.com
X-API-Key: your-api-key-here
X-Timestamp: 1718620800
X-Nonce: abc123def456
X-Signature: hmac-sha256-signature-here

响应示例

{
  "statusCode": 100,
  "msg": "获取成功",
  "data": [
    {
      "value": "task.created",
      "label": "任务创建",
      "description": "通过开放平台 API 创建任务时触发。",
      "category": "task"
    },
    {
      "value": "task.sent",
      "label": "任务下发",
      "description": "任务下发给执行人时触发。",
      "category": "task"
    },
    {
      "value": "task.received",
      "label": "任务接收",
      "description": "执行人接收任务时触发。",
      "category": "task"
    },
    {
      "value": "task.executing",
      "label": "任务开始执行",
      "description": "执行人开始执行任务时触发。",
      "category": "task"
    },
    {
      "value": "task.paused",
      "label": "任务暂停",
      "description": "任务被暂停时触发。",
      "category": "task"
    },
    {
      "value": "task.suspended",
      "label": "任务挂起",
      "description": "任务被挂起时触发。",
      "category": "task"
    },
    {
      "value": "task.deleted",
      "label": "任务删除",
      "description": "任务被删除时触发。",
      "category": "task"
    },
    {
      "value": "task.submitted",
      "label": "任务提交",
      "description": "执行人完成任务并提交时触发。",
      "category": "task"
    },
    {
      "value": "task.approved",
      "label": "任务审核通过",
      "description": "任务审核人通过任务时触发。",
      "category": "task"
    },
    {
      "value": "task.rejected",
      "label": "任务审核不通过",
      "description": "任务审核人不通过任务时触发。",
      "category": "task"
    },
    {
      "value": "score_apply.created",
      "label": "贡献申请创建成功",
      "description": "通过开放平台提交贡献申请成功后触发。",
      "category": "score"
    },
    {
      "value": "score_apply.approved",
      "label": "贡献申请审批通过",
      "description": "贡献申请审批通过时触发。",
      "category": "score"
    },
    {
      "value": "score_apply.rejected",
      "label": "贡献申请审批不通过",
      "description": "贡献申请审批不通过时触发。",
      "category": "score"
    },
    {
      "value": "score_apply.complained",
      "label": "贡献申请申诉",
      "description": "贡献申请被申诉时触发。",
      "category": "score"
    },
    {
      "value": "score_apply.confirmed",
      "label": "贡献申请确认",
      "description": "贡献申请被确认时触发。",
      "category": "score"
    },
    {
      "value": "common.accountUnbound",
      "label": "账号解绑",
      "description": "三方账号与员工解绑时触发。",
      "category": "common"
    }
  ]
}

响应字段说明

字段类型说明
statusCodeint状态码,100 表示成功。
msgstring响应消息。
dataarray事件类型列表。
data[].valuestring事件类型标识符,用于订阅配置。
data[].labelstring事件类型的中文名称。
data[].descriptionstring事件触发时机的详细说明。
data[].categorystring事件分类:task(任务类)、score(贡献类)或 common(通用类)。
使用场景:建议在 API Key 配置页面调用此接口,动态渲染事件类型多选框,避免硬编码事件列表。

事件 Data 字段详解

不同事件类型会在 data 字段中返回不同的业务数据,三方应用应根据 eventType 解析对应字段:

1. 任务类事件

task.created - 任务创建

字段类型说明
taskIdstring (UUID)任务唯一标识符。
titlestring任务标题。
createTimestring任务创建时间(ISO 8601 格式)。
{
  "eventType": "task.created",
  "timestamp": "1718620800",
  "data": {
    "taskId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "title": "完成季度复盘",
    "createTime": "2026-06-17T16:00:00"
  }
}

task.sent / task.received / task.executing / task.paused / task.suspended / task.deleted / task.submitted / task.approved / task.rejected - 任务状态变更

字段类型说明
taskIdstring (UUID)任务唯一标识符。
eventTypestring事件类型标识,与外层 eventType 一致。
建议操作:接收到任务状态变更事件后,三方可调用 GET /api/openplatform/tasks/{taskId} 接口获取任务完整详情(包括状态、执行人、进度、附件等)。
{
  "eventType": "task.submitted",
  "timestamp": "1718624400",
  "data": {
    "taskId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "eventType": "task.submitted"
  }
}

2. 贡献类事件

score_apply.created - 贡献申请创建

字段类型说明
applyIdstring (UUID)贡献申请唯一标识符。
applyTypeint申请类型(具体类型值需参考贡献模块文档)。
scoredecimal申请贡献点数量。
isAnonymousbool是否匿名申请。
createTimestring申请创建时间(ISO 8601 格式)。
{
  "eventType": "score_apply.created",
  "timestamp": "1718628000",
  "data": {
    "applyId": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
    "applyType": 1,
    "score": 5.0,
    "isAnonymous": false,
    "createTime": "2026-06-17T17:00:00"
  }
}

score_apply.approved / score_apply.rejected / score_apply.confirmed / score_apply.complained - 贡献申请状态变更

字段类型说明
applyIdstring (UUID)贡献申请唯一标识符。
statusCodeint业务状态码(100 表示成功)。
msgstring状态变更说明信息(如审批意见)。
建议操作:接收到贡献申请状态变更事件后,三方可调用贡献申请详情接口获取完整信息(包括审批人、审批时间、贡献点变更记录等)。
{
  "eventType": "score_apply.approved",
  "timestamp": "1718631600",
  "data": {
    "applyId": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
    "statusCode": 100,
    "msg": "审批通过"
  }
}
说明:score_apply.rejectedscore_apply.confirmedscore_apply.complaineddata 字段结构与上例一致,均返回 applyIdstatusCodemsg

3. 通用类事件

common.accountUnbound - 三方账号解绑

字段类型说明
apiKeyIdstring (UUID)API Key 唯一标识符。
thirdPartyUserIdstring三方系统的用户唯一标识。
employeeVirtualIdstring慧企星助平台员工虚拟 ID(解绑后该员工将无法再通过三方身份访问)。
eventTypestring事件类型标识,固定为 "common.accountUnbound"
处理建议:接收到解绑事件后,三方应用应:
  • 立即失效该 thirdPartyUserId 对应的访问令牌或会话。
  • 清除三方系统中与该员工相关的缓存数据。
  • 如三方系统需要,可记录解绑时间用于审计。
  • 该员工下次尝试通过三方登录时,应引导其重新授权绑定。
{
  "eventType": "common.accountUnbound",
  "timestamp": "1718635200",
  "data": {
    "apiKeyId": "c3d4e5f6-a7b8-9012-cdef-a12345678901",
    "thirdPartyUserId": "third_party_user_12345",
    "employeeVirtualId": "emp_T7dQ2mYk8rLp4cN1sVx3bH9wAe6fJuKz",
    "eventType": "common.accountUnbound"
  }
}

回调请求格式

开放平台会以 HTTP POST 方式向配置的回调地址发送 JSON 数据:

参数类型说明
eventTypestring事件类型,如 task.created
timestampstringWebhook 发送时的 Unix 秒级时间戳字符串,例如 "1718620800";该值同时用于签名验证与防重放校验。
dataobject事件详细数据(由具体事件类型决定,见上方"事件 Data 字段详解")。

签名验证

每个 Webhook 请求都会在 HTTP Header 中携带签名,三方应用应验证签名以确保请求来源可信:

Header 名称说明
X-Webhook-SignatureHMAC-SHA256 签名值(十六进制字符串)。
X-Webhook-Timestamp与请求体中的 timestamp 一致,值为 Unix 秒级时间戳字符串。

签名算法:

signature = HMAC-SHA256(
  key = webhookSecret,
  message = timestamp + "\n" + requestBodyJson
)
验签规则:
  • 签名原文只包含 timestamp、换行符 \n 和完整请求体 JSON,不拼接 eventType、URL 或其他 Header。
  • 验签时必须使用接收到的原始请求体字符串,不能先反序列化再重新序列化,否则字段顺序、空格或转义差异会导致签名不一致。
  • 建议按 UTC 校验时间戳有效期,例如与 DateTime.UtcNow 比较,并控制在 5 分钟误差窗口内。
安全提示:webhookSecret 由后端在配置 Webhook 回调地址时自动生成(256 位随机字符串,使用 RNGCryptoServiceProvider 密码学安全随机数生成器),用户可随时点击"重新生成密钥"按钮重新生成。密钥仅在配置成功时返回给前端展示,不会在网络传输中暴露。接收到 Webhook 请求后,务必先验证签名,再处理业务逻辑。

重试机制

开放平台会对 Webhook 投递失败进行自动重试,最多重试 3 次:

  • 第 1 次重试:失败后 1 分钟
  • 第 2 次重试:失败后 5 分钟
  • 第 3 次重试:失败后 30 分钟

如果 3 次重试后仍然失败,该事件将标记为投递失败,可在日志中查看详细信息。

最佳实践:三方应用接收到 Webhook 请求后,应尽快返回成功结果,复杂业务逻辑请异步处理,避免超时导致重试。若已接收成功,建议返回 HTTP 200 且响应体 {"statusCode":100,"msg":"success"};若验签失败、参数非法或业务未接收成功,应返回非成功 HTTP 状态码,或在响应体中返回非 100statusCode,开放平台会按失败处理并进入重试。

标签接口

标签接口会按当前访问员工身份返回可见标签列表,因此必须传 X-Employee-Virtual-Id

GET /api/openplatform/labels

获取当前企业可用标签列表。

必填请求头:必须提供 X-Employee-Virtual-Id。未传时返回 403
{
  "statusCode": 100,
  "msg": "获取成功",
  "data": [
    {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "name": "紧急",
      "color": "#ff4d4f",
      "groupName": "优先级"
    },
    {
      "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
      "name": "我的标签",
      "color": "#1890ff",
      "groupName": null
    }
  ]
}

贡献点接口

贡献点接口的单位统一为“点”。增加、扣减贡献点时都必须通过 X-Employee-Virtual-Id 指定当前操作人。

POST /api/openplatform/scores/add

增加贡献点。

参数类型必填说明
employeeVirtualIdstring目标员工 virtualId
scoredecimal增加的贡献点数量,传正数。
reasonstring变更原因。
typeIdstring业务类型 ID。
{
  "statusCode": 100,
  "msg": "贡献变更请求已提交",
  "data": {
    "queueId": "6fbb6f6d-4fa0-4fd3-a87c-fdf691c2a260",
    "employeeVirtualId": "emp_T7dQ2mYk8rLp4cN1sVx3bH9wAe6fJuKz",
    "score": 5,
    "reason": "季度激励",
    "acceptedTime": "2026-06-17T16:00:00+08:00"
  }
}
POST /api/openplatform/scores/subtract

扣减贡献点。score 传正数即可,服务端会按扣减语义处理,返回结构与增加贡献点一致。

GET /api/openplatform/scores/{employeeVirtualId}

查询员工贡献点。

{
  "statusCode": 100,
  "msg": "获取成功",
  "data": {
    "employeeVirtualId": "emp_T7dQ2mYk8rLp4cN1sVx3bH9wAe6fJuKz",
    "score": 5,
    "reason": "季度激励",
    "createTime": "2026-06-17T16:00:00+08:00"
  }
}

贡献申请接口

贡献申请接口用于三方系统提交贡献申请、查询行为标准、获取申请详情等。所有接口都必须通过 X-Employee-Virtual-Id 指定当前操作人。

三方标识说明:通过开放平台创建的贡献申请,在查询详情时会返回 apiKeyIdapiKeyName 字段,用于标识该申请来源于哪个三方应用。
GET /api/openplatform/scoreApplies/init

获取贡献申请初始化参数,包括是否允许匿名申请、自定义申请的分值上下限等。

{
  "statusCode": 100,
  "msg": "获取成功",
  "data": {
    "allowAnonymous": true,
    "minScore": 1,
    "maxScore": 100
  }
}
GET /api/openplatform/scoreApplies/standards

获取行为标准列表(分页),支持按关键字搜索。

参数类型必填说明
pageint页码,默认 1。
pageSizeint每页条数,默认 20。
keywordstring行为标准名称关键字。
{
  "statusCode": 100,
  "msg": "获取成功",
  "data": {
    "total": 10,
    "rows": [
      {
        "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        "name": "优秀代码贡献",
        "description": "对项目有显著贡献的代码提交",
        "score": 10,
        "category": "技术贡献"
      }
    ]
  }
}
POST /api/openplatform/scoreApplies

提交贡献申请,支持自定义申请和行为标准申请两种类型。

参数类型必填说明
applyTypeint申请类型,0=行为标准申请,1=自定义申请。
targetEmployeeVirtualIdsstring[]目标员工 virtualId 列表。
scoredecimal申请分值(自定义申请时必填)。
reasonstring申请理由。
attachsstring[]附件 URL 列表。
isAnonymousbool是否匿名申请。
standardListobject[]行为标准申请项列表(行为标准申请时必填)。
standardList 项结构
参数类型必填说明
standardItemIdstring行为标准项 ID (UUID)。
scoredecimal申请分值。
reasonstring申请理由。
attachsstring[]附件 URL 列表。
{
  "statusCode": 100,
  "msg": "申请已提交",
  "data": {
    "applyId": "b34b6f3f-f84e-45ce-8c44-bb85d55a9ef5",
    "message": "申请已提交"
  }
}
GET /api/openplatform/scoreApplies/{applyId}

获取贡献申请详情。

{
  "statusCode": 100,
  "msg": "获取成功",
  "data": {
    "applyId": "b34b6f3f-f84e-45ce-8c44-bb85d55a9ef5",
    "status": 1,
    "applyType": 1,
    "apiKeyId": "c56d7f8g-h90i-1234-jklm-no5678901234",
    "apiKeyName": "我的三方应用",
    "score": 10,
    "reason": "优秀代码贡献",
    "attachs": [],
    "isAnonymous": false,
    "createTime": "2026-06-18T10:00:00+08:00"
  }
}

附件接口

附件上传接口必须通过 X-Employee-Virtual-Id 指定当前操作人,上传后可把返回 URL 回填到任务创建请求的 attachmentUrls

POST /api/openplatform/attachments/upload

上传附件,表单字段名固定为 file

必填请求头:必须提供 X-Employee-Virtual-Id。未传时返回 403
{
  "statusCode": 100,
  "msg": "上传成功",
  "data": {
    "url": "https://cdn.example.com/task/20260617/demo.pdf",
    "fileName": "demo.pdf",
    "fileSize": 204800,
    "id": "b34b6f3f-f84e-45ce-8c44-bb85d55a9ef5"
  }
}

错误码与排查

HTTP 状态statusCode说明
400400 / 101请求参数错误,例如标题为空、附件为空、virtualId 无效等。
40140101缺少认证请求头。
40140102API Key 无效。
40140103时间戳格式错误。
40140104请求已过期。
40140105签名校验失败。
40140106Nonce 重复,或请求被重复使用。
40340301API Key 已停用。
40340302API Key 已过期。
40340303IP 不在白名单中。
40340304操作人不属于当前企业,或当前员工上下文无效。
403403权限不足,或缺少 X-Employee-Virtual-Id,或当前 API Key 未授权指定能力。
404404员工、任务、绑定关系等资源不存在。
502502 及其他大于 100 的状态码开放平台网关调用下游内部服务失败,或下游返回结构异常。
500500系统异常。
状态码约定:HTTP 状态码 用于表示错误大类(如 401 认证失败、403 授权失败),statusCode 用于表示更细粒度、可供程序稳定判断的机器错误码;两者不要求一一对应。
日志说明:开放平台请求日志会记录请求体和响应体,日志中的手机号、姓名、各种业务 Id、virtualId、第三方用户标识等敏感字段都会做脱敏处理。GET 请求会把查询串按 [query]?... 形式写入 RequestBody,并按字段名统一脱敏。

常见排查项

  • 确认 API Key 已启用、未过期,且命中白名单。
  • 确认签名原文中的路径、QueryString、Body 与真实请求完全一致。
  • 确认每次请求都重新生成 X-TimestampX-NonceX-Signature,不要在重试或并发请求中复用旧请求头。
  • 确认需要当前员工身份的接口都传了 X-Employee-Virtual-Id
  • 确认被引用的员工 virtualId 来自当前 API Key 下的 /employees 返回结果。