必须完成三件事:一是用app_id和app_secret动态获取有效期2小时的app_access_token;二是用它换取tenant_access_token;三是确保企业已授权该应用通讯录权限,否则调用户接口会返回99991601错误。

PHP 调用字节跳动企业应用 API 前必须确认的三件事
不能直接调用,必须先完成鉴权。字节跳动企业开放平台所有接口都依赖 access_token,而它不是静态配置项,每次请求前都要动态获取,且有效期仅 2 小时。
- 你得有企业自建应用的
app_id和app_secret(在「开发者后台 → 应用管理」里找,不是小程序或飞书开放平台的) - 调用
https://open.feishu.cn/open-apis/auth/v3/app_access_token/internal/换取app_access_token,再用它去换员工相关的tenant_access_token(注意:不是直接拿app_access_token调组织架构接口) - 员工组织架构接口(如
/open-apis/contact/v3/users)必须使用tenant_access_token,且该 token 需要企业管理员授权后才有效——没走「应用授权」流程的话,哪怕 token 拿到了,调用户列表也会返回{"code":99991601,"msg":"Invalid tenant access token"}
PHP 获取员工组织架构信息的最小可行代码片段
别套 SDK,手写 cURL 更可控。重点不是“怎么发请求”,而是“token 怎么链式换、header 怎么设、分页怎么处理”。
- 先 POST
https://open.feishu.cn/open-apis/auth/v3/app_access_token/internal/,body 是{"app_id":"xxx","app_secret":"yyy"},拿到app_access_token - 再 POST
https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal/,body 是{"app_access_token":"zzz"},拿到tenant_access_token和tenant_key - 最后 GET
https://open.feishu.cn/open-apis/contact/v3/users?page_size=100,header 加Authorization: Bearer {tenant_access_token};注意:首次调可能只返回部分用户,必须循环读page_token字段继续拉取
curl -X GET "https://open.feishu.cn/open-apis/contact/v3/users?page_size=100" \ -H "Authorization: Bearer t-xxx"
常见 403 / 400 错误对应的真实原因
错误码不骗人,但字节跳动的提示文案容易误导。比如 403 Forbidden 看似权限问题,实际大概率是 token 过期或未授权;400 Bad Request 则常因参数名写错或类型不对。
-
{"code":99991601,"msg":"Invalid tenant access token"}→ 企业没在「应用管理 → 授权管理」里给该应用开通「通讯录」权限,或者tenant_access_token已过期(2 小时) -
{"code":210001,"msg":"invalid parameter"}→ 把page_token当字符串传了,但接口要求它是 URL-safe base64 编码后的值(不是原始 JSON) -
{"code":99991603,"msg":"App not installed in this tenant"}→ 应用压根没被该企业安装,连授权入口都没出现过 - 空响应或只有 1 条数据 → 忘了加
?page_size=100,默认只返回 20 条,且不返回page_token
PHP 实现里最容易漏掉的兼容性细节
字节跳动接口返回的 JSON 字段名是下划线风格(user_name),但 PHP 变量习惯驼峰,别硬转。更关键的是分页逻辑和 token 刷新时机。
立即学习“PHP免费学习笔记(深入)”;
- 不要把
tenant_access_token存成全局常量——它 2 小时失效,PHP-FPM 模式下常驻内存会卡死后续请求;建议每次业务入口都检查缓存中的 token 是否快过期(比如剩余 - 用户列表接口返回的
page_token是字符串,但下次请求时必须作为 query 参数原样拼接,不能 urlencode 两次(PHPhttp_build_query()默认会 encode,得手动rawurldecode()再拼) - 员工手机号字段叫
mobile,但只有企业开启「手机号对外可见」权限后才返回;没开的话字段为空,不是接口 bug
token 链路长、分页不透明、权限开关分散——这些不是 PHP 的问题,是字节跳动开放平台的设计事实。写的时候就得按“每次请求都重走鉴权+分页兜底”来设计,别省那几行代码。



















