注意:说明:
二、步骤一:第三方服务开发
按照下文中的 接口规范,开发第三方服务。
三、步骤二:启用第三方集成
进入企业控制台 <企业id>.copilot.qq.com/admin,选择开放与集成 > 组织架构同步,单击任意第三方系统;
根据页面提示,输入上游系统名称、服务域名、token 信息;
配置关联规则,支持根据用户 ID、邮箱、手机号匹配,选择完成后提交即可。
四、步骤三:效果验证
配置完成,在开放与集成 > 组织架构同步页面,可以看到从第三方服务获取到的组织架构和人员信息。能查看到即代表获取成功,单击手动关联,系统会将该成员从第三方服务中同步至 CodeBuddy;
六、概述
custom provider 通过 HTTP 代理对接外部组织架构服务。组织服务需要实现一组固定的 REST 接口,返回符合约定的数据结构。
七、接入流程
1. 部署自定义组织服务,实现这篇所列 API。
2. 配置组织服务访问参数(BaseURL、AuthToken、EnterpriseID 等)。
3. 使用 /org/health 校验可用性。
八、配置项(custom)
{ "name": "custom-org", "base_url": "https://example.com", "enterprise_id": "ent-xxx", "timeout_seconds": 15, "auth_header": "Authorization", "auth_token": "token-value", "bearer_token": true, "extra_headers": { "X-From": "org-service" }, "account_id_header": "X-Account-Id", "account_id_query": "account_id", "success_code": 0, "config_header": "X-Custom-Config"}
字段说明:
·name:接口名。
·base_url:必填,自定义组织服务的根地址。
·enterprise_id:默认会作为 enterprise_id 查询参数附加。
·timeout_seconds:请求超时,默认 15 秒。
·auth_token:鉴权 token,发送 Authorization: Bearer <token>。
·auth_header / bearer_token:当前实现未生效,仅用于日志。
·extra_headers:会附加到所有请求。
·account_id_header:如果设置,会将 AccountID 放入该请求头。
·account_id_query:如果设置,会将 AccountID 作为该 query 参数。
·success_code:响应包装 code 成功值,默认 0。
·config_header:默认 X-Custom-Config,值为 base64(json(config))。
九、请求公共规则
·请求头
·Authorization: Bearer <auth_token>(auth_token 非空时)
·X-Custom-Config: <base64(config-json)>(配置完整 JSON 编码)
·extra_headers 中所有键值
·若配置了 account_id_header 且本次请求有 AccountID,则附加该头
·查询参数拼装
·布尔值:仅当 true 才追加
·整数值:仅当 > 0 才追加
·字符串:trim 后非空才追加
·切片:逗号拼接
·默认追加 enterprise_id(若未显式提供)
·路径参数
·node_id / user_id 使用 url.PathEscape 转义
·响应格式
·支持两种格式:
·直接返回目标结构 JSON
·包装结构:
{ "code": 0, "message": "ok", "data": { … } }
·code 必须等于 success_code(默认 0)
十、数据结构(JSON)
组织节点(OrgNode)字段说明(Swagger 类型):
·id(string):节点唯一标识
·name(string):节点名称
·display_name(string):展示名称
·parent_id(string):父节点 ID
·full_path(string):节点完整路径
·has_child(boolean):是否有子节点
·member_count(integer):成员数量(可选)
·user_count(integer):已登录系统的用户数量(可选)
·order(integer):排序权重(可选)
·attributes(object<string,string>):自定义属性(键值对)
·external_data(object):扩展数据(任意 JSON)
组织节点(OrgNode)示例:
{ "id": "dept-1", "name": "研发部", "display_name": "研发部", "parent_id": "root", "full_path": "/公司/研发部", "has_child": true, "member_count": 10, "user_count": 5, "order": 1, "attributes": { "cost_center": "R&D" }, "external_data": { "raw": "…" }}
成员(OrgMember)字段说明(Swagger 类型):
·id(string):成员唯一标识
·name(string):成员名称(用户名/昵称)
·display_name(string):展示名称
·email(string):邮箱
·mobile(string):手机号
·employee_number(string):工号
·title(string):职级/职位
·department_path(array<string>):部门名称路径(不含 ID)
·department_full_path(array<string>):部门完整路径(可包含前缀)
·is_leader(boolean):是否负责人
·status(string):状态(如 active/disabled)
·extra(object<string,string>):扩展字段(键值对)
成员(OrgMember)示例:
{ "id": "m-100", "name": "zhangsan", "display_name": "张三", "email": "a@b.com", "mobile": "13800000000", "employee_number": "E123", "title": "SDE", "department_path": ["公司", "研发部"], "department_full_path": ["/公司", "/公司/研发部"], "is_leader": false, "status": "active", "extra": { "location": "SZ" }}
用户(OrgUser)字段说明(Swagger 类型):
·member(OrgMember):成员信息
·nodes(array<OrgNode>):所属节点列表
用户(OrgUser)示例:
{ "member": { …OrgMember… }, "nodes": [ …OrgNode… ]}
十二、1. 健康检查
·GET /org/health
·响应:HealthStatus
·响应字段说明(Swagger 类型):
·enterprise_id(string):企业 ID
·provider(string):提供方名称(固定为 custom)
·status(string):状态(healthy/unhealthy)
·message(string):异常信息
·last_synced_at(string(date-time)):最近同步时间
·cache_refreshed_at(string(date-time)):最近缓存刷新时间
{ "enterprise_id": "ent-xxx", "provider": "custom", "status": "healthy", "message": "", "last_synced_at": "2024-01-01T00:00:00Z", "cache_refreshed_at": "2024-01-01T00:00:00Z"}
十三、2. 获取部门树
·GET /org/nodes
·Query 字段说明(Swagger 类型)
·root_id(string):起始节点 ID(为空表示从根开始)
·depth(integer):展开深度(正数才生效)
·include_members(boolean):是否返回成员信息(true 时生效)
·use_cache(boolean):是否允许缓存(true 时生效)
·account_id(string):请求账号(用于审计/鉴权透传)
·响应字段说明(Swagger 类型)
·nodes(array<OrgNode>):节点数组
{ "nodes": [ …OrgNode… ] }
十四、3. 获取单个部门
·GET /org/nodes/{id}
·Query 字段说明(Swagger 类型)
·include_path(boolean):是否附带路径信息(true 时生效)
·include_members(boolean):是否返回成员信息(true 时生效)
·use_cache(boolean):是否允许缓存(true 时生效)
·account_id(string):请求账号(用于审计/鉴权透传)
·响应:OrgNode
十五、4. 批量获取部门
·POST /org/nodes/batch
·Query 字段说明(Swagger 类型)
·include_path(boolean):是否附带路径信息(true 时生效)
·include_members(boolean):是否返回成员信息(true 时生效)
·use_cache(boolean):是否允许缓存(true 时生效)
·account_id(string):请求账号(用于审计/鉴权透传)
·Body 字段说明(Swagger 类型)
·node_ids(array<string>):节点 ID 列表(必填)
·include_path(boolean):是否附带路径信息
·include_members(boolean):是否返回成员信息
·use_cache(boolean):是否允许缓存
·account_id(string):请求账号(可选)
{ "node_ids": ["id1","id2"], "include_path": true, "include_members": false, "use_cache": true, "account_id": "acc-1"}
·响应字段说明(Swagger 类型)
·nodes(array<OrgNode>):节点数组
{ "nodes": [ …OrgNode… ] }
十六、5. 子部门列表
·GET /org/nodes/{id}/children
·Query 字段说明(Swagger 类型)
·include_members(boolean):是否返回成员信息(true 时生效)
·limit(integer):分页大小(正数才生效)
·offset(integer):分页偏移(正数才生效)
·use_cache(boolean):是否允许缓存(true 时生效)
·account_id(string):请求账号(用于审计/鉴权透传)
·响应字段说明(Swagger 类型)
·nodes(array<OrgNode>):节点数组
{ "nodes": [ …OrgNode… ] }
十七、6. 部门成员列表
·GET /org/nodes/{id}/members
·Query 字段说明(Swagger 类型)
·include_subtree(boolean):是否包含子部门成员(true 时生效)
·use_cache(boolean):是否允许缓存(true 时生效)
·limit(integer):分页大小(正数才生效)
·offset(integer):分页偏移(正数才生效)
·role(string):成员角色过滤
·keyword(string):关键词过滤
·fields(string):指定返回字段(逗号分隔)
·account_id(string):请求账号(用于审计/鉴权透传)
·响应字段说明(MemberListResult, Swagger 类型)
·members(array<OrgMember>):成员数组
·next_offset(integer):下一页偏移
·next_token(string):下一页令牌
·total(integer):总数量
·exhausted(boolean):是否已返回完毕
{ "members": [ …OrgMember… ], "next_offset": 20, "next_token": "xxx", "total": 100, "exhausted": false}
十八、7. 路径解析节点
·GET /org/path
·Query 字段说明(Swagger 类型)
·delimiter(string):路径分隔符(默认 /)
·path(string):路径字符串(segments 按 delimiter 拼接)
·include_members(boolean):是否返回成员信息(true 时生效)
·use_cache(boolean):是否允许缓存(true 时生效)
·account_id(string):请求账号(用于审计/鉴权透传)
·响应:OrgNode
十九、8. 搜索
·GET /org/search
·Query 字段说明(Swagger 类型)
·type(string):搜索类型(node/user:node 为部门,user 为用户)
·keyword(string):关键词
·fuzzy(boolean):是否模糊搜索(true 时为模糊搜索,false 时为精准搜索,注:接口需要支持两种搜索方式,否则页面可能报错)
·limit(integer):分页大小(正数才生效)
·offset(integer):分页偏移(正数才生效)
·fields(string):指定返回字段(逗号分隔)
·use_cache(boolean):是否允许缓存(true 时生效)
·account_id(string):请求账号(用于审计/鉴权透传)
·响应字段说明(SearchResult, Swagger 类型)
·nodes(array<OrgNode>):匹配的节点列表
·users(array<OrgMember>):匹配的成员列表
·next_offset(integer):下一页偏移
·next_token(string):下一页令牌
·total(integer):总数量
·exhausted(boolean):是否已返回完毕
{ "nodes": [ …OrgNode… ], "users": [ …OrgMember… ], "next_offset": 20, "next_token": "xxx", "total": 100, "exhausted": false}
20、9. 用户详情
·GET /org/users/{id}
·Query 字段说明(Swagger 类型)
·use_cache(boolean):是否允许缓存(true 时生效)
·account_id(string):请求账号(用于审计/鉴权透传)
·响应:OrgUser
21、10. 刷新缓存
·POST /org/cache/refresh
·Body 字段说明(Swagger 类型)
·enterprise_id(string):企业 ID(可选)
·node_ids(array<string>):需要刷新的节点 ID 列表(可选)
·full_path(string):部门路径(可选)
·force(boolean):是否强制刷新
{ "enterprise_id": "ent-xxx", "node_ids": ["id1","id2"], "full_path": "/公司/研发部", "force": true}
·响应字段说明(Swagger 类型)
·succeeded(array<string>):成功刷新节点列表
·failed(object<string,string>):失败节点与原因映射
{ "succeeded": ["id1"], "failed": { "id2": "reason" }}
22、11. 同步状态
·GET /org/sync/status
·响应:任意 JSON(RawMessage)
23、12. 根据账号解析用户(内部逻辑)
·SDK 会调用 /org/search(type=user, fuzzy=false, limit=1)
·该接口无需额外实现
24、13. 解析成员 ID
·POST /org/members/resolve
·Body 字段说明(Swagger 类型,注意:无 JSON tag,字段名为驼峰)
·EnterpriseID(string):企业 ID
·UserID(string):用户 ID
·Username(string):用户名/账号
·Email(string):邮箱
·PhoneNumber(string):手机号
{ "EnterpriseID": "ent-xxx", "UserID": "u-1", "Username": "zhangsan", "Email": "a@b.com", "PhoneNumber": "13800000000"}
·响应字段说明(Swagger 类型)
·member_id(string):解析后的成员 ID
·member(OrgMember):成员详情(可选)
响应示例:
{ "member_id": "m-1", "member": { …OrgMember… }}
26、Q1:响应包装是否必须?
不必须,可以直接返回数据结构 JSON;如果使用包装结构,需要提供 code/message/data。
27、Q2:鉴权头可以自定义吗?
当前实现是固定的 Authorization: Bearer <auth_token>。auth_header/bearer_token 仅在日志中显示,不参与实际请求。
28、Q3:Config Header 做什么?
SDK 会在 X-Custom-Config(或自定义 config_header)里传递完整配置的 Base64 JSON,用于自定义服务侧识别上下文(如 enterprise_id 等)。