跳到主要内容

获取部门列表

分页获取指定父部门下的直接子部门列表。

接口信息​

项目说明
接口名称获取部门列表
权限标识contact.department.read(读取组织架构)
请求方式POST / GET
请求地址https://{gateway_host}/open/v1/contact/department/list
数据格式application/json(POST 时)或 URL Query
鉴权方式应用级 access_token(需具备 contact.department.read 权限)

前置条件​

  1. 应用已在管理后台「内部应用」中发布并启用。
  2. 已获取有效的应用级凭证 access_token。
  3. 查询的父部门必须存在且处于应用的可见范围之内。

请求参数​

请求头​

请求头必填说明
Authorization否Bearer <access_token>,推荐的凭证传递方式(与 Query / 表单三选一)
Content-Type否POST 请求使用 JSON 时传 application/json

参数列表​

参数支持在 POST JSON Body、POST Form 表单或 GET Query 中传递:

参数名类型必填说明
access_tokenstring是应用级令牌(若未在 Authorization 头中携带,则必填)
dept_idstring否父部门 ID。省略或传 "0" 时返回应用可见范围内的顶层部门/根部门
cursorstring否分页游标,从 0 开始的数字偏移量,默认 0。系统兼容别名 next_cursor、nextCursor
sizeinteger否每页返回数量,取值范围 1–100,默认 100
languagestring否语言/国际化预留参数,当前不影响返回内容

请求示例​

POST 请求示例:

POST https://{gateway_host}/open/v1/contact/department/list
Authorization: Bearer <access_token>
Content-Type: application/json

{
"dept_id": "0",
"cursor": "0",
"size": 50
}

GET 请求示例:

GET https://{gateway_host}/open/v1/contact/department/list?dept_id=0&cursor=0&size=50
Authorization: Bearer <access_token>

响应参数​

成功响应(平台统一响应外壳):

{
"code": 200,
"msg": "",
"data": {
"departments": [
{
"deptId": "20",
"name": "研发部",
"parentId": "10",
"order": 1
},
{
"deptId": "30",
"name": "市场部",
"parentId": "10",
"order": 2
}
],
"hasMore": true,
"nextCursor": "2"
}
}
字段类型说明
codeinteger业务状态码,200 表示成功
msgstring提示信息,成功时为空
data.departmentsobject[]直接子部门列表
data.departments[].deptIdstring部门 ID
data.departments[].namestring部门名称
data.departments[].parentIdstring上级部门 ID(上级不在可见范围内时截断为 "0")
data.departments[].orderinteger同级排序权重
data.hasMoreboolean是否还有更多数据(true 表示未遍历完,false 表示已结束)
data.nextCursorstring下一页分页游标。仅在 hasMore 为 true 时返回,后续请求作为 cursor 传入

遍历与组织树读取建议​

  1. 单层获取:本接口仅返回指定部门的直接下级部门,不会递归展开整棵树。
  2. 完整遍历组织架构推荐流程:
    • 步骤 1:调用本接口并传 dept_id="0",获取应用可见范围内的所有顶层部门;
    • 步骤 2:对每个部门递归调用本接口,逐层向下遍历读取子部门;
    • 步骤 3:结合《获取部门成员列表》接口读取每个部门的直属成员,组装完整的通讯录数据。
  3. 分页结束标记:请以 hasMore == false 作为循环终止条件。

可见范围与组织遍历​

应用可见范围同时影响工作台展示、免登和通讯录返回结果。范围之外的成员或部门按不存在处理。

推荐遍历顺序​

  1. 不传 dept_id 调用《获取部门列表》,得到可见范围内的顶层节点。
  2. 对每个部门递归调用部门列表接口,直到没有子部门。
  3. 对每个部门调用获取部门成员列表并按 userId 归并。
  4. 使用事件订阅获取变化信号,并定期全量对账。

语义约束​

  • parentId="0" 可能只是可见范围下的顶层节点,不一定是真实企业根节点。
  • 可见范围变更后,后续请求立即按新范围过滤,不需要重新换取 access_token。
  • 成员可能属于多个部门,deptIdList 只包含应用可见部门。
  • 分页以 hasMore 为准,不能以当前页数量是否小于 size 判断结束。

组织遍历示例​

Shell​

# 中文注释:先读取顶层部门,再把 nextCursor 原样传回下一页。
curl -sS -X POST "https://{gateway_host}/open/v1/contact/department/list" -H "Authorization: Bearer access-token-xxx" -H "Content-Type: application/json" -d '{"cursor":"0","size":100}'

PHP​

<?php
// 中文注释:生产代码应使用队列遍历部门,避免递归深度不可控。
$url = 'https://{gateway_host}/open/v1/contact/department/list?cursor=0&size=100'; $ch = curl_init($url); curl_setopt_array($ch, [CURLOPT_POST => true, CURLOPT_HTTPHEADER => ['Authorization: Bearer access-token-xxx'], CURLOPT_RETURNTRANSFER => true]); echo curl_exec($ch); curl_close($ch);

