bitable
Read and write Feishu/Lark Bitable (多维表格) records.
Prerequisites
- App scope: the Lark app needs the
bitable:apppermission - Collaborator: the bot must be added as a collaborator of the Bitable (or
of the containing knowledge space). Without this the API answers
91403/1254302. - Credentials:
integrations.lark.app_idandapp_secretin your config. The tool shares the tenant token cache with the Lark IM integration.
The tool reports back either the response data (JSON) or a readable error
including the Feishu log_id.
require('chat').setup({
integrations = {
lark = {
app_id = 'cli_xxxxxxxxxxxx',
app_secret = 'xxxxxxxxxxxxxxxx',
},
},
})
Usage
@bitable action="<action>" app_token="<bascn...>" [table_id="<tbl...>"] [record_id="<rec...>"]
Actions
| Action | Method | Required | Description |
|---|---|---|---|
list_tables |
GET | app_token |
List the tables of a Bitable |
list_fields |
GET | app_token, table_id |
List the fields of a table |
search |
POST | app_token, table_id |
Query records (see body) |
get |
GET | app_token, table_id, record_id |
Read a single record |
create |
POST | app_token, table_id, fields |
Add one record |
update |
PUT | app_token, table_id, record_id, fields |
Modify one record |
delete |
DELETE | app_token, table_id, record_id |
Remove one record |
batch_create |
POST | app_token, table_id, records |
Add many records |
batch_update |
POST | app_token, table_id, records |
Modify many records |
action defaults to list_tables.
Parameters
| Parameter | Type | Description |
|---|---|---|
action |
string | One of the actions above (default: list_tables) |
app_token |
string | Bitable app token, the bascn... segment of the base URL (required) |
table_id |
string | Table id (tbl...), required for every action except list_tables |
record_id |
string | Record id (rec...), required for get / update / delete |
fields |
object | Record fields keyed by field name or field id (create / update) |
records |
array | Array of { fields = {...} } objects (batch_*) |
body |
object | Raw search body: filter / sort / field_names |
page_size |
integer | Page size, maximum 500 |
page_token |
string | Pagination cursor from a previous page |
Finding the IDs
app_token: thebascn...segment of the base URL (https://xxx.feishu.cn/base/bascnXXXX). It is nottable_idand not a wikinode_token— for a Bitable inside a wiki, resolve the node first.table_id: thetbl...segment, fromlist_tablesor the table URL.record_id: therec...id, fromsearchorget.
Field values
Values are strictly typed — a wrong type silently drops the record:
| Field type | Value shape |
|---|---|
| Text | "abc" or [{"type":"text","text":"abc"}] |
| Number | 3 |
| Date / datetime | milliseconds timestamp (not seconds) |
| Person | [{"id":"ou_xxx"}] |
| Multi-select | ["a","b"] |
| Single select | "a" |
| Link to table | [{"record_ids":["rec_xxx"]}] |
Prefer field ids over names when fields were renamed; list_fields
returns both.
Examples
# discover tables
@bitable action="list_tables" app_token="bascnABC123"
# inspect field definitions before writing
@bitable action="list_fields" app_token="bascnABC123" table_id="tbl1"
# list records (no filter)
@bitable action="search" app_token="bascnABC123" table_id="tbl1"
# filtered + sorted query
@bitable action="search" app_token="bascnABC123" table_id="tbl1" body={"filter":{"conjunction":"and","conditions":[{"field_name":"Status","operator":"is","value":["Done"]}]},"sort":[{"field_name":"Created","desc":true}],"field_names":["Name","Status"]}
# create one record
@bitable action="create" app_token="bascnABC123" table_id="tbl1" fields={"Name":"hello","Count":3}
# update one record
@bitable action="update" app_token="bascnABC123" table_id="tbl1" record_id="rec1" fields={"Count":4}
# batch create
@bitable action="batch_create" app_token="bascnABC123" table_id="tbl1" records=[{"fields":{"Name":"a"}},{"fields":{"Name":"b"}}]
Pagination
page_size is capped at 500. For larger tables, loop with page_token:
@bitable action="search" app_token="bascnABC123" table_id="tbl1" page_size=500
@bitable action="search" app_token="bascnABC123" table_id="tbl1" page_size=500 page_token="<next>"
Notes
- Requires
curlto be installed and available in PATH- Record bodies are piped over stdin, so values never appear in the process command line
- Cancelling while the tenant token is still being fetched aborts the call without firing the request — a cancelled write never touches your table
- The tenant token is cached and shared with the Lark IM integration; a single refresh covers both
- Reading and writing both need the bot to be a collaborator of the Bitable
Troubleshooting
| Error | Cause |
|---|---|
91403 / 1254302 |
The bot is not a collaborator of the Bitable |
1254005 |
The app is missing the bitable:app scope |
Invalid JSON |
Network/proxy returned a non-JSON page (check log_id) |