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
-
Create a Personal Access Token
Airtable → Account → Developer Hub → Personal access tokens → Create new token.
Field Value Name spelo-readonlyScopes data.records:read,schema.bases:readAccess Choose the specific bases you want Spelo to read Copy the
pat...token. You won’t see it again. -
Get your base ID
Open the base. The URL is
https://airtable.com/appXXXXXXXXXXXXXX/tblYYY...— theapp...prefix is your base ID. -
Paste in the dashboard
Dashboard → Data → Airtable → paste token and base ID → Test connection.
-
Map collections
The
sourceis 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 operator | Airtable 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}) |
in | OR({Field}="a", {Field}="b", ...) |
free-text query | OR(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
urlkeys. Keep them out ofsearchable_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/:tableNamewith 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 withpatand 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 infilterable_fieldsdoesn’t exist in the table. Field names are case-sensitive.REQUEST_TOO_BIG→ you included hundreds of records in a single filter list. Slim downdisplay_fields.
More: Database connection errors.