Skip to content
GitHub
Get started →

Airtable adapter

Airtable is a great fit when your team already maintains inventory / listings / menus / content in a spreadsheet-y tool and doesn’t want a “real” database. The Airtable adapter translates Spelo searches into Airtable formulas.

If you’re not sure whether to use OAuth or a Personal Access Token, prefer OAuth — simpler, no credential to rotate.

Config shape

{
"type": "airtable",
"config": {
"apiKey": "patXXXXXXXXXX.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"baseId": "appXXXXXXXXXXXXXX"
},
"collections": {
"menu": {
"source": "Menu Items",
"searchable_fields": ["Name", "Description"],
"filterable_fields": ["Category", "Price", "Vegan"],
"display_fields": ["Name", "Price", "Category"]
}
}
}

Setup

  1. Create a Personal Access Token

    Airtable → AccountDeveloper HubPersonal access tokensCreate new token.

    FieldValue
    Namespelo-readonly
    Scopesdata.records:read, schema.bases:read
    AccessChoose the specific bases you want Spelo to read

    Copy the pat... token. You won’t see it again.

  2. Get your base ID

    Open the base. The URL is https://airtable.com/appXXXXXXXXXXXXXX/tblYYY... — the app... prefix is your base ID.

  3. Paste in the dashboard

    Dashboard → DataAirtable → paste token and base ID → Test connection.

  4. Map collections

    The source is the exact table name as it appears in Airtable (spaces and punctuation allowed — it’s URL-encoded when calling).

Operator translation

Airtable uses formula strings. The adapter builds them like this:

SearchParams operatorAirtable formula fragment
eq{Field}="value"
neq{Field}!="value"
gt, gte, lt, lte{Field}>value, etc. (numeric only)
contains (multi-select or array)FIND("value", ARRAYJOIN({Field}))
contains (text)FIND("value", {Field})
inOR({Field}="a", {Field}="b", ...)
free-text queryOR(SEARCH("q", {A}), SEARCH("q", {B}), ...) over searchable_fields

Values are escaped (double quotes) before formula embedding.

Linked records, attachments, rollups

  • Linked records appear as arrays of record IDs. To search by linked record, either use a lookup field that exposes a real value, or fetch the linked records via a Webhook adapter where you can do the join.
  • Attachments appear as arrays of objects with url keys. Keep them out of searchable_fields — the AI won’t do anything useful with the blob URL.
  • Rollups, formulas, lookups work — their computed values are filterable just like real fields.

Rate limits

Airtable caps each base at 5 requests per second. The adapter sends one request per voice query. At five concurrent voice sessions on the same base you might hit 429. If that’s a concern, migrate to Postgres or a Webhook adapter that caches Airtable records.

Security notes

  • Personal Access Tokens are scoped to specific bases. A leaked token only exposes those bases.
  • Adapter only calls GET /v0/:baseId/:tableName with query params — no write endpoints ever.
  • Formula string values are escaped against injection (double quote doubling, Excel-style).

Troubleshooting

  • AUTHENTICATION_REQUIRED → token missing or malformed. Must start with pat and end with a 32-char suffix.
  • NOT_FOUND → wrong base ID or table name. Check that the PAT has access to this base.
  • INVALID_REQUEST_MISSING_FIELDS → a field in filterable_fields doesn’t exist in the table. Field names are case-sensitive.
  • REQUEST_TOO_BIG → you included hundreds of records in a single filter list. Slim down display_fields.

More: Database connection errors.