feishu

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese
We drive the Feishu Open Platform API with
curl + jq
. The user's OAuth
user_access_token
is in
$FEISHU_TOKEN
; every call sends it as
Authorization: Bearer $FEISHU_TOKEN
. All endpoints live under
https://open.feishu.cn/open-apis
.
Calls run in the user's context (their docs, calendar, messages) — only data the user can access and only the scopes they granted at connect time (docs / sheets / base / drive / calendar / IM / wiki / task / contacts).
我们通过
curl + jq
调用飞书开放平台API。用户的OAuth
user_access_token
存储在
$FEISHU_TOKEN
中;每次调用都会以
Authorization: Bearer $FEISHU_TOKEN
的形式携带该令牌。所有接口端点均位于
https://open.feishu.cn/open-apis
下。
调用将在用户上下文中执行(访问用户的文档、日历、消息)——仅能访问用户有权限查看的数据,且仅使用用户在连接时授予的权限范围(文档/表格/多维表格/云盘/日历/即时通讯/知识库/任务/联系人)。

Response shape & error handling

响应格式与错误处理

Every Feishu response is
{"code": 0, "msg": "success", "data": {…}}
.
code == 0
means success
; any non-zero
code
is an error — surface
msg
to the user. Always check it:
sh
resp=$(curl -sS)
echo "$resp" | jq 'if .code == 0 then .data else error("Feishu \(.code): \(.msg)") end'
Common error codes:
codemeaningwhat to do
99991663
/
99991668
access token invalid / expiredtell the user to reconnect Feishu in 连接 settings
99991661
no permission (scope not granted)the connect-time scope is missing — reconnect and grant it
1254xxx
resource not found / no accessthe user can't see that doc / sheet / app — double-check the token/id
飞书的每个响应格式均为
{"code": 0, "msg": "success", "data": {…}}
code == 0
表示请求成功
;任何非零
code
均代表错误——需将
msg
内容展示给用户。请务必检查该字段:
sh
resp=$(curl -sS)
echo "$resp" | jq 'if .code == 0 then .data else error("Feishu \(.code): \(.msg)") end'
常见错误码:
错误码含义处理方式
99991663
/
99991668
访问令牌无效/过期告知用户在连接设置中重新连接飞书
99991661
无权限(未授予对应权限范围)缺少连接时的权限范围——重新连接并授予对应权限
1254xxx
资源未找到/无访问权限用户无法查看该文档/表格/应用——请核实令牌或资源ID

Recipes

操作示例

Verify auth (always run first)

验证授权(请始终先执行此步骤)

sh
curl -sS https://open.feishu.cn/open-apis/authen/v1/user_info \
  -H "Authorization: Bearer $FEISHU_TOKEN" \
  | jq 'if .code == 0 then {name: .data.name, open_id: .data.open_id, email: .data.email} else . end'
sh
curl -sS https://open.feishu.cn/open-apis/authen/v1/user_info \
  -H "Authorization: Bearer $FEISHU_TOKEN" \
  | jq 'if .code == 0 then {name: .data.name, open_id: .data.open_id, email: .data.email} else . end'

Docs (docx)

文档(docx)

A Feishu doc URL looks like
https://…feishu.cn/docx/<document_id>
. The
document_id
is the last path segment.
Read a document's plain text:
sh
curl -sS "https://open.feishu.cn/open-apis/docx/v1/documents/DOCUMENT_ID/raw_content" \
  -H "Authorization: Bearer $FEISHU_TOKEN" \
  | jq -r 'if .code == 0 then .data.content else "ERR \(.code): \(.msg)" end'
List a document's blocks (structured content):
sh
curl -sS "https://open.feishu.cn/open-apis/docx/v1/documents/DOCUMENT_ID/blocks?page_size=500" \
  -H "Authorization: Bearer $FEISHU_TOKEN" \
  | jq 'if .code == 0 then [.data.items[] | {block_id, block_type}] else . end'
Create a new empty document (optionally inside a folder):
sh
curl -sS -X POST "https://open.feishu.cn/open-apis/docx/v1/documents" \
  -H "Authorization: Bearer $FEISHU_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -nc --arg title "会议纪要 2026-07-01" '{title: $title}')" \
  | jq 'if .code == 0 then {document_id: .data.document.document_id} else . end'
