---
title: "Airtable Connector"
description: "Complete Airtable integration guide for syncing bases, tables, and records with Brevo contacts and lists via Tajo."
url: https://tajo.io/docs/connectors/custom/airtable/
markdown: https://tajo.io/docs/connectors/custom/airtable.md
lang: en-US
robots: noindex
---

# Airtable Connector

Connector status: Planned Not built yet. Tajo does not run this connector today.

| Source field | Destination field | Sample value |
| --- | --- | --- |
| `record.id` | `source_id` | `record_1042` |
| `record.updated_at` | `updated_at` | `2026-10-18T08:00:00Z` |
| `record.value` | `value` | `sample_value` |

Connect your Airtable bases to Brevo for CRM synchronization, product catalog management, and automated marketing workflows powered by structured data through Tajo.

## Overview

| Property | Value |
| --- | --- |
| **Platform** | Airtable |
| **Category** | Custom |
| **Setup Complexity** | Easy |
| **Official Integration** | No |
| **Data Synced** | Records, Tables, Users |
| **API Type** | REST API |
| **Authentication** | Personal Access Token / OAuth 2.0 |
| **Base URL** | `https://api.airtable.com/v0/` |

## Features

- **Table-to-list sync** - Sync Airtable table records directly to Brevo contact lists
- **Product catalog bridge** - Use Airtable tables as product catalogs for email recommendations
- **CRM synchronization** - Bidirectional sync between Airtable CRM and Brevo contacts
- **Form submission events** - Forward Airtable form submissions as Brevo events
- **View-based filtering** - Sync specific Airtable views to targeted Brevo lists
- **Webhook automation** - Trigger Brevo campaigns when Airtable records change

## Prerequisites

Before you begin, ensure you have:

1. An Airtable account (Free plan or above)
2. A Personal Access Token or OAuth app configured
3. Access to the bases and tables you want to sync
4. A Brevo account with API access
5. A Tajo account with an active subscription

## Authentication

Airtable supports Personal Access Tokens and OAuth 2.0.

### Option 1: Personal Access Token (Recommended)

1. Go to [airtable.com/create/tokens](https://airtable.com/create/tokens)
2. Click **Create new token**
3. Name it “Tajo Integration”
4. Add scopes:

```
data.records:read
data.records:write
data.recordComments:read
schema.bases:read
webhook:manage
```

5. Add access to specific bases or all bases
6. Click **Create token**

### Option 2: OAuth 2.0

For multi-user integrations, use the OAuth 2.0 flow:

1. Register your integration at [airtable.com/create/oauth](https://airtable.com/create/oauth)
2. Configure redirect URI: `https://app.tajo.io/callbacks/airtable`
3. Request the same scopes as above

Token Scoping

Personal Access Tokens can be scoped to specific bases. For security, only grant access to the bases your integration needs rather than selecting “All current and future bases.”

### Connecting to Tajo

```bash
tajo connectors install airtable \
  --token $AIRTABLE_TOKEN
```

## Configuration

### Basic Setup

```yaml
connectors:
  airtable:
    enabled: true

    sync:
      records: true
      comments: false

    tables:
      - base_id: "appXXXXXXXXXXXXXX"
        table_name: "Customers"
        view: "Active Customers"
        sync_to_list: 28
      - base_id: "appXXXXXXXXXXXXXX"
        table_name: "Products"
        sync_as: "catalog"
```

### Field Mapping

Map Airtable fields to Brevo contact attributes:

```yaml
field_mapping:
  # Airtable field -> Brevo attribute
  Name: FIRSTNAME
  Email: email
  Phone: SMS
  Company: COMPANY
  Status: LEAD_STATUS
  Revenue: TOTAL_REVENUE
  "Last Contact": LAST_CONTACT_DATE
  Tags: TAGS
  Notes: NOTES
  "Created Time": SIGNUP_DATE
```

### View-Based Sync

```yaml
views:
  - base_id: "appXXXXXXXXXXXXXX"
    table_name: "Customers"
    view: "High Value"
    sync_to_list: 29
    filter_by_view: true

  - base_id: "appXXXXXXXXXXXXXX"
    table_name: "Customers"
    view: "Churned"
    sync_to_list: 30
    filter_by_view: true
```

## API Endpoints

Tajo integrates with the following Airtable Web API endpoints:

| Endpoint | Method | Purpose |
| --- | --- | --- |
| `/v0/{baseId}/{tableIdOrName}` | GET | List records in a table |
| `/v0/{baseId}/{tableIdOrName}` | POST | Create records |
| `/v0/{baseId}/{tableIdOrName}` | PATCH | Update records |
| `/v0/{baseId}/{tableIdOrName}` | DELETE | Delete records |
| `/v0/{baseId}/{tableIdOrName}/{recordId}` | GET | Retrieve a single record |
| `/v0/meta/bases` | GET | List accessible bases |
| `/v0/meta/bases/{baseId}/tables` | GET | List tables in a base |
| `/v0/{baseId}/{tableIdOrName}/listRecordComments` | GET | List record comments |
| `/v0/bases/{baseId}/webhooks` | POST | Create a webhook |
| `/v0/bases/{baseId}/webhooks` | GET | List webhooks |

## Code Examples

### Initialize Connector

```javascript
import { TajoClient } from '@tajo/sdk';

const tajo = new TajoClient({
  apiKey: process.env.TAJO_API_KEY,
  brevoApiKey: process.env.BREVO_API_KEY
});

await tajo.connectors.connect('airtable', {
  token: process.env.AIRTABLE_TOKEN
});
```

### Sync Table to Brevo

```javascript
// Sync an Airtable table to a Brevo list
await tajo.connectors.sync('airtable', {
  type: 'full',
  resources: ['records'],
  baseId: 'appXXXXXXXXXXXXXX',
  tableName: 'Customers',
  view: 'Active Customers',
  targetList: 28
});

const status = await tajo.connectors.status('airtable');
console.log(status);
// {
//   connected: true,
//   lastSync: '2024-03-15T15:00:00Z',
//   recordsSynced: 2340,
//   tablesMonitored: 2,
//   basesConnected: 1
// }
```

### Handle Webhooks

```javascript
// Airtable webhooks notify of changes; fetch details with cursor
app.post('/webhooks/airtable', async (req, res) => {
  const { base, webhook, timestamp } = req.body;

  // Fetch changed records using webhook cursor
  const changes = await tajo.connectors.getWebhookPayloads('airtable', {
    baseId: base.id,
    webhookId: webhook.id,
    cursor: timestamp
  });

  for (const change of changes) {
    await tajo.connectors.handleEvent('airtable', {
      type: change.actionType,
      payload: change
    });
  }

  res.status(200).send('OK');
});
```

### Create Record from Brevo

```javascript
// Create an Airtable record when a Brevo contact converts
tajo.events.on('contact.attribute_updated', async (event) => {
  if (event.attribute === 'LIFECYCLE_STAGE' && event.value === 'customer') {
    await tajo.connectors.create('airtable', {
      baseId: 'appXXXXXXXXXXXXXX',
      tableName: 'Customers',
      fields: {
        Name: event.contact.name,
        Email: event.contact.email,
        Status: 'Customer',
        'Converted Date': new Date().toISOString().split('T')[0]
      }
    });
  }
});
```

## Rate Limits

Airtable enforces rate limits per base:

| Limit Type | Value |
| --- | --- |
| **API rate limit** | 5 requests per second per base |
| **Records per request** | 100 records max (list), 10 records max (create/update) |
| **Webhook payloads** | 50 payloads per `listWebhookPayloads` call |
| **Request size** | Payload max ~2MB |

Batch Operations

Airtable allows creating or updating up to 10 records per request. Tajo automatically batches larger operations into multiple requests while respecting rate limits.

## Troubleshooting

### Common Issues

| Issue | Cause | Solution |
| --- | --- | --- |
| 401 Unauthorized | Invalid or expired token | Regenerate Personal Access Token |
| 403 Forbidden | Token lacks base access | Add the base to your token’s scope |
| 404 Not Found | Invalid base or table ID | Verify base ID and table name |
| 422 Invalid Request | Field type mismatch | Check Airtable field types match your data |
| Rate limit exceeded | More than 5 req/s per base | Reduce sync frequency or stagger base syncs |

### Debug Mode

```yaml
connectors:
  airtable:
    debug: true
    log_level: verbose
    log_api_calls: true
```

### Test Connection

```bash
tajo connectors test airtable
# ✓ API authentication successful
# ✓ Base access verified
# ✓ Table schema readable
# ✓ Record listing operational
# ✓ Webhook registration available
```

## Best Practices

1. **Scope tokens to specific bases** - Do not grant access to all bases unless necessary
2. **Use views for filtered sync** - Sync specific views instead of full tables to reduce data volume
3. **Batch record operations** - Group creates and updates in batches of 10
4. **Handle pagination** - Airtable returns 100 records per page; iterate with `offset`
5. **Use webhooks for real-time** - Register webhooks instead of polling for changes
6. **Map field types precisely** - Match Airtable field types (select, number, date) to Brevo attribute types

## Security

- **Personal Access Tokens** - Scoped to specific bases and operations
- **OAuth 2.0** - Secure authorization flow with refresh tokens
- **HTTPS Only** - All API communication encrypted via TLS 1.2+
- **Base-Level Access Control** - Tokens scoped to individual bases
- **Encrypted Storage** - Tokens encrypted at rest in Tajo
- **Webhook HMAC Verification** - Verify webhook notification authenticity

## Related Resources

- [Notion Connector](https://tajo.io/docs/connectors/custom/notion)
- [GitHub Connector](https://tajo.io/docs/connectors/custom/github)
- [Customer Sync Skill](https://tajo.io/docs/skills/data-sync/customer-sync)
- [Brevo Contacts API](https://tajo.io/docs/contact-management)

## Open-Source Implementation Map

No official open-source repository was found in the current Tajo connector catalog for Airtable. Keep this page focused on the verified public API contract and vendor documentation until an official schema, SDK, MCP server, or public integration repository is available.

### Tajo Revamp Checklist

- Verify authentication and scope requirements against the vendor documentation before each connector release.
- Document primary sync objects, external IDs, pagination strategy, and rate limits explicitly.
- Add smoke tests from public API examples rather than undocumented behavior.
- Capture webhook signature verification and replay protection when the vendor supports webhooks.
- Record gaps where no official public repository or schema exists so future maintainers know what still needs source-backed validation.
