Overview
This skill uploads files to Feishu (Lark) Bitable attachment fields through the material upload flow:
- Get source file (local copy, URL download, or Feishu message download)
- Upload to Bitable upload endpoint with
parent_type=bitable_file
- Get
file_token from upload response
- Create/Update record with attachment field
Key design: This is a general-purpose skill for ANY Bitable your app can access. Nothing is hardcoded.
Verification Status
Local Tests Passed
Requires Real Environment Verification
If any API calls fail in your environment, check references/feishu-api-notes.md for extensibility points.
Supported Source Types
| Type | Description | Example |
|---|
local | Local file path | {"type": "local", "ref": "/tmp/file.pdf"} |
url | Download from HTTP(S) URL | {"type": "url", "ref": "https://example.com/file.pdf"} |
feishu_message | Feishu message attachment | {"type": "feishu_message", "ref": {"file_key": "file_xxx"}} |
Target Resolution
This skill supports flexible target specification to work with any Bitable:
Table Specification (priority: table_id > table_name)
- Provide
table_id directly for fastest resolution
- Or provide
table_name for automatic lookup (lists all tables and matches by name)
Field Specification (priority: field_id > field_name)
- Provide
field_id directly for fastest resolution
- Or provide
field_name for automatic lookup (lists all fields and matches by name)
Record Specification
- Provide
record_id to update existing record
- Or provide
lookup to search for record by field value
- Or omit both to create new record
Input JSON Structure
{
"target": {
"app_token": "bascxxxxxxxxxxxxx",
"table_id": "tblxxxxxxxxxx",
"table_name": "",
"record_id": "recxxxxxxxxxx",
"field_id": "fldxxxxxxxxxx",
"field_name": "附件",
"lookup": {
"field_name": "合同编号",
"field_id": "",
"value": "HT-2026-001"
},
"allow_create_if_lookup_missing": false
},
"source": {
"type": "local",
"ref": "/path/to/file.pdf"
},
"append": true
}
Target Parameters
| Parameter | Required | Description |
|---|
app_token | Yes | Bitable app token (basc...) |
table_id | No* | Table ID (tbl...). *Required if table_name not provided |
table_name | No* | Table display name. *Required if table_id not provided |
record_id | No | Record ID (rec...). Leave empty to create new record |
field_id | No* | Field ID. *Required if field_name not provided |
field_name | No* | Field display name. *Required if field_id not provided |
lookup | No | Config to find record_id by searching |
allow_create_if_lookup_missing | No | If true, create new record when lookup finds nothing |
Lookup Config
"lookup": {
"field_name": "合同编号",
"field_id": "",
"value": "HT-2026-001"
}
Source Parameters
| Parameter | Required | Description |
|---|
type | Yes | One of: local, url, feishu_message |
ref | Yes | local: file path / url: download URL / feishu_message: {file_key, filename} |
Append Mode
| Value | Behavior |
|---|
true | Read existing attachments, append new file to the list |
false | Replace attachment field with new file only |
Upload Flow
Small Files (≤20MB)
Direct upload to material endpoint:
POST /open-apis/drive/v1/upload
multipart/form-data fields:
- file: <file content>
- file_name: filename
- size: file size in bytes
- parent_type: bitable_file
- parent_node: {app_token}
- extra: {"drive_route_token": "{app_token}"}
Large Files (>20MB)
Chunked upload in 5MB parts:
POST /open-apis/drive/v1/chunked_upload/prepare → upload_id
POST /open-apis/drive/v1/chunked_upload (per part) → etag
POST /open-apis/drive/v1/chunked_upload/finish → file_token
Environment Variables
Set these before running:
export FEISHU_APP_ID=your_app_id
export FEISHU_APP_SECRET=your_app_secret
export FEISHU_BASE_URL=https://open.feishu.cn # optional
Usage Examples
Local file with known record_id
python scripts/main.py --input payload.local.json
URL download with replace mode
python scripts/main.py --input payload.url.json
Feishu message attachment
python scripts/main.py --input payload.feishu_message.json
Auto-resolve table by name
python scripts/main.py --input payload.table_name.json
Lookup record by field value
python scripts/main.py --input payload.lookup.json
Create new record with attachment
python scripts/main.py --input payload.create_record.json
Basic Verification
Run syntax check before use:
python -m py_compile scripts/*.py
This verifies:
- All Python modules have valid syntax
- No undefined variables or imports
Output
Success
{
"ok": true,
"file_token": "vobxxxxxxxxxx",
"app_token": "bascxxxxxxxxxx",
"table_id": "tblxxxxxxxxxx",
"table_name": "合同归档",
"record_id": "recxxxxxxxxxx",
"field_name": "附件",
"field_id": "fldxxxxxxxxxx",
"upload_type": "direct",
"attachment_count": 3,
"mode": "append",
"message": "Successfully uploaded 'report.pdf'..."
}
Error
{
"ok": false,
"error": "Table 'xxx' not found. Available tables: 表 1, 表 2",
"error_type": "resolve_error"
}
Common Errors
| Error Type | Cause | Solution |
|---|
file_not_found | Local file does not exist | Check file path |
download_failed | URL download failed | Verify URL accessibility |
input_error | Invalid parameters | Check input JSON structure |
auth_error | Invalid credentials | Check FEISHU_APP_ID/SECRET |
upload_error | Upload failed | Check app permissions |
resolve_error | Table/field/record not found | Verify names or IDs |
update_error | Record update failed | Check record exists |
Why This Skill Works with Any Bitable
This skill is not hardcoded to a specific Bitable:
- Dynamic app_token: Read from input, not hardcoded
- Dynamic table resolution: Supports table_id (direct) or table_name (API lookup)
- Dynamic field resolution: Supports field_id (direct) or field_name (API lookup)
- Dynamic record resolution: Supports record_id, lookup search, or create-new mode
References
See references/feishu-api-notes.md for:
- Why file_token from IM/Drive cannot be reused directly
- Why upload to bitable_file upload point is required
- API implementation notes and extensibility points
- Known uncertainties that may need environment-specific verification