Back to skills
SkillHub ClubAnalyze Data & AIFull StackData / AI

feishu-sheets

Feishu online spreadsheet (Sheets) operations including create, read, write, append data, manage worksheets. Use when user mentions Feishu Sheets, online spreadsheet, electronic spreadsheet (not Bitable/multi-dimensional table). Supports: create spreadsheet, write/read cell values, append rows, insert/delete rows/columns, manage worksheets.

Packaged view

This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.

Stars
2,902
Hot score
99
Updated
March 20, 2026
Overall rating
C4.0
Composite score
4.0
Best-practice grade
B78.7

Install command

npx @skill-hub/cli install openclaw-skills-feishu-sheets-skill

Repository

openclaw/skills

Skill path: skills/hewenqiang/feishu-skills-kit/skills/feishu-sheets-skill

Feishu online spreadsheet (Sheets) operations including create, read, write, append data, manage worksheets. Use when user mentions Feishu Sheets, online spreadsheet, electronic spreadsheet (not Bitable/multi-dimensional table). Supports: create spreadsheet, write/read cell values, append rows, insert/delete rows/columns, manage worksheets.

Open repository

Best for

Primary workflow: Analyze Data & AI.

Technical facets: Full Stack, Data / AI.

Target audience: everyone.

License: Unknown.

Original source

Catalog source: SkillHub Club.

Repository owner: openclaw.

This is still a mirrored public skill entry. Review the repository before installing into production workflows.

What it helps with

  • Install feishu-sheets into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
  • Review https://github.com/openclaw/skills before adding feishu-sheets to shared team environments
  • Use feishu-sheets for development workflows

Works across

Claude CodeCodex CLIGemini CLIOpenCode

Favorites: 0.

Sub-skills: 0.

Aggregator: No.

Original source / Raw SKILL.md

---
name: feishu-sheets
description: |
  Feishu online spreadsheet (Sheets) operations including create, read, write, append data, manage worksheets.
  Use when user mentions Feishu Sheets, online spreadsheet, electronic spreadsheet (not Bitable/multi-dimensional table).
  Supports: create spreadsheet, write/read cell values, append rows, insert/delete rows/columns, manage worksheets.
---

# Feishu Sheets Tool

Single tool `feishu_sheets` with action parameter for all spreadsheet operations.

## Token Extraction

From URL `https://xxx.feishu.cn/sheets/shtABC123` → `spreadsheet_token` = `shtABC123`

## Actions

### Create Spreadsheet

```json
{ "action": "create", "title": "New Spreadsheet" }
```

Optional folder:
```json
{ "action": "create", "title": "New Spreadsheet", "folder_token": "fldcnXXX" }
```

Returns: spreadsheet_token, url, title

### Write Values

```json
{
  "action": "write",
  "spreadsheet_token": "shtABC123",
  "sheet_id": "0bxxxx",
  "range": "A1:C3",
  "values": [["Name", "Age", "City"], ["Alice", 25, "Beijing"], ["Bob", 30, "Shanghai"]]
}
```

### Read Values

```json
{
  "action": "read",
  "spreadsheet_token": "shtABC123",
  "sheet_id": "0bxxxx",
  "range": "A1:C10"
}
```

### Append Values

```json
{
  "action": "append",
  "spreadsheet_token": "shtABC123",
  "sheet_id": "0bxxxx",
  "values": [["Charlie", 28, "Shenzhen"]]
}
```

### Insert Rows/Columns

```json
{
  "action": "insert_dimension",
  "spreadsheet_token": "shtABC123",
  "sheet_id": "0bxxxx",
  "dimension": "ROWS",
  "start_index": 5,
  "end_index": 7
}
```

### Delete Rows/Columns

```json
{
  "action": "delete_dimension",
  "spreadsheet_token": "shtABC123",
  "sheet_id": "0bxxxx",
  "dimension": "ROWS",
  "start_index": 5,
  "end_index": 7
}
```

### Get Spreadsheet Info

```json
{ "action": "get_info", "spreadsheet_token": "shtABC123" }
```

Returns: metadata including all sheet_ids and titles

### Add Worksheet

```json
{
  "action": "add_sheet",
  "spreadsheet_token": "shtABC123",
  "title": "Sheet2"
}
```

### Delete Worksheet

```json
{
  "action": "delete_sheet",
  "spreadsheet_token": "shtABC123",
  "sheet_id": "0bxxxx"
}
```

## Range Format

- Cell: `A1`, `B5`
- Range: `A1:C10`, `B2:D5`
- Entire column: `A:A`, `B:D`
- Entire row: `1:1`, `3:5`
- With sheet_id: `0bxxxx!A1:C10`

## Sheet ID

