飞书开放平台 API 实战:技术支持岗笔试全记录
背景
这是一次飞书技术支持岗位的面试前置笔试,考察的核心是候选人能否通过阅读飞书开放平台文档,独立完成一系列 API 调用。考察不要求候选人自行创建应用,而是提供了现成的 app_id 和 app_secret,直接上手调接口。
笔试一共四个场景,串联了飞书开放平台的多个模块:多维表格、即时通讯(群组)、日历、机器人。以下是完整的技术复盘。
前置:获取 Tenant Access Token
所有飞书开放平台的 API 调用都需要鉴权,第一步就是用应用凭证换取 tenant_access_token。
curl -X POST 'https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal' \
-H 'Content-Type: application/json' \
-d '{
"app_id": "cli_xxxxxxxxxxxx",
"app_secret": "<your_app_secret>"
}'响应:
{
"code": 0,
"expire": 5275,
"msg": "ok",
"tenant_access_token": "t-g104xxxxx..."
}这个 token 有效期约 2 小时(expire 单位为秒),后续所有请求都在 Authorization 头中以 Bearer <token> 的形式携带。
前置:解析多维表格信息
笔试提供了一个多维表格链接,格式如下:
https://<tenant>.feishu.cn/base/<app_token>?table=<table_id>&view=<view_id>从 URL 中可以直接提取:
| 参数 | 值 | 说明 |
|---|---|---|
app_token | IwPzbs****c13s****0Lqn6c | 多维表格的唯一标识 |
table_id | tbljZ7****vYwP | 数据表标识(个人信息表) |
view_id | vewvtr****Qc | 视图标识 |
这些参数会在后续所有多维表格操作中反复使用。
场景 1:写入个人信息
目标:向多维表格的「个人信息表」新增一条记录,包含姓名、年龄、毕业院校、提交时间。

