Airtable
REST API Airtable через curl. CRUD для записей, фильтры, апсерты.
Метаданные навыка
| Источник | Встроенный (установлен по умолчанию) |
| Путь | skills/productivity/airtable |
| Версия | 1.1.0 |
| Автор | community |
| Лицензия | MIT |
| Платформы | linux, macos, windows |
| Теги | Airtable, Productivity, Database, API |
Справочник: полный SKILL.md
Ниже приведено полное описание навыка, которое VibeOS загружает при его активации. Агент видит эти инструкции, когда навык активен.
Airtable — Базы, Таблицы и Записи
Работайте с REST API Airtable напрямую через curl с помощью инструмента terminal. Никакого MCP-сервера, OAuth-потока или Python SDK — только curl и персональный токен доступа.
Предварительные требования
- Создайте персональный токен доступа (PAT) на https://airtable.com/create/tokens (токены начинаются с
pat...). - Предоставьте следующие разрешения (минимум):
data.records:read— чтение строкdata.records:write— создание / обновление / удаление строкschema.bases:read— список баз и таблиц
- Важно: в том же интерфейсе токена добавьте каждую базу, к которой нужен доступ, в список Доступ токена. PAT ограничены по базам — валидный токен для неверной базы вернёт
403. - Сохраните токен в
${VIBEOS_HOME:-~/.vibeos}/.env(или черезvibeos 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). - ID объектов: базы
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 — всегда используйте его, чтобы вывод инструмента оставался чистым для VibeOS. Передавайте через python3 -m json.tool (всегда доступен) или jq (если установлен) для читаемого JSON.
Типы полей (форма тела запроса)
| Тип поля | Формат записи |
|---|---|
| Однострочный текст | "Name": "hello" |
| Длинный текст | "Notes": "multi\nline" |
| Число | "Score": 42 |
| Флажок | "Done": true |
| Одиночный выбор | "Status": "Todo" (имя должно существовать, если не typecast: true) |
| Множественный выбор | "Tags": ["urgent", "bug"] |
| Дата | "Due": "2026-04-01" |
| Дата и время (UTC) | "At": "2026-04-01T14:30:00.000Z" |
| URL / Email / Телефон | "Link": "https://…" |
| Вложение | "Files": [{"url": "https://…"}] (Airtable загружает и размещает у себя) |
| Связанная запись | "Owner": ["recXXXXXXXXXXXXXX"] (массив ID записей) |
| Пользователь | "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":"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
Апсерт по полю слияния (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
Типичный рабочий процесс VibeOS
- Подтвердите авторизацию.
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, чтобы получить IDrec..., затем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 vs PUT.
PATCHобъединяет переданные поля с записью.PUTполностью заменяет запись и очищает любое поле, которое вы не включили. По умолчанию используйтеPATCH. - Варианты одиночного выбора должны существовать. Запись
"Status": "Shipping", когдаShippingнет в списке вариантов поля, вызовет ошибкуINVALID_MULTIPLE_CHOICE_OPTIONS, если не передать"typecast": true(который автоматически создаёт вариант). - Область действия токена по базам.
403на одной базе, когда другая работает, означает, что база не добавлена в список доступа токена — это не проблема области или авторизации. Отправьте пользователя на https://airtable.com/create/tokens, чтобы предоставить доступ. - Лимиты запросов действуют на базу, а не на токен. 5 запросов/сек на
baseAи 5 запросов/сек наbaseB— нормально; 6 запросов/сек только наbaseAвызовет ограничение. Следите за заголовкомRetry-Afterпри429.
Важные замечания для VibeOS
- Всегда используйте инструмент
terminalсcurl. НЕ используйтеweb_extract(он не может отправлять заголовки авторизации) илиbrowser_navigate(требует авторизации в UI и медленный). AIRTABLE_API_KEYавтоматически передаётся из${VIBEOS_HOME:-~/.vibeos}/.envв подпроцесс при загрузке этого навыка — не нужно повторно экспортировать его перед каждым вызовомcurl.- Экранируйте фигурные скобки в формулах осторожно. В теле heredoc
{Status}— литерал. В аргументе оболочки{Status}безопасен вне контекста подстановки{...}— но передавайте динамические строки черезpython3 urllib.parse.quoteперед вставкой в URL. - Форматируйте вывод с помощью
python3 -m json.tool(всегда доступен), а неjq(опционально). Используйтеjqтолько когда нужна фильтрация/проекция. - Пагинация постраничная, а не глобальная. Лимит Airtable в 100 записей — жёсткое ограничение; увеличить его нельзя. Используйте цикл с
offset, пока поле не исчезнет. - Читайте массив
errorsв ответах с кодом не 2xx — Airtable возвращает структурированные коды ошибок, такие какAUTHENTICATION_REQUIRED,INVALID_PERMISSIONS,MODEL_ID_NOT_FOUND,INVALID_MULTIPLE_CHOICE_OPTIONS, которые точно указывают на проблему.