Append a text block to a document (insert at the end of the document body —
DOCUMENT_ID
is also the root block id):
sh
curl -sS -X POST "https://open.feishu.cn/open-apis/docx/v1/documents/DOCUMENT_ID/blocks/DOCUMENT_ID/children" \
  -H "Authorization: Bearer $FEISHU_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -nc --arg text "由助手追加的一段内容。" '
    {children: [{block_type: 2, text: {elements: [{text_run: {content: $text}}]}}]}')" \
  | jq 'if .code == 0 then "appended" else . end'
飞书文档的URL格式为
https://…feishu.cn/docx/<document_id>
document_id
是URL路径的最后一段。
读取文档纯文本内容:
sh
curl -sS "https://open.feishu.cn/open-apis/docx/v1/documents/DOCUMENT_ID/raw_content" \
  -H "Authorization: Bearer $FEISHU_TOKEN" \
  | jq -r 'if .code == 0 then .data.content else "ERR \(.code): \(.msg)" end'
列出文档的结构化内容块:
sh
curl -sS "https://open.feishu.cn/open-apis/docx/v1/documents/DOCUMENT_ID/blocks?page_size=500" \
  -H "Authorization: Bearer $FEISHU_TOKEN" \
  | jq 'if .code == 0 then [.data.items[] | {block_id, block_type}] else . end'
创建新的空白文档(可选择创建在指定文件夹内):
sh
curl -sS -X POST "https://open.feishu.cn/open-apis/docx/v1/documents" \
  -H "Authorization: Bearer $FEISHU_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -nc --arg title "会议纪要 2026-07-01" '{title: $title}')" \
  | jq 'if .code == 0 then {document_id: .data.document.document_id} else . end'
向文档追加文本块(插入到文档正文末尾——
DOCUMENT_ID
同时也是根内容块ID):
sh
curl -sS -X POST "https://open.feishu.cn/open-apis/docx/v1/documents/DOCUMENT_ID/blocks/DOCUMENT_ID/children" \
  -H "Authorization: Bearer $FEISHU_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -nc --arg text "由助手追加的一段内容。" '
    {children: [{block_type: 2, text: {elements: [{text_run: {content: $text}}]}}]}')" \
  | jq 'if .code == 0 then "appended" else . end'

Spreadsheets (sheets v2)

电子表格(sheets v2)

A sheet URL looks like
https://…feishu.cn/sheets/<spreadsheet_token>
. A range is
<sheetId>!<A1:range>
, e.g.
abc123!A1:D10
. List sheet ids via the metainfo endpoint first if you don't have one.
Read a range:
sh
curl -sS "https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/SPREADSHEET_TOKEN/values/RANGE" \
  -H "Authorization: Bearer $FEISHU_TOKEN" \
  | jq 'if .code == 0 then .data.valueRange.values else . end'
Append rows after the last non-empty row:
sh
curl -sS -X POST "https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/SPREADSHEET_TOKEN/values_append" \
  -H "Authorization: Bearer $FEISHU_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -nc '{valueRange: {range: "SHEET_ID!A1:B1", values: [["张三", 100], ["李四", 200]]}}')" \
  | jq 'if .code == 0 then .data.updates else . end'
飞书表格的URL格式为
https://…feishu.cn/sheets/<spreadsheet_token>
。数据范围格式为
<sheetId>!<A1:range>
,例如
abc123!A1:D10
。若未获取sheetId,可先通过元信息接口列出所有sheetId。
读取指定范围的数据:
sh
curl -sS "https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/SPREADSHEET_TOKEN/values/RANGE" \
  -H "Authorization: Bearer $FEISHU_TOKEN" \
  | jq 'if .code == 0 then .data.valueRange.values else . end'
在最后一行非空行后追加数据行:
sh
curl -sS -X POST "https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/SPREADSHEET_TOKEN/values_append" \
  -H "Authorization: Bearer $FEISHU_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -nc '{valueRange: {range: "SHEET_ID!A1:B1", values: [["张三", 100], ["李四", 200]]}}')" \
  | jq 'if .code == 0 then .data.updates else . end'

Base / 多维表格 (bitable v1)

多维表格(Base / bitable v1)

A Base URL looks like
https://…feishu.cn/base/<app_token>
. Get
table_id
from
…/bitable/v1/apps/APP_TOKEN/tables
.
List records:
sh
curl -sS "https://open.feishu.cn/open-apis/bitable/v1/apps/APP_TOKEN/tables/TABLE_ID/records?page_size=100" \
  -H "Authorization: Bearer $FEISHU_TOKEN" \
  | jq 'if .code == 0 then [.data.items[] | {record_id, fields}] else . end'
