Write content to Feishu cloud documents via the Docx API. Feishu documents use Block tree model, and do not accept raw Markdown.
Base URL: https://open.feishu.cn/open-apis/docx/v1
Authentication and Token Acquisition
From the feishu_skills root directory, execute the shared script:
TOKEN="$(./scripts/get_feishu_token.sh)"
Request headers uniformly use Authorization: Bearer ${TOKEN}。
If a business API returns token invalid, expired, or 401, force refresh and retry the original request only once:
TOKEN="$(./scripts/get_feishu_token.sh --force-refresh)"
Environment Variables:
FEISHU_APP_IDFEISHU_APP_SECRET
Local Cache: ./.feishu_token_cache.json(reuse directly if not expired, default refresh 5 minutes in advance)
Recommended method: conversion API
Feishu provides the official Markdown → Blocks conversion endpoint:
POST /documents/{document_id}/convert
{
"content": "# 标题\n\n正文\n\n- 列表项",
"content_type": "markdown"
}
✅ No need to manually build Block JSON, supports standard Markdown ⚠️ Does not support Feishu-specific blocks (Callout, etc.) — must be created manually
Block Type
| block_type | Name | JSON Key | Description |
|---|---|---|---|
| 1 | Page | page |
Document root node |
| 2 | Text | text |
Paragraph |
| 3-11 | Heading 1-9 | heading1-heading9 |
- |
| 12 | Unordered List | bullet |
Each item is a separate block |
| 13 | Ordered List | ordered |
- |
| 14 | Code Block | code |
Must specify style.language |
| 15 | Quote | quote |
- |
| 17 | To-do | todo |
With style.done |
| 19 | Callout | callout |
Feishu-specific, container block |
| 22 | Divider | divider |
- |
| 27 | Image | image |
Two steps: create placeholder + upload |
| 31 | Table | table |
- |
Create Blocks
POST /documents/{document_id}/blocks/{block_id}/children?document_revision_id=-1
{
"children": [...],
"index": 0
}
block_id: Parent block ID (for root node usedocument_id)index: Insertion position (0=beginning, -1=end)
Delete Blocks
Delete the child blocks within the specified range under the parent block:
DELETE /documents/{document_id}/blocks/{block_id}/children/batch_delete?document_revision_id=-1
{
"start_index": 3,
"end_index": 4
}
block_id: Parent block ID to operate onstart_index: Starting child block index (inclusive)end_index: Ending child block index (exclusive)- ⚠️ This API is
DELETE, notPOST
Block Example
Text:
{"block_type": 2, "text": {"elements": [{"text_run": {"content": "段落"}}]}}
Heading:
{"block_type": 3, "heading1": {"elements": [{"text_run": {"content": "标题"}}]}}
Code Block:
{
"block_type": 14,
"code": {
"style": {"language": 1},
"elements": [{"text_run": {"content": "console.log('hello')"}}]
}
}
Mermaid diagram block (plugin block):
{
"block_type": 40,
"add_ons": {
"component_type_id": "blk_631fefbbae02400430b8f9f4",
"record": "{\"data\":\"flowchart TD\\nA-->B\",\"theme\":\"default\",\"view\":\"codeChart\"}"
}
}
block_type = 40indicates a plugin blockcomponent_type_id = blk_631fefbbae02400430b8f9f4can be used for Mermaid diagramsrecordis stringified JSON; fields verified so far:data: Mermaid source codetheme: usually usedefaultview: usually usecodeChart
- If someone has already manually inserted a Mermaid in the "本文绘图" format into the document, read that block first, then reuse its
component_type_id/theme/view
Callout:
{
"block_type": 19,
"callout": {
"background_color": 1,
"border_color": 1,
"emoji_id": "bulb"
},
"children": [
{"block_type": 2, "text": {"elements": [{"text_run": {"content": "提示内容"}}]}}
]
}
Image (two steps):
- Create placeholder:
{"block_type": 27, "image": {}} - Upload:
PUT /documents/{document_id}/blocks/{block_id}/image
Text Style
{
"text_run": {
"content": "样式文本",
"text_element_style": {
"bold": true,
"italic": true,
"strikethrough": true,
"underline": true,
"inline_code": true,
"background_color": 1,
"text_color": 1
}
}
}
Concurrency Handling
Feishu documents support multi-user collaboration, so concurrency must be handled:
- Get the latest revision:
GET /documents/{document_id} - Write with revision:
?document_revision_id={revision} - Retry on conflict(HTTP 409)
Recommended Mermaid workflow
When the user requests "unify Mermaid according to the drawing format in this document", do not directly write plain text blocks or the ```mermaid。
Recommended order:
- First read all blocks in the target document to confirm whether manually adjusted Mermaid diagram blocks already exist
- If it exists, read the block's:
block_typeadd_ons.component_type_idadd_ons.record
- Create a new diagram by reusing the same drawing block structure instead of continuing to write
codeblock - After the new diagram is successfully created, delete the old Mermaid code block to avoid keeping both sets of content in the document
Applicable scenarios:
- The user has manually changed a Mermaid diagram to the ideal style and asks to "change the other diagrams to this format as well"
- Multiple flowcharts need to maintain a consistent visual effect in the same Docx
Practical suggestions
- For ordinary structure, prioritize text blocks/heading blocks
- For code display use
block_type = 14 - For flowchart display, prioritize Mermaid plugin blocks; do not treat ```mermaid as the final presentation form
- When replacing an old diagram, insert the new block first, then delete the old block to avoid content loss
- When batch replacement is involved, first read the parent block's children order, then delete precisely by index
Best practices
- Prioritize the conversion API(simplifies development)
- Batch-create blocks(reduces API calls)
- Handle concurrency conflicts(with revision parameter)
- Images in two steps(placeholder + upload)
- For Mermaid diagrams, prioritize reusing the existing plugin block format