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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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