- From URL: `https://xxx.feishu.cn/sheets/shtABC123?sheet=0bxxxx`
- From get_info action
- Default first sheet often has simple id like `0bxxxx`

## Data Types

Values can be:
- String: `"Hello"`
- Number: `123`, `45.67`
- Formula: `{"type": "formula", "text": "=SUM(A1:A10)"}`
- Link: `{"type": "url", "text": "Click here", "link": "https://..."}`

## Configuration

```yaml
channels:
  feishu:
    tools:
      sheets: true  # default: true
```

## Permissions Required

- `sheets:spreadsheet` - Create and manage spreadsheets
- `sheets:spreadsheet:readonly` - Read spreadsheet data
- `drive:drive` - Access cloud storage

## API Reference

Base URL: `https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/`

See references/api-reference.md for detailed API documentation.


---

## Skill Companion Files

> Additional files collected from the skill directory layout.

### _meta.json

```json
{
  "ownerId": "kn710qwp94vjc36crngn15sfq9819j6c",
  "slug": "feishu-sheets-skill",
  "version": "1.0.0",
  "publishedAt": 1771220240776
}
```

### references/api-reference.md

```markdown
# Feishu Sheets API Reference

## Base URLs

- Sheets API v2: `https://open.feishu.cn/open-apis/sheets/v2/spreadsheets`
- Sheets API v3: `https://open.feishu.cn/open-apis/sheets/v3/spreadsheets`
- Auth API: `https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal`

## Authentication

All API calls require a tenant access token in the Authorization header:
```
Authorization: Bearer {tenant_access_token}
```

Get token by calling auth API with app_id and app_secret.

## Core APIs

### 1. Create Spreadsheet

**Endpoint:** `POST /sheets/v3/spreadsheets`

**Request Body:**
```json
{
  "title": "Spreadsheet Name",
  "folder_token": "fldcnXXX"  // optional
}
```

**Response:**
```json
{
  "code": 0,
  "msg": "success",
  "data": {
    "spreadsheet": {
      "title": "Spreadsheet Name",
      "spreadsheet_token": "shtcnXXX",
      "url": "https://xxx.feishu.cn/sheets/shtcnXXX"
    }
  }
}
```

### 2. Get Spreadsheet Info

**Endpoint:** `GET /sheets/v2/spreadsheets/{spreadsheet_token}/metainfo`

**Response:**
```json
{
  "code": 0,
  "data": {
    "properties": {
      "title": "Spreadsheet Name"
    },
    "sheets": [
      {
        "sheet_id": "0bxxxx",
        "title": "Sheet1",
        "grid_properties": {
          "row_count": 1000,
          "column_count": 20
        }
      }
    ]
  }
}
```

### 3. Read Values

**Endpoint:** `GET /sheets/v2/spreadsheets/{spreadsheet_token}/values/{range}`

**Range Formats:**
- `A1:C10` - Cell range
- `0bxxxx!A1:C10` - With sheet_id
- `Sheet1!A1:C10` - With sheet title

**Response:**
```json
{
  "code": 0,
  "data": {
    "range": "0bxxxx!A1:C3",
    "values": [
      ["Name", "Age", "City"],
      ["Alice", 25, "Beijing"],
      ["Bob", 30, "Shanghai"]
    ]
  }
}
```

### 4. Write Values

**Endpoint:** `PUT /sheets/v2/spreadsheets/{spreadsheet_token}/values`

**Request Body:**
```json
{
  "valueRange": {
    "range": "0bxxxx!A1:C3",
    "values": [
      ["Name", "Age", "City"],
      ["Alice", 25, "Beijing"],
      ["Bob", 30, "Shanghai"]
    ]
  }
}
```

### 5. Append Values

**Endpoint:** `POST /sheets/v2/spreadsheets/{spreadsheet_token}/values_append`

**Request Body:**
```json
{
  "valueRange": {
    "range": "0bxxxx",
    "values": [
      ["Charlie", 28, "Shenzhen"]
    ]
  }
}
```

### 6. Insert Rows/Columns

**Endpoint:** `POST /sheets/v2/spreadsheets/{spreadsheet_token}/insert_dimension_range`

**Request Body:**
```json
{
  "dimension": {
    "sheetId": "0bxxxx",
    "majorDimension": "ROWS",  // or "COLUMNS"
    "startIndex": 5,
    "endIndex": 7
  }
}
```

### 7. Delete Rows/Columns

**Endpoint:** `DELETE /sheets/v2/spreadsheets/{spreadsheet_token}/dimension_range`

**Request Body:** Same as insert

### 8. Add Worksheet

**Endpoint:** `POST /sheets/v2/spreadsheets/{spreadsheet_token}/sheets_batch_update`