Golang​

package main
import "net/http"
func main() {
// 中文注释:实际同步应使用队列和 userId 去重,避免成员多部门重复入库。
request, _ := http.NewRequest(http.MethodPost, "https://{gateway_host}/open/v1/contact/department/list?cursor=0&size=100", nil); request.Header.Set("Authorization", "Bearer access-token-xxx"); response, _ := http.DefaultClient.Do(request); defer response.Body.Close()
}

C++​

#include <curl/curl.h>
int main() {
// 中文注释:不要硬编码唯一根部门 ID,应以接口返回的顶层节点为起点。
CURL* handle = curl_easy_init(); struct curl_slist* headers = curl_slist_append(nullptr, "Authorization: Bearer access-token-xxx"); curl_easy_setopt(handle, CURLOPT_URL, "https://{gateway_host}/open/v1/contact/department/list?cursor=0&size=100"); curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers); curl_easy_setopt(handle, CURLOPT_POST, 1L); const CURLcode result = curl_easy_perform(handle); curl_slist_free_all(headers); curl_easy_cleanup(handle); return result == CURLE_OK ? 0 : 1;
}

事件只表示“可能发生变化”,不能替代最终查询;详见事件订阅。

数据规则​

  • 可见范围之外的数据按不存在处理,应用不能通过错误码区分“不存在”和“不可见”。
  • 部门列表返回直接子部门,成员列表返回直属成员;完整同步按可见范围与组织遍历执行。
  • 成员 ID、部门 ID 使用字符串;未设置的可选字段可能不返回。
  • 列表接口使用 cursor、size、hasMore 和 nextCursor 翻页。

公共错误码和重试规则见接入指南。

错误码说明​

鉴权与中间件错误(HTTP 状态码)​

HTTP 状态码msg 错误码说明
401INVALID_TOKEN令牌缺失、已过期、已失效,或应用不可用
403SCOPE_DENIED令牌缺少 contact.department.read 权限
403IP_DENIED请求来源 IP 未命中应用安全设置的 IP 白名单

业务错误(HTTP 200,code=500)​

{
"code": 500,
"msg": "DEPARTMENT_NOT_FOUND",
"data": null
}
msg 错误码说明与排查建议
INVALID_REQUEST参数 cursor 不是合法的数字偏移量或超出范围;size 不在 1–100 区间内
DEPARTMENT_NOT_FOUND指定的父部门 dept_id 不存在、已被删除或不在应用可见范围内
PERMISSION_DENIED应用状态异常(已被停用、取消发布或删除)
SERVER_ERROR服务端内部异常,请稍后重试

多语言调用示例​

以下示例使用服务端调用方式;应用密钥和应用令牌不得下发到客户端。

Shell​

curl -sS -X POST "https://{gateway_host}/open/v1/contact/department/list" \
-H "Authorization: Bearer access-token-xxx" \\\n -H "Content-Type: application/json" \
-d '{"dept_id":"0","cursor":"0","size":50}'

PHP​

<?php
// 中文注释:生产环境应检查 HTTP 状态码和响应体,再映射业务错误。
$handle = curl_init('https://{gateway_host}/open/v1/contact/department/list');
curl_setopt_array($handle, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => ['Authorization: Bearer access-token-xxx', 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => '{"dept_id":"0","cursor":"0","size":50}',
CURLOPT_RETURNTRANSFER => true,
]);
echo curl_exec($handle);
curl_close($handle);

Golang​

package main

import (
"bytes"
"net/http"
)

func main() {
// 中文注释:令牌只在服务端请求中使用,并按接口约定携带。
request, _ := http.NewRequest(http.MethodPost, "https://{gateway_host}/open/v1/contact/department/list", bytes.NewBufferString(`{"dept_id":"0","cursor":"0","size":50}`))
request.Header.Set("Authorization", "Bearer access-token-xxx")
request.Header.Set("Content-Type", "application/json")
response, _ := http.DefaultClient.Do(request)
defer response.Body.Close()
}

C++​

#include <curl/curl.h>

int main() {
// 中文注释:生产环境应启用 TLS 校验并处理 HTTP 错误。
CURL* handle = curl_easy_init();
struct curl_slist* headers = nullptr;
headers = curl_slist_append(headers, "Authorization: Bearer access-token-xxx");
headers = curl_slist_append(headers, "Content-Type: application/json");
curl_easy_setopt(handle, CURLOPT_URL, "https://{gateway_host}/open/v1/contact/department/list");
curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(handle, CURLOPT_POSTFIELDS, R"({"dept_id":"0","cursor":"0","size":50})");
const CURLcode result = curl_easy_perform(handle);
curl_slist_free_all(headers);
curl_easy_cleanup(handle);
return result == CURLE_OK ? 0 : 1;
}