| 用户 | `"AssignedTo": {"id": "usrXXXXXXXXXXXXXX"}` |
在创建/更新请求体的顶层传入 "typecast": true,让 Airtable 自动转换值(例如,即时创建新的选项、将 "42" 转为 42)。
常用查询
列出令牌可见的库
curl -s "https://api.airtable.com/v0/meta/bases"
-H "Authorization: Bearer $AIRTABLE_API_KEY" | python3 -m json.tool
列出库的表和模式
curl -s "https://api.airtable.com/v0/meta/bases/$BASE_ID/tables"
-H "Authorization: Bearer $AIRTABLE_API_KEY" | python3 -m json.tool
在执行修改前使用此命令——确认确切的字段名称和 ID、显示选择字段的 options.choices、以及主字段名称。
列出记录(前10条)
curl -s "https://api.airtable.com/v0/$BASE_ID/$TABLE?maxRecords=10"
-H "Authorization: Bearer $AIRTABLE_API_KEY" | python3 -m json.tool
获取单条记录
curl -s "https://api.airtable.com/v0/$BASE_ID/$TABLE/$RECORD_ID"
-H "Authorization: Bearer $AIRTABLE_API_KEY" | python3 -m json.tool
筛选记录(filterByFormula)
Airtable 公式必须进行 URL 编码。使用 Python 标准库处理——不要手动编码:
FORMULA="{Status}='Todo'"
ENC=$(python3 -c 'import sys, urllib.parse; print(urllib.parse.quote(sys.argv[1], safe=""))' "$FORMULA")
curl -s "https://api.airtable.com/v0/$BASE_ID/$TABLE?filterByFormula=$ENC&maxRecords=20"
-H "Authorization: Bearer $AIRTABLE_API_KEY" | python3 -m json.tool
常用公式模式:
精确匹配:{Email}='user@example.com'
包含:FIND('bug', LOWER({Title}))
多条件:AND({Status}='Todo', {Priority}='High')
或:OR({Owner}='alice', {Owner}='bob')
非空:NOT({Assignee}='')
日期比较:IS_AFTER({Due}, TODAY())
排序 + 选择特定字段
curl -s "https://api.airtable.com/v0/$BASE_ID/$TABLE?sort%5B0%5D%5Bfield%5D=Priority&sort%5B0%5D%5Bdirection%5D=asc&fields%5B%5D=Name&fields%5B%5D=Status"
-H "Authorization: Bearer $AIRTABLE_API_KEY" | python3 -m json.tool
查询参数中的方括号必须进行 URL 编码(%5B / %5D)。
使用命名视图
curl -s "https://api.airtable.com/v0/$BASE_ID/$TABLE?view=Grid%20view&maxRecords=50"
-H "Authorization: Bearer $AIRTABLE_API_KEY" | python3 -m json.tool
视图会在服务端应用其已保存的筛选 + 排序。
常用修改操作
创建一条记录
curl -s -X POST "https://api.airtable.com/v0/$BASE_ID/$TABLE"
-H "Authorization: Bearer $AIRTABLE_API_KEY"
-H "Content-Type: application/json"
-d '{"fields":{"Name":"新任务","Status":"待办","Priority":"高"}}' | python3 -m json.tool
一次创建最多 10 条记录
curl -s -X POST "https://api.airtable.com/v0/$BASE_ID/$TABLE"
-H "Authorization: Bearer $AIRTABLE_API_KEY"
-H "Content-Type: application/json"
-d '{
"typecast": true,
"records": [
{"fields": {"Name": "任务 A", "Status": "待办"}},
{"fields": {"Name": "任务 B", "Status": "进行中"}}
]
}' | python3 -m json.tool
批量端点每次最多 10 条记录。对于更大批量的插入,循环以 10 条为批次并短暂休眠,遵守 5次/秒/库 的限制。
更新记录(PATCH — 合并更新,保留未更改的字段)
curl -s -X PATCH "https://api.airtable.com/v0/$BASE_ID/$TABLE/$RECORD_ID"
-H "Authorization: Bearer $AIRTABLE_API_KEY"
-H "Content-Type: application/json"
-d '{"fields":{"Status":"已完成"}}' | python3 -m json.tool
通过合并字段进行 Upsert(无需 ID)
curl -s -X PATCH "https://api.airtable.com/v0/$BASE_ID/$TABLE"
-H "Authorization: Bearer $AIRTABLE_API_KEY"
-H "Content-Type: application/json"
-d '{
"performUpsert": {"fieldsToMergeOn": ["Email"]},
"records": [
{"fields": {"Email": "user@example.com", "Status": "活跃"}}
]
}' | python3 -m json.tool
performUpsert 对合并字段值不存在的记录执行创建,对已存在的记录执行更新。非常适合幂等同步。
删除一条记录
curl -s -X DELETE "https://api.airtable.com/v0/$BASE_ID/$TABLE/$RECORD_ID"
-H "Authorization: Bearer $AIRTABLE_API_KEY" | python3 -m json.tool
一次删除最多 10 条记录
curl -s -X DELETE "https://api.airtable.com/v0/$BASE_ID/$TABLE?records%5B%5D=rec1&records%5B%5D=rec2"
-H "Authorization: Bearer $AIRTABLE_API_KEY" | python3 -m json.tool
分页
列表端点每页最多返回 100 条记录。如果响应中包含 "offset": "...",在下次请求中传回它。循环直到该字段不存在:
OFFSET=""
while :; do
URL="https://api.airtable.com/v0/$BASE_ID/$TABLE?pageSize=100"
[ -n "$OFFSET" ] && URL="$URL&offset=$OFFSET"
RESP=$(curl -s "$URL" -H "Authorization: Bearer $AIRTABLE_API_KEY")
echo "$RESP" | python3 -c 'import json,sys; d=json.load(sys.stdin); [print(r["id"], r["fields"].get("Name","")) for r in d["records"]]'
OFFSET=$(echo "$RESP" | python3 -c 'import json,sys; d=json.load(sys.stdin); print(d.get("offset",""))')
[ -z "$OFFSET" ] && break
done
典型 Hermes 工作流程
确认认证。 curl -s -o /dev/null -w "%{http_code}n" https://api.airtable.com/v0/meta/bases -H "Authorization: Bearer $AIRTABLE_API_KEY" — 预期返回 200。
找到库。 列出库(如上步骤)或如果令牌缺少 schema.bases:read,直接询问用户提供 app... ID。
检查模式。 GET /v0/meta/bases/$BASE_ID/tables — 在执行任何修改操作之前,在会话中缓存确切的字段名称和主字段名称。
先读后写。 对于"更新满足条件 Y 的 X",先用 filterByFormula 解析出 rec... ID,然后执行 PATCH /v0/$BASE_ID/$TABLE/$RECORD_ID。切勿猜测记录 ID。
批量写入。 将相关的创建合并为一次 10 条记录的 POST,保持在 5次/秒 的预算内。
破坏性操作。 通过 API 删除的数据无法撤销。如果用户说"删除所有 X",先回显筛选条件和记录数量,确认后再执行。
常见陷阱
filterByFormula 必须进行 URL 编码。 包含空格或非 ASCII 字符的字段名也需要编码({我的字段} → %7B%E6%88%91%E7%9A%84%E5%AD%97%E6%AE%B5%7D)。使用 Python 标准库(参考上方模式)——切勿手动转义。
空字段在响应中会被省略。 缺少 "Assignee" 键并不意味着字段不存在——而是这条记录该字段的值为空。在断定字段缺失之前先检查模式(第3步)。
PATCH vs PUT。 PATCH 将提供字段合并到记录中。PUT 完全替换记录并清空未提供的字段。默认使用 PATCH。
单选选项必须存在。 当 Shipping 不在该字段的选项列表中时,写入 "Status": "Shipping" 会报错 INVALID_MULTIPLE_CHOICE_OPTIONS,除非传入 "typecast": true(会自动创建选项)。
按库限定的令牌范围。 在一个库上返回 403 而另一个库正常,意味着令牌的访问范围列表不包含该库——不是权限或认证问题。请用户前往 https://airtable.com/create/tokens 授予访问权限。
速率限制是按库计算的,而非按令牌。 在 baseA 上每秒 5 次请求、在 baseB 上每秒 5 次请求是可以的;仅在 baseA 上每秒 6 次请求会被限流。收到 429 时关注 Retry-After 响应头。
Hermes 重要说明
始终使用 terminal 工具配合 curl。 不要使用 web_extract(无法发送认证头)或 browser_navigate(需要 UI 认证且速度慢)。
加载此技能时,AIRTABLE_API_KEY 会自动从 ~/.hermes/.env 流入子进程——无需在每次 curl 调用前重新导出。
在公式中仔细转义花括号。 在 heredoc 体中,{Status} 是原文字面值。在 shell 参数中,{Status} 在大括号展开上下文之外是安全的——但在拼接到 URL 之前,将动态字符串通过 python3 urllib.parse.quote 处理。
使用 python3 -m json.tool 格式化输出(始终可用),而非 jq(可选)。仅在需要过滤/投影时才使用 jq。
分页是按页的,不是全局的。 Airtable 的 100 条记录是硬限制;无法提高。循环使用 offset 直到该字段不再出现。
在非 2xx 响应上读取 errors 数组——Airtable 返回结构化错误代码,如 AUTHENTICATION_REQUIRED、INVALID_PERMISSIONS、MODEL_ID_NOT_FOUND、INVALID_MULTIPLE_CHOICE_OPTIONS,可以精确告诉你问题所在。
评论区