API 调用
curl -X POST "https://open.feishu.cn/open-apis/bitable/v1/apps/${APP_TOKEN}/tables/${TABLE_ID}/records" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"fields": {
"姓名": "候选人姓名",
"年龄": 22,
"毕业院校": "XX大学",
"提交时间": 1776917790070
}
}'关键细节
- 字段名必须与多维表格中的列名完全匹配,包括中文和大小写
- 日期字段需要传入毫秒级 Unix 时间戳,不是 ISO 8601 字符串。可以用
python3 -c "import time; print(int(time.time()*1000))"快速生成 - 数字字段直接传数字类型,不要加引号
响应
{
"code": 0,
"msg": "success",
"data": {
"record": {
"record_id": "recXXXXXXXX",
"fields": {
"姓名": "候选人姓名",
"年龄": 22,
"毕业院校": "XX大学",
"提交时间": 1776917790070
}
}
}
}务必保存 record_id,后续场景 2 和场景 3 都需要用它来更新这条记录。
文档参考:新增记录
场景 2:创建群组并回写
目标:以机器人身份创建一个群组,群名称为自己的姓名,然后将群名称以群组类型写回多维表格。
2a. 创建群组
curl -X POST "https://open.feishu.cn/open-apis/im/v1/chats" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{"name": "候选人姓名"}'响应中的关键字段:
{
"code": 0,
"data": {
"chat_id": "oc_xxxxxxxxxxxxxxxxxxxx",
"name": "候选人姓名",
"chat_type": "private",
"owner_id": "ou_xxxxxxxxxxxxxxxxxxxx"
}
}机器人创建群组时自动成为群主(owner_id 就是机器人的 open_id)。
2b. 回写群名称(群组类型)
这里有一个关键坑点:题目要求写入的是群组类型的值,不是纯文本。群组类型字段需要传入对象数组,包含 id 字段(即 chat_id):
curl -X PUT "https://open.feishu.cn/open-apis/bitable/v1/apps/${APP_TOKEN}/tables/${TABLE_ID}/records/${RECORD_ID}" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"fields": {
"群名称": [{"id": "oc_xxxxxxxxxxxxxxxxxxxx"}]
}
}'如果直接传字符串 "群名称": "候选人姓名",虽然不会报错但写入的是纯文本,不会显示为可点击跳转的群组链接。
场景 3:创建日程 + 上传截图
目标:创建一个当天 10:00-10
的日程(标题为自己姓名),截图 API 响应,上传到多维表格的附件字段。
这是四个场景中步骤最多的一个,串联了三个不同的 API 模块。
3a. 获取主日历 ID
curl -X POST "https://open.feishu.cn/open-apis/calendar/v4/calendars/primary" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json"响应:
{
"code": 0,
"data": {
"calendars": [{
"calendar": {
"calendar_id": "feishu.cn_XXXXXXXXXXXX@group.calendar.feishu.cn",
"summary": "技术支持面试考察",
"type": "primary"
}
}]
}
}calendar_id 藏在 data.calendars[0].calendar.calendar_id 里,嵌套较深。
3b. 创建日程
时间戳计算是关键——需要的是秒级 Unix 时间戳(不是毫秒级,和多维表格日期字段不同):
from datetime import datetime, timezone, timedelta
tz = timezone(timedelta(hours=8))
start = datetime(2026, 4, 23, 10, 0, 0, tzinfo=tz)
end = datetime(2026, 4, 23, 10, 30, 0, tzinfo=tz)
print(int(start.timestamp())) # 1776909600
print(int(end.timestamp())) # 1776911400curl -X POST "https://open.feishu.cn/open-apis/calendar/v4/calendars/${CALENDAR_ID}/events" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"summary": "候选人姓名",
"start_time": {
"timestamp": "1776909600",
"timezone": "Asia/Shanghai"
},
"end_time": {
"timestamp": "1776911400",
"timezone": "Asia/Shanghai"
}
}'注意
timestamp字段的值是字符串类型,不是数字。
3c. 生成响应截图
API 响应需要截图上传。我用 Python + Pillow 将 JSON 响应渲染为 PNG 图片:
import json
from PIL import Image, ImageDraw, ImageFont
with open("calendar_response.json") as f:
data = json.load(f)
pretty = json.dumps(data, indent=2, ensure_ascii=False)
lines = pretty.split('\n')
font = ImageFont.truetype(
"/System/Library/Fonts/Hiragino Sans GB.ttc", 14
)
line_height = 20
padding = 20
max_width = max(font.getlength(line) for line in lines)
width = int(max_width + padding * 2 + 20)
height = len(lines) * line_height + padding * 2
img = Image.new('RGB', (width, height), color=(30, 30, 30))
draw = ImageDraw.Draw(img)
y = padding
for line in lines:
draw.text((padding, y), line, fill=(0, 255, 0), font=font)
y += line_height
img.save("calendar_screenshot.png")生成效果如下:

