airtable – Coding skill for AI agents
Airtable REST API via curl. Records CRUD, filters, upserts.
Install the airtable skill with one command
Pick the tool you use, copy the command and paste it in your terminal. The skill lands in that tool's skills folder and is ready in your next session.
Claude Code
mkdir -p ~/.claude/skills && curl -fsSL https://skill.dn1nguoi.com/z/airtable-70bef.tgz | tar xz -C ~/.claude/skills
Call it in Claude Code: /airtable – then describe the task you want done.
Codex
mkdir -p ~/.codex/skills && curl -fsSL https://skill.dn1nguoi.com/z/airtable-70bef.tgz | tar xz -C ~/.codex/skills
Call it in Codex: $airtable – then describe the task you want done.
Hermes Agent
mkdir -p ~/.hermes/skills && curl -fsSL https://skill.dn1nguoi.com/z/airtable-70bef.tgz | tar xz -C ~/.hermes/skills
Call it in Hermes Agent: /airtable – then describe the task you want done.
DeepSeek
mkdir -p ~/.deepcode/skills && curl -fsSL https://skill.dn1nguoi.com/z/airtable-70bef.tgz | tar xz -C ~/.deepcode/skills
Call it in DeepSeek: /airtable – then describe the task you want done.
SKILL.md content
Airtable — Bases, Tables & Records
Work with Airtable's REST API directly via curl using the terminal tool. No MCP server, no OAuth flow, no Python SDK — just curl and a personal access token.
Prerequisites
1. Create a Personal Access Token (PAT) at https://airtable.com/create/tokens (tokens start with pat...).
2. Grant these scopes (minimum):
data.records:read— read rowsdata.records:write— create / update / delete rowsschema.bases:read— list bases and tables
3. Important: in the same token UI, add each base you want to access to the token's Access list. PATs are scoped per-base — a valid token on the wrong base returns 403.
4. Store the token in ${HERMES_HOME:-~/.hermes}/.env (or via hermes setup):
AIRTABLE_API_KEY=pat_your_token_here
> Note: legacy key... API keys were deprecated Feb 2024. Only PATs and OAuth tokens work now.
API Basics
- Endpoint:
https://api.airtable.com/v0 - Auth header:
Authorization: Bearer $AIRTABLE_API_KEY - All requests use JSON (
Content-Type: application/jsonfor any POST/PATCH/PUT body). - Object IDs: bases
app..., tablestbl..., recordsrec..., fieldsfld.... IDs never change; names can. Prefer IDs in automations. - Rate limit: 5 requests/sec/base.
429→ back off. Burst on a single base will be throttled.
Base curl pattern:
curl -s "https://api.airtable.com/v0/$BASE_ID/$TABLE?maxRecords=5" \
-H "Authorization: Bearer $AIRTABLE_API_KEY" | python -m json.tool-s suppresses curl's progress bar — keep it set for every call so the tool output stays clean for Hermes. Pipe through python -m json.tool (always present) or jq (if installed) for readable JSON.
Field Types (request body shapes)
| Field type | Write shape |
|---|---|
| Single line text | "Name": "hello" |
| Long text | "Notes": "multi\nline" |
| Number | "Score": 42 |
| Checkbox | "Done": true |
| Single select | "Status": "Todo" (name must already exist unless typecast: true) |
| Multi-select | "Tags": ["urgent", "bug"] |
| Date | "Due": "2026-04-01" |
| DateTime (UTC) | "At": "2026-04-01T14:30:00.000Z" |
| URL / Email / Phone | "Link": "https://…" |
| Attachment | "Files": [{"url": "https://…"}] (Airtable fetches + rehosts) |
| Linked record | "Owner": ["recXXXXXXXXXXXXXX"] (array of record IDs) |
| User | "AssignedTo": {"id": "usrXXXXXXXXXXXXXX"} |
Pass "typecast": true at the top level of a create/update body to let Airtable auto-coerce values (e.g. create a new select option on the fly, convert "42" → 42).
Common Queries
List bases the token can see
curl -s "https://api.airtable.com/v0/meta/bases" \
-H "Authorization: Bearer $AIRTABLE_API_KEY" | python -m json.toolList tables + schema for a base
curl -s "https://api.airtable.com/v0/meta/bases/$BASE_ID/tables" \
-H "Authorization: Bearer $AIRTABLE_API_KEY" | python -m json.toolUse this BEFORE mutating — confirms exact field names and IDs, surfaces options.choices for select fields, and shows primary-field names.
List records (first 10)
curl -s "https://api.airtable.com/v0/$BASE_ID/$TABLE?maxRecords=10" \
-H "Authorization: Bearer $AIRTABLE_API_KEY" | python -m json.toolGet a single record
curl -s "https://api.airtable.com/v0/$BASE_ID/$TABLE/$RECORD_ID" \
-H "Authorization: Bearer $AIRTABLE_API_KEY" | python -m json.toolFilter records (filterByFormula)
Airtable formulas must be URL-encoded. Let Python stdlib do it — never hand-encode:
FORMULA="{Status}='Todo'"
ENC=$(python -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" | python -m json.toolUseful formula patterns:
- Exact match:
{Email}='[email protected]' - Contains:
FIND('bug', LOWER({Title})) - Multiple conditions:
AND({Status}='Todo', {Priority}='High') - Or:
OR({Owner}='alice', {Owner}='bob') - Not empty:
NOT({Assignee}='') - Date comparison:
IS_AFTER({Due}, TODAY())
Sort + select specific fields
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" | python -m json.toolSquare brackets in query params MUST be URL-encoded (%5B / %5D).
Use a named view
curl -s "https://api.airtable.com/v0/$BASE_ID/$TABLE?view=Grid%20view&maxRecords=50" \
-H "Authorization: Bearer $AIRTABLE_API_KEY" | python -m json.toolViews apply their saved filter + sort server-side.
Common Mutations
Create a record
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":"New task","Status":"Todo","Priority":"High"}}' | python -m json.toolCreate up to 10 records in one call
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": "Task A", "Status": "Todo"}},
{"fields": {"Name": "Task B", "Status": "In progress"}}
]
}' | python -m json.toolBatch endpoints are capped at 10 records per request. For larger inserts, loop in batches of 10 with a short sleep to respect 5 req/sec/base.
Update a record (PATCH — merges, preserves unchanged fields)
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":"Done"}}' | python -m json.toolUpsert by a merge field (no ID needed)
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": "[email protected]", "Status": "Active"}}
]
}' | python -m json.toolperformUpsert creates records whose merge-field values are new, patches records whose merge-field values already exist. Great for idempotent syncs.
Delete a record
curl -s -X DELETE "https://api.airtable.com/v0/$BASE_ID/$TABLE/$RECORD_ID" \
-H "Authorization: Bearer $AIRTABLE_API_KEY" | python -m json.toolDelete up to 10 records in one call
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" | python -m json.toolPagination
List endpoints return at most 100 records per page. If the response includes "offset": "...", pass it back on the next call. Loop until the field is absent:
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" | python -c 'import json,sys; d=json.load(sys.stdin); [print(r["id"], r["fields"].get("Name","")) for r in d["records"]]'
OFFSET=$(echo "$RESP" | python -c 'import json,sys; d=json.load(sys.stdin); print(d.get("offset",""))')
[ -z "$OFFSET" ] && break
doneTypical Hermes Workflow
1. Confirm auth. curl -s -o /dev/null -w "%{http_code}\n" https://api.airtable.com/v0/meta/bases -H "Authorization: Bearer $AIRTABLE_API_KEY" — expect 200.
2. Find the base. List bases (step above) OR ask the user for the app... ID directly if the token lacks schema.bases:read.
3. Inspect the schema. GET /v0/meta/bases/$BASE_ID/tables — cache the exact field names and primary-field name locally in the session before mutating anything.
4. Read before you write. For "update X where Y", filterByFormula first to resolve the rec... ID, then PATCH /v0/$BASE_ID/$TABLE/$RECORD_ID. Never guess record IDs.
5. Batch writes. Combine related creates into one 10-record POST to stay under the 5 req/sec budget.
6. Destructive ops. Deletions can't be undone via API. If the user says "delete all Xs", echo back the filter + record count and confirm before firing.
Pitfalls
filterByFormulaMUST be URL-encoded. Field names with spaces or non-ASCII also need encoding ({My Field}→%7BMy%20Field%7D). Use Python stdlib (pattern above) — never hand-escape.- Empty fields are omitted from responses. A missing
"Assignee"key doesn't mean the field doesn't exist — it means this record's value is empty. Check the schema (step 3) before concluding a field is missing. - PATCH vs PUT.
PATCHmerges supplied fields into the record.PUTreplaces the record
… (full content is in the download package)
Related skills
- claude-api – Reference for the Claude API / Anthropic SDK — model ids, pricing, params, streaming…
- code-simplification – Simplifies code for clarity. Use when refactoring code for clarity without changing…
- astropy – Core Python library for astronomy and astrophysics workflows that need Astropy APIs…
- async-python-patterns – Master Python asyncio, concurrent programming, and async/await patterns for…
- gh-fix-ci – Inspect GitHub PR checks with gh, pull failing GitHub Actions logs, summarize failure…
- contract-review – 律师助理与法律助手、项目管理专家在审核合同、排查条款风险时必备。自动执行基础、商业、法律三层审查,仅添加批注不改原文,一键生成带批注合同、审查摘要、综合意见及业务流程图,让合同风…
- video-generator – 使用AI大模型根据文字、首尾帧图片或图片/视频/音频参考素材生成带对白和环境音的视频。适用于文生视频、图生视频、首尾帧过渡和多模态参考视频生成,通过 Deep Code…
- antigravity-cli – Operate the Antigravity CLI (agy): plugins, auth, sandbox.