A reference guide for building AI agents: every method, how to authenticate, and the permissions each one needs.
The Airtable API is how an app or AI agent works with an Airtable base: listing and creating records, updating cell values, reading or editing a base's tables and fields, and leaving comments on a record. Access is granted through a bearer token, a personal access token or an OAuth token, which carries scopes like data.records:read or schema.bases:write and is limited to specific bases, so a call needs both the right scope and access to the base. Airtable can push a notification when records, fields, or tables change, so an integration learns about activity without polling.
How an app or AI agent connects to Airtable determines what it can reach. There is a route for making calls, a route for receiving change notifications, and a hosted server that exposes Airtable to agents, and each is governed by the token behind it and the scopes and bases that token carries.
The Web API answers at https://api.airtable.com/v0. It follows REST semantics, takes and returns JSON, and signals outcomes with standard HTTP status codes. A call authenticates with a bearer token, either a personal access token or an OAuth access token. Record paths are /v0/{baseId}/{tableIdOrName}, and structure (schema) paths sit under /v0/meta.
Airtable can watch a base and send a short notification ping to a registered URL when subscribed changes occur. The ping carries no change detail; the app then calls the list-payloads endpoint with a cursor to collect the actual changes. A webhook is scoped to dataTypes (tableData, tableFields, tableMetadata) and expires after 7 days unless refreshed.
Airtable runs a hosted Model Context Protocol server at https://mcp.airtable.com/mcp that exposes Airtable to AI assistants like Claude and ChatGPT. It connects with OAuth or a personal access token, and its access mirrors the permissions the connecting user already has in Airtable. It can search and read records, create and update records, create bases, and create tables and fields. It is included on all plans at no extra cost.
A personal access token is the standard way to connect to Airtable. It is created in the developer hub and is doubly scoped: it carries a chosen set of OAuth scopes (like data.records:read) and is limited to chosen workspaces or bases, so it reaches only what it was granted. It is sent as a bearer token and never exceeds its owner's own permissions.
OAuth lets a third-party integration act on behalf of any Airtable user who grants it. It uses the authorization-code flow with PKCE (S256) at https://airtable.com/oauth2/v1/authorize, exchanging the code at /oauth2/v1/token. The user picks which scopes and which bases to grant. Access tokens last 60 minutes; refresh tokens last 60 days and are rotated on use.
The original account-wide API key gave one secret full access to everything the account could reach, with no scoping. Airtable deprecated it in favor of personal access tokens and OAuth, and shut it off on 1 February 2024. New integrations must use a personal access token or OAuth.
The Airtable API is split into areas an agent can act on, like the records inside a table, the structure of a base, its comments, and webhooks. Each area has its own methods and its own scope, and changing a base's structure reaches further than editing the rows inside it.
List, read, create, update, and delete the records inside a table.
List the bases a token can reach, read a base's structure, and create or edit its tables and fields.
List, create, update, and delete the comments on a record.
Create, list, refresh, and delete webhooks, and collect the change payloads they queue.
Read the identity and scopes behind the current token.
Filter by method, access, or permission, or search any path. Select a row for version detail, rate limits, the related webhook event, and the source.
| Method | Endpoint | What it does | Access | Permission | Version | |
|---|---|---|---|---|---|---|
RecordsList, read, create, update, and delete the records inside a table.7 | ||||||
| GET | /v0/{baseId}/{tableIdOrName} | List records in a table, one page at a time (default 100 per page). | read | data.records:read | Current | |
Returns records with id, createdTime, and fields. Pages with an offset token; supports filterByFormula, sort, view, and fields parameters. Acts onrecord Permission (capability) data.records:readVersionAvailable since the API’s base version Webhook event tableDataRate limitCounts against the 5 req/s per-base limit. SourceOfficial documentation ↗ | ||||||
| GET | /v0/{baseId}/{tableIdOrName}/{recordId} | Retrieve a single record by its id. | read | data.records:read | Current | |
Read-only. Acts onrecord Permission (capability) data.records:readVersionAvailable since the API’s base version Webhook eventNone Rate limitCounts against the 5 req/s per-base limit. SourceOfficial documentation ↗ | ||||||
| POST | /v0/{baseId}/{tableIdOrName} | Create one or more records (up to 10 per request). | write | data.records:write | Current | |
Up to 10 records per request. typecast can coerce string values into the right cell type. Acts onrecord Permission (capability) data.records:writeVersionAvailable since the API’s base version Webhook event tableDataRate limitCounts against the 5 req/s per-base limit. SourceOfficial documentation ↗ | ||||||
| PATCH | /v0/{baseId}/{tableIdOrName}/{recordId} | Update a single record, changing only the fields included in the request. | write | data.records:write | Current | |
PATCH leaves omitted fields unchanged. The PUT form on the same path is destructive and clears any cell value not included. Acts onrecord Permission (capability) data.records:writeVersionAvailable since the API’s base version Webhook event tableDataRate limitCounts against the 5 req/s per-base limit. SourceOfficial documentation ↗ | ||||||
| PATCH | /v0/{baseId}/{tableIdOrName} | Update up to 10 records in one request (partial update). | write | data.records:write | Current | |
Up to 10 records per request. The PUT form is destructive. performUpsert with fieldsToMergeOn (up to three fields) can match and update existing records instead of creating duplicates. Acts onrecord Permission (capability) data.records:writeVersionAvailable since the API’s base version Webhook event tableDataRate limitCounts against the 5 req/s per-base limit. SourceOfficial documentation ↗ | ||||||
| DELETE | /v0/{baseId}/{tableIdOrName}/{recordId} | Delete a single record. | write | data.records:write | Current | |
Irreversible. Acts onrecord Permission (capability) data.records:writeVersionAvailable since the API’s base version Webhook event tableDataRate limitCounts against the 5 req/s per-base limit. SourceOfficial documentation ↗ | ||||||
| DELETE | /v0/{baseId}/{tableIdOrName} | Delete up to 10 records in one request, passing their ids as query parameters. | write | data.records:write | Current | |
Up to 10 record ids per request. Irreversible. Acts onrecord Permission (capability) data.records:writeVersionAvailable since the API’s base version Webhook event tableDataRate limitCounts against the 5 req/s per-base limit. SourceOfficial documentation ↗ | ||||||
Bases, tables & fieldsList the bases a token can reach, read a base's structure, and create or edit its tables and fields.7 | ||||||
| GET | /v0/meta/bases | List the bases the token can access, with each base's permission level. | read | schema.bases:read | Current | |
Returns up to 1,000 bases per page with id, name, and permissionLevel (none to create); pages with an offset. Acts onbase Permission (capability) schema.bases:readVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /v0/meta/bases/{baseId}/tables | Get the schema of a base: its tables, fields, and views. | read | schema.bases:read | Current | |
Read-only structure, not the rows. Returns each table's fields and views. Acts onbase Permission (capability) schema.bases:readVersionAvailable since the API’s base version Webhook event tableMetadataRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /v0/meta/bases | Create a new base in a workspace, optionally with starting tables. | write | schema.bases:write | Current | |
Also needs workspace access; the token owner must be able to create bases in the target workspace. Acts onbase Permission (capability) schema.bases:writeVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /v0/meta/bases/{baseId}/tables | Create a table in a base, with its fields. | write | schema.bases:write | Current | |
Changes base structure. Requires base-creator permission. Acts ontable Permission (capability) schema.bases:writeVersionAvailable since the API’s base version Webhook event tableMetadataRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| PATCH | /v0/meta/bases/{baseId}/tables/{tableIdOrName} | Update a table's name, description, or date-dependency settings. | write | schema.bases:write | Current | |
The API cannot delete a table. Requires base-creator permission. Acts ontable Permission (capability) schema.bases:writeVersionAvailable since the API’s base version Webhook event tableMetadataRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /v0/meta/bases/{baseId}/tables/{tableId}/fields | Create a field (column) in a table. | write | schema.bases:write | Current | |
Some field types, like formula, cannot be created via the API. Requires base-creator permission. Acts onfield Permission (capability) schema.bases:writeVersionAvailable since the API’s base version Webhook event tableFieldsRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| PATCH | /v0/meta/bases/{baseId}/tables/{tableId}/fields/{fieldId} | Update a field's name or description. | write | schema.bases:write | Current | |
The API cannot delete a field. Requires base-creator permission. Acts onfield Permission (capability) schema.bases:writeVersionAvailable since the API’s base version Webhook event tableFieldsRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
Record commentsList, create, update, and delete the comments on a record.4 | ||||||
| GET | /v0/{baseId}/{tableIdOrName}/{recordId}/comments | List the comments on a record. | read | data.recordComments:read | Current | |
Read-only. Acts oncomment Permission (capability) data.recordComments:readVersionAvailable since the API’s base version Webhook eventNone Rate limitCounts against the 5 req/s per-base limit. SourceOfficial documentation ↗ | ||||||
| POST | /v0/{baseId}/{tableIdOrName}/{recordId}/comments | Create a comment on a record. | write | data.recordComments:write | Current | |
Supports @mentions of collaborators in the text. Acts oncomment Permission (capability) data.recordComments:writeVersionAvailable since the API’s base version Webhook eventNone Rate limitCounts against the 5 req/s per-base limit. SourceOfficial documentation ↗ | ||||||
| PATCH | /v0/{baseId}/{tableIdOrName}/{recordId}/comments/{rowCommentId} | Update the text of a comment. | write | data.recordComments:write | Current | |
Only the comment's author can edit it. Acts oncomment Permission (capability) data.recordComments:writeVersionAvailable since the API’s base version Webhook eventNone Rate limitCounts against the 5 req/s per-base limit. SourceOfficial documentation ↗ | ||||||
| DELETE | /v0/{baseId}/{tableIdOrName}/{recordId}/comments/{rowCommentId} | Delete a comment from a record. | write | data.recordComments:write | Current | |
Irreversible. Acts oncomment Permission (capability) data.recordComments:writeVersionAvailable since the API’s base version Webhook eventNone Rate limitCounts against the 5 req/s per-base limit. SourceOfficial documentation ↗ | ||||||
WebhooksCreate, list, refresh, and delete webhooks, and collect the change payloads they queue.5 | ||||||
| POST | /v0/bases/{baseId}/webhooks | Create a webhook on a base for the change types named in its specification. | write | webhook:manage | Current | |
Reading the changes also needs the scope for the subscribed dataTypes, like data.records:read for tableData. A webhook expires after 7 days unless refreshed. Acts onwebhook Permission (capability) webhook:manageVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /v0/bases/{baseId}/webhooks | List the webhooks registered on a base. | read | webhook:manage | Current | |
Returns each webhook's id, expiry, and last notification result. Acts onwebhook Permission (capability) webhook:manageVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /v0/bases/{baseId}/webhooks/{webhookId}/payloads | List the change payloads a webhook has queued since a given cursor. | read | webhook:manage | Current | |
Called after a notification ping arrives. Also needs the scope for the subscribed dataTypes to read the change detail. Payloads are retained for 7 days. Acts onwebhook Permission (capability) webhook:manageVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /v0/bases/{baseId}/webhooks/{webhookId}/refresh | Extend a webhook's expiry by another 7 days. | write | webhook:manage | Current | |
A webhook stops sending notifications once it expires, so a long-lived integration refreshes it. Acts onwebhook Permission (capability) webhook:manageVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| DELETE | /v0/bases/{baseId}/webhooks/{webhookId} | Delete a webhook from a base. | write | webhook:manage | Current | |
Requires base-creator permission. Acts onwebhook Permission (capability) webhook:manageVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
User & metadataRead the identity and scopes behind the current token.1 | ||||||
| GET | /v0/meta/whoami | Get the id and scopes of the user behind the current token. | read | — | Current | |
Needs no scope. The email address is returned only when the token also holds user.email:read. Acts onuser Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
Airtable can notify an app when something changes in a base, like a record being created or a field being edited. It sends a short notification ping to a registered URL, and the app then calls back to collect the list of changes since it last looked.
| Event | What it signals | Triggered by |
|---|---|---|
tableData | Fires when record or cell values change in the base, like a record being created, edited, or deleted. The optional changeTypes filter narrows to add, remove, or update. | /v0/{baseId}/{tableIdOrName}/v0/{baseId}/{tableIdOrName}/{recordId}/v0/{baseId}/{tableIdOrName}/v0/{baseId}/{tableIdOrName}/{recordId}/v0/{baseId}/{tableIdOrName}/v0/{baseId}/{tableIdOrName}/v0/{baseId}/{tableIdOrName}/{recordId} |
tableFields | Fires when a field (column) changes, like one being added or edited. | /v0/meta/bases/{baseId}/tables/{tableId}/fields/v0/meta/bases/{baseId}/tables/{tableId}/fields/{fieldId} |
tableMetadata | Fires when a table's metadata changes, like its name or description. | /v0/meta/bases/{baseId}/tables/v0/meta/bases/{baseId}/tables/{tableIdOrName}/v0/meta/bases/{baseId}/tables |
Airtable limits how fast an app can call, by a request rate measured per second against each base and a separate ceiling across everything one token does.
Airtable meters requests by rate, not by a per-method cost. Each base allows 5 requests per second, and a single user or service account is capped at 50 requests per second across all its traffic. Going over returns HTTP 429, after which Airtable expects a 30-second wait before requests succeed again. The official JavaScript client retries on 429 automatically; a high-volume integration is advised to add a caching proxy. Write methods that take a batch (create, update, delete) are limited to 10 records per request, which keeps row volume off the request count.
List endpoints page with an opaque offset token rather than page numbers. A response includes an offset only when more records remain, and that value is passed back on the next request to fetch the following page. The record list defaults to 100 records per page (pageSize, up to 100), and maxRecords can cap the total returned. The list-bases endpoint pages the same way, returning up to 1,000 bases at a time.
A batched record write (create, update, or delete) handles at most 10 records per request. filterByFormula and similar parameters are sent in the query string, so an overlong formula can hit URL length limits and is better sent as a POST-style list. Webhook payloads are retained for 7 days, and a webhook itself expires 7 days after creation or its last refresh.
The status codes an agent should handle, and what to do about each.
| Status | Code | Meaning | What to do |
|---|---|---|---|
| 401 | AUTHENTICATION_REQUIRED | No valid token was provided, or it has expired (an OAuth access token lasts 60 minutes). | Send a valid personal access token, or refresh the OAuth access token using the refresh token. |
| 403 | INVALID_PERMISSIONS / NOT_AUTHORIZED | The token is valid but lacks the scope, the base, or the collaborator-level permission the request needs. | Add the missing scope to the token, grant it access to the base, or use an account with the right permission level. |
| 404 | NOT_FOUND / MODEL_ID_NOT_FOUND | The base, table, or record does not exist, or the token cannot see it. | Check the baseId, table, and record id, and confirm the token has access to that base. |
| 422 | INVALID_REQUEST / UNPROCESSABLE_ENTITY | The request was malformed: a field name or type is wrong, a value does not fit the cell, or more than 10 records were sent in one write. | Fix the named field or value, keep batch writes to 10 records, and resend. |
| 429 | TOO_MANY_REQUESTS | The rate limit was exceeded: more than 5 requests per second to one base, or more than 50 per second across one token. | Back off and wait 30 seconds before retrying, then smooth the request rate or add a caching layer. |
| 500 | INTERNAL_SERVER_ERROR | An error on Airtable's side, which can also appear as 502 or 503. It is rare. | Retry with backoff, and contact Airtable support if it persists. |
Airtable runs a single, unversioned Web API under the /v0 path, with no dated version to pin. Changes are additive and announced in a dated changelog.
Airtable runs one Web API under the /v0 path with no dated version to pin. New endpoints and changes are additive and announced in a dated changelog rather than minted as a new version string. Recent additions include enterprise endpoints for retrieving and revoking personal access tokens, base creation from packages, and broader collaborator-retrieval access.
Enterprise admin scopes became available for OAuth integrations without special approval, alongside new enterprise hub and workspace-creation endpoints earlier in the year.
An endpoint to upload an attachment to a cell by sending the file bytes directly was added, along with enterprise hub support and improved OAuth refresh handling.
The deprecation period for the original account-wide API key ended and the key was switched off, leaving personal access tokens and OAuth as the only authentication methods.
Personal access tokens and OAuth reached general availability, the CSV-sync endpoint shipped, and the deprecation of account-wide API keys began, with shutdown set for 1 February 2024.
Airtable launched the beta of personal access tokens, OAuth, service accounts, webhooks, and the metadata and record-comments APIs, the foundation of today's Web API.
There is no version header to set; track the changelog for new endpoints and deprecations.
Airtable Web API changelog ↗Bollard AI sits between a team's AI agents and Airtable. Grant each agent exactly the access it needs, read or write, base by base, and every call is checked and logged.