有两个渲染细节需要注意:
- 字体选择:macOS 上 Menlo 等等宽字体不支持中文,会导致
"summary": "候选人姓名"中的中文显示为方块。需要用Hiragino Sans GB或PingFang等中文字体 - 图片宽度:要根据最长行动态计算宽度,否则长 URL(如
app_link)会被截断
3d. 上传素材到多维表格
飞书多维表格的附件字段不能直接传 URL,需要先通过素材上传接口获取 file_token:
curl -X POST "https://open.feishu.cn/open-apis/drive/v1/medias/upload_all" \
-H "Authorization: Bearer ${TOKEN}" \
-F "file_name=calendar_response.png" \
-F "parent_type=bitable_image" \
-F "parent_node=${APP_TOKEN}" \
-F "size=${FILE_SIZE}" \
-F "file=@calendar_screenshot.png"关键参数说明:
| 参数 | 值 | 说明 |
|---|---|---|
parent_type | bitable_image | 表示上传到多维表格,如果是普通文件用 bitable_file |
parent_node | 多维表格的 app_token | 不是 table_id |
size | 文件字节数 | 必须精确匹配,可用 stat -f%z file 获取 |
3e. 更新记录附件字段
拿到 file_token 后,更新记录的附件字段:
curl -X PUT "https://open.feishu.cn/open-apis/bitable/v1/apps/${APP_TOKEN}/tables/${TABLE_ID}/records/${RECORD_ID}" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"fields": {
"日程接口响应截图": [{"file_token": "XXXXXXXXXXXX"}]
}
}'附件字段的值是一个数组,每个元素包含 file_token。如果要追加附件而不是覆盖,需要先读取现有记录,合并 token 后再写入。
场景 4:获取机器人信息并写入
目标:获取机器人应用信息,写入多维表格的对应字段,机器人名称后附加自己的姓名。
4a. 获取机器人信息
curl -X GET "https://open.feishu.cn/open-apis/bot/v3/info" \
-H "Authorization: Bearer ${TOKEN}"响应:
{
"code": 0,
"msg": "ok",
"bot": {
"activate_status": 2,
"app_name": "技术支持面试考察",
"avatar_url": "https://s3-imfile.feishucdn.com/static-resource/v1/XXXXXXXXXXXX",
"ip_white_list": [],
"open_id": "ou_xxxxxxxxxxxxxxxxxxxx"
}
}注意这个接口的响应结构与其他接口不同——bot 对象直接在根级别,不在 data 里。
4b. 写入机器人信息
curl -X PUT "https://open.feishu.cn/open-apis/bitable/v1/apps/${APP_TOKEN}/tables/${TABLE_ID}/records/${RECORD_ID}" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"fields": {
"机器人名称": "技术支持面试考察-候选人姓名",
"图像地址": {
"text": "机器人头像",
"link": "https://s3-imfile.feishucdn.com/static-resource/v1/XXXXXXXXXXXX"
},
"机器人的open_id": "ou_xxxxxxxxxxxxxxxxxxxx"
}
}'「图像地址」字段是超链接类型,需要传 {text, link} 对象而非纯文本。

文档参考:获取机器人信息
踩坑总结
多维表格字段类型映射
这次笔试涉及的字段类型比较多,总结如下:
| 多维表格字段类型 | API 传值格式 | 示例 |
|---|---|---|
| 文本 | 字符串 | "姓名": "候选人姓名" |
| 数字 | 数字 | "年龄": 22 |
| 日期 | 毫秒级时间戳 | "提交时间": 1776917790070 |
| 群组 | 对象数组 [{id}] | "群名称": [{"id": "oc_xxx"}] |
| 附件 | 对象数组 [{file_token}] | "截图": [{"file_token": "xxx"}] |
| 超链接 | 对象 {text, link} | "链接": {"text": "显示文字", "link": "https://..."} |
时间戳精度差异
- 多维表格日期字段:毫秒级时间戳(13 位)
- 日历 API 的 start_time/end_time:秒级时间戳(10 位),且为字符串类型
权限问题
调用 API 时可能遇到 99991672 错误(权限不足)。这不影响写操作——有些应用可能只配置了写权限而没有读权限。遇到读接口报权限错误时,可以尝试直接调用写接口,只要从 URL 中提取了 app_token 和 table_id 就不需要先调用列表接口。
素材上传
parent_type 的值容易混淆:
bitable_image:上传图片到多维表格bitable_file:上传文件到多维表格parent_node是多维表格的app_token,不是table_id
完整调用链路
获取 tenant_access_token
│
├─ 场景1:POST /bitable/.../records → 拿到 record_id
│
├─ 场景2:POST /im/v1/chats → 拿到 chat_id
│ PUT /bitable/.../records → 回写群名称
│
├─ 场景3:POST /calendar/.../primary → 拿到 calendar_id
│ POST /calendar/.../events → 创建日程,保存响应
│ POST /drive/.../upload_all → 上传截图,拿到 file_token
│ PUT /bitable/.../records → 回写附件
│
└─ 场景4:GET /bot/v3/info → 拿到 bot 信息
PUT /bitable/.../records → 回写机器人信息整个流程涉及 8 次 API 调用,横跨 4 个飞书开放平台模块。每一步的输出都是下一步的输入,是一次很好的 API 串联实战练习。