**Request Body:**
```json
{
  "requests": [{
    "addSheet": {
      "properties": {
        "title": "New Sheet"
      }
    }
  }]
}
```

### 9. Delete Worksheet

**Endpoint:** `POST /sheets/v2/spreadsheets/{spreadsheet_token}/sheets_batch_update`

**Request Body:**
```json
{
  "requests": [{
    "deleteSheet": {
      "sheetId": "0bxxxx"
    }
  }]
}
```

## Data Types

### Cell Values

**String:**
```json
"Hello World"
```

**Number:**
```json
123
45.67
```

**Formula:**
```json
{
  "type": "formula",
  "text": "=SUM(A1:A10)"
}
```

**Hyperlink:**
```json
{
  "type": "url",
  "text": "Click here",
  "link": "https://example.com"
}
```

## Error Codes

| Code | Message | Description |
|------|---------|-------------|
| 0 | success | Request successful |
| 10001 | bad request | Invalid parameters |
| 10002 | unauthorized | Invalid or expired token |
| 10003 | forbidden | Insufficient permissions |
| 10004 | not found | Spreadsheet or sheet not found |
| 10005 | internal error | Server error |

## Rate Limits

- Default: 100 requests per minute per app
- Bulk operations (batch_update): 20 requests per minute

## Best Practices

1. **Reuse token:** Cache tenant_access_token for up to 2 hours
2. **Batch operations:** Use batch_update for multiple changes
3. **Range selection:** Be specific with ranges to reduce data transfer
4. **Error handling:** Always check response code before processing data
5. **Sheet ID:** Use sheet_id (not title) for reliable operations

```

### scripts/feishu_sheets.py

```python
#!/usr/bin/env python3
"""
Feishu Sheets API Client
Supports: create, read, write, append, insert/delete rows/columns
"""

import os
import sys
import json
import requests
from typing import List, Dict, Any, Optional

# API Base URLs
BASE_URL = "https://open.feishu.cn/open-apis"
SHEETS_API = f"{BASE_URL}/sheets/v2/spreadsheets"
AUTH_API = f"{BASE_URL}/auth/v3/tenant_access_token/internal"

class FeishuSheetsClient:
    def __init__(self):
        self.app_id = os.getenv("FEISHU_APP_ID")
        self.app_secret = os.getenv("FEISHU_APP_SECRET")
        self._token = None
        
    def _get_token(self) -> str:
        """Get tenant access token"""
        if self._token:
            return self._token
            
        resp = requests.post(AUTH_API, json={
            "app_id": self.app_id,
            "app_secret": self.app_secret
        })
        resp.raise_for_status()
        data = resp.json()
        
        if data.get("code") != 0:
            raise Exception(f"Auth failed: {data}")
            
        self._token = data["tenant_access_token"]
        return self._token
        
    def _headers(self) -> Dict[str, str]:
        return {
            "Authorization": f"Bearer {self._get_token()}",
            "Content-Type": "application/json"
        }
        
    def create_spreadsheet(self, title: str, folder_token: Optional[str] = None) -> Dict:
        """Create a new spreadsheet"""
        url = f"{BASE_URL}/sheets/v3/spreadsheets"
        payload = {"title": title}
        if folder_token:
            payload["folder_token"] = folder_token
            
        resp = requests.post(url, headers=self._headers(), json=payload)
        resp.raise_for_status()
        return resp.json()
        
    def get_spreadsheet_info(self, spreadsheet_token: str) -> Dict:
        """Get spreadsheet metadata including sheets"""
        url = f"{SHEETS_API}/{spreadsheet_token}/metainfo"
        resp = requests.get(url, headers=self._headers())
        resp.raise_for_status()
        return resp.json()
        
    def read_values(self, spreadsheet_token: str, sheet_id: str, range_str: str) -> Dict:
        """Read values from a range"""
        range_param = f"{sheet_id}!{range_str}" if sheet_id else range_str
        url = f"{SHEETS_API}/{spreadsheet_token}/values/{range_param}"
        resp = requests.get(url, headers=self._headers())
        resp.raise_for_status()
        return resp.json()
        
    def write_values(self, spreadsheet_token: str, sheet_id: str, 
                     range_str: str, values: List[List[Any]]) -> Dict:
        """Write values to a range"""
        url = f"{SHEETS_API}/{spreadsheet_token}/values"
        range_param = f"{sheet_id}!{range_str}" if sheet_id else range_str
        payload = {
            "valueRange": {
                "range": range_param,
                "values": values
            }
        }
        resp = requests.put(url, headers=self._headers(), json=payload)
        resp.raise_for_status()
        return resp.json()
        
    def append_values(self, spreadsheet_token: str, sheet_id: str, 
                      values: List[List[Any]]) -> Dict:
        """Append values to the end of sheet"""
        url = f"{SHEETS_API}/{spreadsheet_token}/values_append"
        payload = {
            "valueRange": {
                "range": sheet_id,
                "values": values
            }
        }
        resp = requests.post(url, headers=self._headers(), json=payload)
        resp.raise_for_status()
        return resp.json()
        
    def insert_dimension(self, spreadsheet_token: str, sheet_id: str,
                        dimension: str, start_index: int, end_index: int) -> Dict:
        """Insert rows or columns"""
        url = f"{SHEETS_API}/{spreadsheet_token}/insert_dimension_range"
        payload = {
            "dimension": {
                "sheetId": sheet_id,
                "majorDimension": dimension,  # ROWS or COLUMNS
                "startIndex": start_index,
                "endIndex": end_index
            }
        }
        resp = requests.post(url, headers=self._headers(), json=payload)
        resp.raise_for_status()
        return resp.json()
        
    def delete_dimension(self, spreadsheet_token: str, sheet_id: str,
                        dimension: str, start_index: int, end_index: int) -> Dict:
        """Delete rows or columns"""
        url = f"{SHEETS_API}/{spreadsheet_token}/dimension_range"
        payload = {
            "dimension": {
                "sheetId": sheet_id,
                "majorDimension": dimension,
                "startIndex": start_index,
                "endIndex": end_index
            }
        }
        resp = requests.delete(url, headers=self._headers(), json=payload)
        resp.raise_for_status()
        return resp.json()
        
    def add_sheet(self, spreadsheet_token: str, title: str) -> Dict:
        """Add a new worksheet"""
        url = f"{SHEETS_API}/{spreadsheet_token}/sheets_batch_update"
        payload = {
            "requests": [{
                "addSheet": {
                    "properties": {"title": title}
                }
            }]
        }
        resp = requests.post(url, headers=self._headers(), json=payload)
        resp.raise_for_status()
        return resp.json()
        
    def delete_sheet(self, spreadsheet_token: str, sheet_id: str) -> Dict:
        """Delete a worksheet"""
        url = f"{SHEETS_API}/{spreadsheet_token}/sheets_batch_update"
        payload = {
            "requests": [{
                "deleteSheet": {"sheetId": sheet_id}
            }]
        }
        resp = requests.post(url, headers=self._headers(), json=payload)
        resp.raise_for_status()
        return resp.json()