Create a record:
sh
curl -sS -X POST "https://open.feishu.cn/open-apis/bitable/v1/apps/APP_TOKEN/tables/TABLE_ID/records" \
  -H "Authorization: Bearer $FEISHU_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -nc '{fields: {"标题": "新任务", "状态": "待办"}}')" \
  | jq 'if .code == 0 then {record_id: .data.record.record_id} else . end'
飞书多维表格的URL格式为
https://…feishu.cn/base/<app_token>
。可通过
…/bitable/v1/apps/APP_TOKEN/tables
接口获取
table_id
列出表格记录:
sh
curl -sS "https://open.feishu.cn/open-apis/bitable/v1/apps/APP_TOKEN/tables/TABLE_ID/records?page_size=100" \
  -H "Authorization: Bearer $FEISHU_TOKEN" \
  | jq 'if .code == 0 then [.data.items[] | {record_id, fields}] else . end'
创建新记录:
sh
curl -sS -X POST "https://open.feishu.cn/open-apis/bitable/v1/apps/APP_TOKEN/tables/TABLE_ID/records" \
  -H "Authorization: Bearer $FEISHU_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -nc '{fields: {"标题": "新任务", "状态": "待办"}}')" \
  | jq 'if .code == 0 then {record_id: .data.record.record_id} else . end'

Drive files

云盘文件

List files in a folder (omit
folder_token
for the root):
sh
curl -sS "https://open.feishu.cn/open-apis/drive/v1/files?folder_token=FOLDER_TOKEN&page_size=50" \
  -H "Authorization: Bearer $FEISHU_TOKEN" \
  | jq 'if .code == 0 then [.data.files[] | {name, type, token, url}] else . end'
列出指定文件夹内的文件(省略
folder_token
则列出根目录文件):
sh
curl -sS "https://open.feishu.cn/open-apis/drive/v1/files?folder_token=FOLDER_TOKEN&page_size=50" \
  -H "Authorization: Bearer $FEISHU_TOKEN" \
  | jq 'if .code == 0 then [.data.files[] | {name, type, token, url}] else . end'

Calendar (v4)

日历(v4)

List the user's calendars (the primary one has
type: "primary"
):
sh
curl -sS "https://open.feishu.cn/open-apis/calendar/v4/calendars?page_size=50" \
  -H "Authorization: Bearer $FEISHU_TOKEN" \
  | jq 'if .code == 0 then [.data.calendar_list[] | {calendar_id, summary, type}] else . end'
List events in a time window (epoch-seconds strings):
sh
curl -sS "https://open.feishu.cn/open-apis/calendar/v4/calendars/CALENDAR_ID/events?start_time=1751299200&end_time=1751385600&page_size=100" \
  -H "Authorization: Bearer $FEISHU_TOKEN" \
  | jq 'if .code == 0 then [.data.items[] | {summary, start: .start_time, end: .end_time, event_id}] else . end'
Create an event (times are epoch-seconds strings):
sh
curl -sS -X POST "https://open.feishu.cn/open-apis/calendar/v4/calendars/CALENDAR_ID/events" \
  -H "Authorization: Bearer $FEISHU_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -nc '{summary: "项目评审", start_time: {timestamp: "1751302800"}, end_time: {timestamp: "1751306400"}}')" \
  | jq 'if .code == 0 then {event_id: .data.event.event_id} else . end'
列出用户的日历(主日历的
type
"primary"
):
sh
curl -sS "https://open.feishu.cn/open-apis/calendar/v4/calendars?page_size=50" \
  -H "Authorization: Bearer $FEISHU_TOKEN" \
  | jq 'if .code == 0 then [.data.calendar_list[] | {calendar_id, summary, type}] else . end'
列出指定时间范围内的日历事件(时间戳为秒级时间戳字符串):
sh
curl -sS "https://open.feishu.cn/open-apis/calendar/v4/calendars/CALENDAR_ID/events?start_time=1751299200&end_time=1751385600&page_size=100" \
  -H "Authorization: Bearer $FEISHU_TOKEN" \
  | jq 'if .code == 0 then [.data.items[] | {summary, start: .start_time, end: .end_time, event_id}] else . end'
创建日历事件(时间戳为秒级时间戳字符串):
sh
curl -sS -X POST "https://open.feishu.cn/open-apis/calendar/v4/calendars/CALENDAR_ID/events" \
  -H "Authorization: Bearer $FEISHU_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -nc '{summary: "项目评审", start_time: {timestamp: "1751302800"}, end_time: {timestamp: "1751306400"}}')" \
  | jq 'if .code == 0 then {event_id: .data.event.event_id} else . end'

