Airtable
REST API Airtable через curl. CRUD-операции над записями, фильтры, upsert.
Метаданные навыка
| Источник | Встроенный (установлен по умолчанию) |
| Путь | skills/productivity/airtable |
| Версия | 1.1.0 |
| Автор | community |
| Лицензия | MIT |
| Платформы | linux, macos, windows |
| Теги | Airtable, Productivity, Database, API |
Справочник: полный SKILL.md
Ниже приведено полное определение навыка, которое Hermes загружает при срабатывании этого навыка. Именно это агент видит как инструкции, пока навык активен.
Airtable — базы, таблицы и записи
Работа с REST API Airtable напрямую через curl с помощью инструмента terminal. Без MCP-сервера, без OAuth-потока, без Python SDK — только curl и персональный токен доступа.
Требования
- Создайте персональный токен доступа (PAT) на https://airtable.com/create/tokens (токены начинаются с
pat...). - Выдайте как минимум такие права (scopes):
data.records:read— чтение строкdata.records:write— создание / обновление / удаление строкschema.bases:read— получение списка баз и таблиц
- Важно: в том же интерфейсе токена добавьте каждую нужную базу в список Access токена. PAT привязаны к конкретным базам — валидный токен на чужой базе вернёт
403. - Сохраните токен в
~/.hermes/.env(или черезhermes setup):AIRTABLE_API_KEY=pat_your_token_here
Примечание: старые API-ключи вида
key...отключены в феврале 2024 года. Сейчас работают только PAT и токены OAuth.
Основы API
- Эндпоинт:
https://api.airtable.com/v0 - Заголовок авторизации:
Authorization: Bearer $AIRTABLE_API_KEY - Все запросы используют JSON (
Content-Type: application/jsonдля любого тела POST/PATCH/PUT). - Идентификаторы объектов: базы
app..., таблицыtbl..., записиrec..., поляfld.... ID никогда не меняются, а имена — могут. В автоматизациях лучше опираться на ID. - Лимит запросов: 5 запросов/сек на базу. При
429— снижайте темп. Всплеск нагрузки на одну базу будет ограничен.
Базовый шаблон curl:
curl -s "https://api.airtable.com/v0/$BASE_ID/$TABLE?maxRecords=5" \
-H "Authorization: Bearer $AIRTABLE_API_KEY" | python3 -m json.tool
-s убирает индикатор прогресса curl — держите этот флаг для каждого вызова, чтобы вывод инструмента оставался чистым для Hermes. Прогоняйте ответ через python3 -m json.tool (есть всегда) или jq (если установлен) — для читаемого JSON.
Типы полей (форма тела запроса)
| Тип поля | Форма для записи |
|---|---|
| Single line text | "Name": "hello" |
| Long text | "Notes": "multi\nline" |
| Number | "Score": 42 |
| Checkbox | "Done": true |
| Single select | "Status": "Todo" (имя должно уже существовать, если не задан 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 скачивает и перехостит) |
| Linked record | "Owner": ["recXXXXXXXXXXXXXX"] (массив ID записей) |
| User | "AssignedTo": {"id": "usrXXXXXXXXXXXXXX"} |
Передайте "typecast": true на верхнем уровне тела create/update, чтобы Airtable автоматически приводил значения (например, создавал новый вариант select на лету или превращал "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 для select-полей и выясняются имена первичных полей.
Список записей (первые 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).
Использование именованного представления (view)
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":"New task","Status":"Todo","Priority":"High"}}' | 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": "Task A", "Status": "Todo"}},
{"fields": {"Name": "Task B", "Status": "In progress"}}
]
}' | 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":"Done"}}' | 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": "Active"}}
]
}' | 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. - Найдите базу. Получите список баз (шаг выше) ИЛИ спросите у пользователя ID вида
app...напрямую, если у токена нетschema.bases:read. - Изучите схему.
GET /v0/meta/bases/$BASE_ID/tables— закешируйте точные имена полей и имя первичного поля локально в сессии, прежде чем что-либо менять. - Сначала читайте, потом пишите. Для «обнови X, где Y» сперва
filterByFormula, чтобы определить ID видаrec..., затемPATCH /v0/$BASE_ID/$TABLE/$RECORD_ID. Никогда не угадывайте ID записей. - Пакетная запись. Объединяйте связанные создания в один POST на 10 записей, чтобы держаться в бюджете 5 запросов/сек.
- Деструктивные операции. Удаления через API не отменить. Если пользователь говорит «удали все X», выведите фильтр и число найденных записей и дождитесь подтверждения перед выполнением.
Подводные камни
filterByFormulaОБЯЗАТЕЛЬНО кодировать в URL. Имена полей с пробелами или не-ASCII тоже нуждаются в кодировании ({My Field}→%7BMy%20Field%7D). Используйте стандартную библиотеку Python (шаблон выше) — никогда не экранируйте вручную.- Пустые поля выпадают из ответов. Отсутствие ключа
"Assignee"не значит, что поля нет, — значит, у этой записи значение пустое. Сверьтесь со схемой (шаг 3), прежде чем делать вывод об отсутствии поля. - PATCH против PUT.
PATCHсливает переданные поля в запись.PUTзаменяет запись целиком и обнуляет любое поле, которое вы не включили. По умолчанию беритеPATCH. - Варианты single-select должны существовать. Запись
"Status": "Shipping", когдаShippingнет в списке вариантов поля, вызовет ошибкуINVALID_MULTIPLE_CHOICE_OPTIONS, если не передать"typecast": true(он создаст вариант автоматически). - Токен привязан к конкретной базе.
403на одной базе при рабочей другой означает, что в списке Access токена нет этой базы — а не проблему со scope или авторизацией. Отправьте пользователя на https://airtable.com/create/tokens выдать доступ. - Лимиты считаются по базе, а не по токену. 5 запросов/сек на
baseAи 5 запросов/сек наbaseB— нормально; 6 запросов/сек на однойbaseAуже упрётся в троттлинг. Следите за заголовкомRetry-Afterпри429.
Важные замечания для Hermes
- Всегда используйте инструмент
terminalсcurl. НЕ применяйтеweb_extract(он не умеет слать заголовки авторизации) иbrowser_navigate(требует UI-авторизации и работает медленно). AIRTABLE_API_KEYподтягивается из~/.hermes/.envв подпроцесс автоматически при загрузке навыка — переэкспортировать его перед каждым вызовомcurlне нужно.- Аккуратно экранируйте фигурные скобки в формулах. В теле heredoc
{Status}берётся буквально. В аргументе shell{Status}безопасен вне контекста brace-expansion{...}— но динамические строки прогоняйте черезpython3 urllib.parse.quote, прежде чем вставлять в URL. - Форматируйте вывод через
python3 -m json.tool(есть всегда), а неjq(опционально). Тянитесь кjqтолько когда нужна фильтрация или выборка полей. - Пагинация постраничная, не глобальная. Лимит в 100 записей у Airtable жёсткий, поднять его нельзя. Крутите цикл с
offset, пока поле не исчезнет. - Читайте массив
errorsв ответах не-2xx — Airtable возвращает структурированные коды ошибок вродеAUTHENTICATION_REQUIRED,INVALID_PERMISSIONS,MODEL_ID_NOT_FOUND,INVALID_MULTIPLE_CHOICE_OPTIONS, которые точно говорят, что не так.