def main():
    """CLI entry point for tool calls"""
    if len(sys.argv) < 2:
        print(json.dumps({"error": "No action specified"}))
        sys.exit(1)
        
    action = sys.argv[1]
    client = FeishuSheetsClient()
    
    try:
        if action == "create":
            title = sys.argv[2]
            folder = sys.argv[3] if len(sys.argv) > 3 else None
            result = client.create_spreadsheet(title, folder)
            
        elif action == "get_info":
            token = sys.argv[2]
            result = client.get_spreadsheet_info(token)
            
        elif action == "read":
            token = sys.argv[2]
            sheet_id = sys.argv[3]
            range_str = sys.argv[4]
            result = client.read_values(token, sheet_id, range_str)
            
        elif action == "write":
            token = sys.argv[2]
            sheet_id = sys.argv[3]
            range_str = sys.argv[4]
            values = json.loads(sys.argv[5])
            result = client.write_values(token, sheet_id, range_str, values)
            
        elif action == "append":
            token = sys.argv[2]
            sheet_id = sys.argv[3]
            values = json.loads(sys.argv[4])
            result = client.append_values(token, sheet_id, values)
            
        elif action == "insert_dimension":
            token = sys.argv[2]
            sheet_id = sys.argv[3]
            dimension = sys.argv[4]
            start = int(sys.argv[5])
            end = int(sys.argv[6])
            result = client.insert_dimension(token, sheet_id, dimension, start, end)
            
        elif action == "delete_dimension":
            token = sys.argv[2]
            sheet_id = sys.argv[3]
            dimension = sys.argv[4]
            start = int(sys.argv[5])
            end = int(sys.argv[6])
            result = client.delete_dimension(token, sheet_id, dimension, start, end)
            
        elif action == "add_sheet":
            token = sys.argv[2]
            title = sys.argv[3]
            result = client.add_sheet(token, title)
            
        elif action == "delete_sheet":
            token = sys.argv[2]
            sheet_id = sys.argv[3]
            result = client.delete_sheet(token, sheet_id)
            
        else:
            result = {"error": f"Unknown action: {action}"}
            
        print(json.dumps(result, ensure_ascii=False, indent=2))
        
    except Exception as e:
        print(json.dumps({"error": str(e)}, ensure_ascii=False))
        sys.exit(1)


if __name__ == "__main__":
    main()

```

feishu-sheets | SkillHub