Skip to content

feat: add Airtable action #47

Description

@nicosammito

Summary

Add an Airtable action so Hercules flows can create, read, update, and search records in Airtable bases — a flexible cloud database / spreadsheet hybrid that non-technical users adopt as the backing store for their automations. Airtable is a top data integration on both n8n and Zapier, frequently used for "new record → do X" and "sync records between apps" workflows.

n8n/Zapier validation: Airtable has a first-party node on n8n (supporting all field types incl. linked records, attachments, and formulas) and is one of the most popular database/productivity apps on Zapier.

Suggested directory

actions/airtable-action

Triggers

Airtable's webhooks API can push change notifications, but the simplest, most portable approach (and the one n8n's trigger uses) is polling the list-records endpoint with a cursor on a Last Modified Time field or createdTime. Where the codebase lacks a polling base, this can piggyback on a scheduled/cron-style event or a lightweight interval poller in the action process — the same approach proposed for the Notion (#42) and Google Sheets (#43) actions.

  • AirtableRecordCreated — new record in a watched table (settings: baseId, tableId)
  • AirtableRecordUpdated — a record in a watched table changed (settings: baseId, tableId, optional watchedFields)

Functions

  • airtableCreateRecord(baseId, tableId, fields): AIRTABLE_RECORD
  • airtableCreateRecords(baseId, tableId, records): AIRTABLE_RECORD_LIST — batch (up to 10/req)
  • airtableGetRecord(baseId, tableId, recordId): AIRTABLE_RECORD
  • airtableUpdateRecord(baseId, tableId, recordId, fields, replace?): AIRTABLE_RECORD — PATCH (merge) or PUT (replace)
  • airtableDeleteRecord(baseId, tableId, recordId): BOOLEAN
  • airtableListRecords(baseId, tableId, filterByFormula?, view?, sort?, maxRecords?): AIRTABLE_RECORD_LIST
  • airtableFindRecord(baseId, tableId, field, value): AIRTABLE_RECORD — convenience lookup via filterByFormula
  • airtableUpsertRecord(baseId, tableId, keyField, fields): AIRTABLE_RECORD — find-or-create/update

Utils (data-type builders, mirroring GLS create* utils): airtableCreateFieldMap(...), airtableCreateSort(...).

Data types

One class per file in src/data_types/ (zod schema + @Identifier/@Name/@Schema):

  • AirtableRecord (id, createdTime, fields dynamic key/value bag), AirtableRecordList, AirtableField, AirtableTable, AirtableBase, AirtableAttachment

Auth / config via ConfigurationDefinition on the Action (like GLS client_id/client_secret):

Identifier Type Description
api_token TEXT Airtable personal access token (Bearer) scoped to the target base(s)
endpoint_url TEXT (optional) API base URL, default https://api.airtable.com/v0 (override for self-hosted proxies)

Because Airtable fields are a dynamic key/value bag, record functions accept a JSON object string for fields (coerced per the table schema), the same pattern PR #44 adopted for HubSpot's dynamic properties. Beyond the shared Hercules vars (HERCULES_AUTH_TOKEN, HERCULES_AQUILA_URL, HERCULES_ACTION_ID, HERCULES_SDK_VERSION) an action-specific AIRTABLE_API_TOKEN may back the config default.

Rationale

Cloud-database / structured-records domain, not covered by anything in the repo. Not implemented (gls, shopify, shopware, twilio, woocommerce), not on an in-development branch (stripe, github, hubspot/twilio), and not in any open issue/PR (Google Sheets #43, Notion #42, HubSpot #41/#44, S3 #38, SFTP #37, MCP #40, Stripe #35, Discord #34, GitHub #26, SMTP #20, Cron #15, Rest #14, AI #2, WebSocket #16, MQTT #13). Distinct from the planned Google Sheets (#43) and Notion (#42) actions: Airtable is a typed relational-ish database with views, filterByFormula querying, linked records, and attachment fields — a different data model and API from Sheets' A1/cell grid and Notion's page/block tree. Distinct from S3/SFTP (#38/#37), which are blob/file storage rather than queryable structured rows. Gives flows a first-class record store that non-technical users already know.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions