> ## Documentation Index
> Fetch the complete documentation index at: https://docs.asteragents.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Manage Airtable Records Tool

> Create, read, update, upsert, or delete records in an Airtable table — with batch support and typecast

## What it does

The Manage Airtable Records tool performs all the write (and single-record read) operations on an Airtable table. It supports five actions:

* **get** — retrieve a single record by ID
* **create** — insert 1–10 new records in one call
* **update** — patch specific fields on existing records (requires each record's `id`)
* **upsert** — batch insert-or-update, matching on `fieldsToMergeOn`
* **delete** — remove records by ID (single or batch up to 10)

All writes are capped at **10 records per call** — that's Airtable's API limit, not ours. For larger batches, loop with pagination.

## Key features

* Single action param covers five operations, keeping the tool surface small
* Optional `typecast` flag coerces human-readable strings into existing select options, numbers, and dates — agents don't need to format values exactly
* Upsert matches on any field(s) you designate via `fieldsToMergeOn` (email, external ID, slug, etc.) and cleanly reports which records were created vs updated
* Single-record delete via `recordId`, or batch delete via `records[].id`

## Parameters

| Parameter         | Type      | Required            | Description                                                                                                                                |
| ----------------- | --------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `action`          | string    | Yes                 | One of `get`, `create`, `update`, `upsert`, `delete`                                                                                       |
| `baseId`          | string    | Yes                 | Airtable base ID (starts with `app`)                                                                                                       |
| `tableIdOrName`   | string    | Yes                 | Table ID (starts with `tbl`) or display name                                                                                               |
| `recordId`        | string    | Conditional         | Required for `get`. Optional shorthand for single-record `delete`                                                                          |
| `records`         | array     | Conditional         | Max 10. Required for `create`, `update`, `upsert`, and batch `delete`                                                                      |
| `typecast`        | boolean   | No                  | If `true`, Airtable coerces string values to match existing select options, numbers, and dates. Recommended for `create`/`update`/`upsert` |
| `fieldsToMergeOn` | string\[] | Required for upsert | Field names Airtable should match on to decide create vs update                                                                            |

### Shape of `records[]`

Each entry is `{ id?: string, fields: { [fieldName]: value } }`:

* **create**: each item needs `fields` only
* **update**: each item needs `id` + `fields`
* **upsert**: each item needs `fields`; `id` is optional (present = update that specific record; absent = match via `fieldsToMergeOn`)
* **batch delete**: each item needs `id`

## Common use cases

### Create a single contact

```
action: "create"
baseId: "appXXXXXXXXXXXXXX"
tableIdOrName: "Contacts"
records: [
  { "fields": { "Name": "Jane Smith", "Email": "jane@example.com", "Company": "Acme" } }
]
typecast: true
```

### Batch update deal stages

```
action: "update"
tableIdOrName: "Deals"
records: [
  { "id": "recAAA", "fields": { "Stage": "Closed Won" } },
  { "id": "recBBB", "fields": { "Stage": "Closed Lost" } }
]
```

### Upsert contacts by email (idempotent sync)

```
action: "upsert"
tableIdOrName: "Contacts"
fieldsToMergeOn: ["Email"]
records: [
  { "fields": { "Name": "Alice",  "Email": "alice@example.com", "Status": "Lead" } },
  { "fields": { "Name": "Bob",    "Email": "bob@example.com",   "Status": "Customer" } }
]
typecast: true
```

Airtable reports `createdRecordIds` and `updatedRecordIds` separately so the agent knows what happened.

### Write linked records

Linked-record fields take an **array of record IDs** (not names):

```
action: "create"
tableIdOrName: "Deals"
records: [
  { "fields": {
      "Name": "Q2 Renewal",
      "Contact": ["recAliceID"],
      "Company": ["recAcmeID"]
  } }
]
```

### Single-record delete

```
action: "delete"
tableIdOrName: "Contacts"
recordId: "recXXXX"
```

### Batch delete

```
action: "delete"
tableIdOrName: "Contacts"
records: [
  { "id": "recAAA", "fields": {} },
  { "id": "recBBB", "fields": {} },
  { "id": "recCCC", "fields": {} }
]
```

## What you get back

All responses include a `status` and an `action`-specific `content`:

* **get** → `{ id, createdTime, fields }`
* **create** → `{ records[], count, message }`
* **update** → `{ records[], count, message }`
* **upsert** → `{ records[], createdRecordIds[], updatedRecordIds[], count, message }`
* **delete** → `{ deletedIds[], count, message }`

## Best practices

* **Pass `typecast: true`** when writing to `singleSelect`, `multipleSelects`, `number`, `date`, etc. — agents don't always produce the exact option strings or formats Airtable expects
* **Use upsert for external-ID syncs.** If your source system has a stable identifier (email, external ID), store it in a unique field and upsert on it — safer than guessing whether to call create or update
* **Keep batches at or below 10.** The Zod validator blocks larger batches locally; larger-than-10 writes need to be chunked by the caller
* **For linked records, pass IDs** — not names. Get IDs from [airtable\_search](/tools/airtable_search) or [airtable\_get\_schema](/tools/airtable_get_schema)
* **For attachments**, pass `[{ url: "..." }]` objects; Airtable fetches the files

## Troubleshooting

**"Unknown field name"**

* Field names are case-sensitive; verify exact spelling with [airtable\_get\_schema](/tools/airtable_get_schema)
* Computed fields (formula, rollup, lookup) are read-only — you can't write to them

**"Invalid value for field" (select/number/date)**

* Add `typecast: true` so Airtable coerces string values to the right type or matches an existing option
* For `multipleSelects`, pass an array of option strings; for `singleSelect`, pass one string

**"Airtable accepts at most 10 records per write request"**

* Split the batch. Each action supports up to 10 in a single call — chain multiple calls for larger sets

**"Record not found" on update/delete**

* The record may have been deleted by another process
* The `id` must start with `rec` and belong to the same table

**Upsert: "wrong record matched"**

* `fieldsToMergeOn` fields must uniquely identify a record. If the match fields aren't unique, Airtable picks one; add more fields (e.g., `["Email", "External ID"]`) to tighten the match

## Related tools

* [Search Airtable](/tools/airtable_search) — find the records you want to update, delete, or link to
* [Get Airtable Schema](/tools/airtable_get_schema) — discover valid table + field names before writing