Tasks (v2)

任务(v2)

List the user's tasks:
sh
curl -sS "https://open.feishu.cn/open-apis/task/v2/tasks?page_size=50" \
  -H "Authorization: Bearer $FEISHU_TOKEN" \
  | jq 'if .code == 0 then [.data.items[] | {summary, completed_at, task_guid: .guid}] else . end'
Create a task:
sh
curl -sS -X POST "https://open.feishu.cn/open-apis/task/v2/tasks" \
  -H "Authorization: Bearer $FEISHU_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -nc '{summary: "准备周会材料"}')" \
  | jq 'if .code == 0 then {task_guid: .data.task.guid} else . end'
列出用户的任务:
sh
curl -sS "https://open.feishu.cn/open-apis/task/v2/tasks?page_size=50" \
  -H "Authorization: Bearer $FEISHU_TOKEN" \
  | jq 'if .code == 0 then [.data.items[] | {summary, completed_at, task_guid: .guid}] else . end'
创建新任务:
sh
curl -sS -X POST "https://open.feishu.cn/open-apis/task/v2/tasks" \
  -H "Authorization: Bearer $FEISHU_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -nc '{summary: "准备周会材料"}')" \
  | jq 'if .code == 0 then {task_guid: .data.task.guid} else . end'

Wiki

知识库

List wiki spaces, then nodes within a space:
sh
curl -sS "https://open.feishu.cn/open-apis/wiki/v2/spaces?page_size=50" \
  -H "Authorization: Bearer $FEISHU_TOKEN" \
  | jq 'if .code == 0 then [.data.items[] | {space_id, name}] else . end'

curl -sS "https://open.feishu.cn/open-apis/wiki/v2/spaces/SPACE_ID/nodes?page_size=50" \
  -H "Authorization: Bearer $FEISHU_TOKEN" \
  | jq 'if .code == 0 then [.data.items[] | {title, node_token, obj_type}] else . end'
先列出知识库空间,再列出指定空间内的节点:
sh
curl -sS "https://open.feishu.cn/open-apis/wiki/v2/spaces?page_size=50" \
  -H "Authorization: Bearer $FEISHU_TOKEN" \
  | jq 'if .code == 0 then [.data.items[] | {space_id, name}] else . end'

curl -sS "https://open.feishu.cn/open-apis/wiki/v2/spaces/SPACE_ID/nodes?page_size=50" \
  -H "Authorization: Bearer $FEISHU_TOKEN" \
  | jq 'if .code == 0 then [.data.items[] | {title, node_token, obj_type}] else . end'

Send an IM message

发送即时消息

Send to a user by
open_id
(use
receive_id_type=chat_id
for a group chat).
content
must be a JSON string, so it's double-encoded:
sh
curl -sS -X POST "https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=open_id" \
  -H "Authorization: Bearer $FEISHU_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -nc --arg rid "ou_xxx" --arg text "你好,这是助手发送的消息。" '
    {receive_id: $rid, msg_type: "text", content: ({text: $text} | tostring)}')" \
  | jq 'if .code == 0 then {message_id: .data.message_id} else . end'
通过
open_id
向用户发送消息(若发送到群组,需将
receive_id_type
设为
chat_id
)。
content
必须为JSON字符串,因此需要进行双重编码:
sh
curl -sS -X POST "https://open.feishu.cn/open-apis/im/v1/messages?receive_id_type=open_id" \
  -H "Authorization: Bearer $FEISHU_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -nc --arg rid "ou_xxx" --arg text "你好,这是助手发送的消息。" '
    {receive_id: $rid, msg_type: "text", content: ({text: $text} | tostring)}')" \
  | jq 'if .code == 0 then {message_id: .data.message_id} else . end'

Notes

注意事项

  • Confirm destructive or outward-facing actions (sending a message, creating a calendar invite, posting to a shared doc) with the user before running them.
  • Pagination: list endpoints return
    data.page_token
    /
    data.has_more
    ; pass
    page_token=…
    to fetch the next page.
  • When the user pastes a Feishu link, extract the token/id from the URL path rather than asking them for it.
  • 在执行具有破坏性或对外操作(发送消息、创建日历邀请、向共享文档写入内容)前,请先与用户确认。
  • 分页处理:列表类接口会返回
    data.page_token
    /
    data.has_more
    ;传递
    page_token=…
    参数可获取下一页数据。
  • 当用户粘贴飞书链接时,请从URL路径中提取令牌/ID,而非向用户索要。