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

# Table API

> Create Airscale tables and read, add, update and delete their columns and rows from your own code.

The Tables API works on the same tables you see in Airscale. Use it to push lists into Airscale, keep them in sync with another system, or read results back out. It never spends credits or starts enrichments: run enrichments in the app on the rows you add.

> [!NOTE]
>
> The Tables API is available on paid plans: an active subscription (including one carried over from Airscale V1) or a custom plan. Other workspaces receive `403` with `code: "subscription_required"`. Access returns within a minute of a plan becoming active.

Base URL: `https://api.airscale.io`. Send your workspace API key as `Authorization: Bearer $AIRSCALE_API_KEY` on every request. See [Authentication](https://docs.airscale.io/api-reference/authentication.md) to get your key.

Browse **Tables** to manage tables, **Row API** to insert and read records, and **Column API** to manage their fields.

## How it fits together

1. [Create a table](https://docs.airscale.io/api-reference/tables/create-table.md) with its columns, or [list tables](https://docs.airscale.io/api-reference/tables/list-tables.md) to find an existing one.
2. Read the column IDs from the response, or from [Get table](https://docs.airscale.io/api-reference/tables/get-table.md). Row values are always keyed by **column ID**, so renaming a column never breaks your integration.
3. [Insert rows](https://docs.airscale.io/api-reference/tables/insert-rows.md) in batches of up to 1,000, then [list rows](https://docs.airscale.io/api-reference/tables/list-rows.md) to read them back.
4. [Update](https://docs.airscale.io/api-reference/tables/update-rows.md) or [delete](https://docs.airscale.io/api-reference/tables/delete-rows.md) rows by row ID.

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl https://api.airscale.io/v1/tables \
  -H "Authorization: Bearer $AIRSCALE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Prospects","columns":[{"label":"Name"},{"label":"Email","type":"email"}]}'
```

## Endpoints

| Endpoint | What it does |
| - | - |
| [List tables](https://docs.airscale.io/api-reference/tables/list-tables.md) | `GET /v1/tables` |
| [Create table](https://docs.airscale.io/api-reference/tables/create-table.md) | `POST /v1/tables` |
| [Get table](https://docs.airscale.io/api-reference/tables/get-table.md) | `GET /v1/tables/{table_id}` |
| [Delete table](https://docs.airscale.io/api-reference/tables/delete-table.md) | `DELETE /v1/tables/{table_id}` |
| [Add column](https://docs.airscale.io/api-reference/tables/add-column.md) | `POST /v1/tables/{table_id}/columns` |
| [Rename column](https://docs.airscale.io/api-reference/tables/rename-column.md) | `PATCH /v1/tables/{table_id}/columns/{column_id}` |
| [Delete column](https://docs.airscale.io/api-reference/tables/delete-column.md) | `DELETE /v1/tables/{table_id}/columns/{column_id}` |
| [List rows](https://docs.airscale.io/api-reference/tables/list-rows.md) | `GET /v1/tables/{table_id}/rows` |
| [Insert rows](https://docs.airscale.io/api-reference/tables/insert-rows.md) | `POST /v1/tables/{table_id}/rows` |
| [Update rows](https://docs.airscale.io/api-reference/tables/update-rows.md) | `PATCH /v1/tables/{table_id}/rows` |
| [Delete rows](https://docs.airscale.io/api-reference/tables/delete-rows.md) | `POST /v1/tables/{table_id}/rows/delete` |
| [Get row](https://docs.airscale.io/api-reference/tables/get-row.md) | `GET /v1/tables/{table_id}/rows/{row_id}` |
| [Update row](https://docs.airscale.io/api-reference/tables/update-row.md) | `PATCH /v1/tables/{table_id}/rows/{row_id}` |
| [Delete row](https://docs.airscale.io/api-reference/tables/delete-row.md) | `DELETE /v1/tables/{table_id}/rows/{row_id}` |

## Column types and values

| Column type | Accepted values |
| - | - |
| `text`, `email`, `phone`, `url` | A string, or `null`. Emails, phone numbers and URLs are stored as sent; they are not validated or normalized. |
| `number` | A finite JSON number, or `null`. `"42"` as a string is rejected. |
| `json` | Any JSON value. |

Enrichment, formula, date and email-deliverability columns are **read-only** through the API. Their values appear when you read rows. Enrichment results that are stored separately because of their size are returned as `null`.

In updates, only the cells you send change, and `null` clears a cell. An invalid value or a read-only column rejects the whole request, and nothing changes.

## Limits

Limits are shared by all API keys of a workspace.

| Limit | Value |
| - | - |
| Reads (`GET`) | 30 requests per minute per workspace |
| Writes (`POST`, `PATCH`, `DELETE`) | 10 requests per minute per workspace |
| Writes at the same time | 1 per workspace. A second write gets `429` with `code: "write_in_progress"`; send writes one after another. |
| Rows inserted, updated or deleted | 5,000 per minute and 100,000 per UTC day per workspace. A 1,000-row batch counts as 1,000. |
| Tables created | 50 per UTC day per workspace |
| Column changes (add, rename, delete) | 100 per UTC day per workspace |
| Per API key | 60 requests per minute |
| Batch size | 1,000 rows per request, 8 MiB per request body |

Daily limits reset at 00:00 UTC. A request that would go over a daily limit returns `429` with `code: "daily_quota_exceeded"` and uses up nothing, so a smaller batch can still succeed; the message says how much is left today. Allowance is counted when a request is received, so a batch later rejected as invalid still counts.

Every `429` and `503` response includes `Retry-After` in seconds. Wait at least that long before retrying.

## Retries

For Create table, Insert rows, Add column and Delete rows (batch), send an optional `Idempotency-Key` header. Use the same key and identical body when retrying the same operation: the API returns the original response without repeating the mutation. Reusing the key for a different body returns `409 idempotency_conflict`. Use a new key for each new operation.

PATCH and single-resource DELETE endpoints do not support this header. After an uncertain response, read the current state before retrying so you do not overwrite a later edit. A repeated single-resource delete returns `404` once the resource is gone. Without an idempotency key, retrying Insert rows can create duplicates.

## Deletes

Deleted tables and rows disappear from the API and from the app. They are not in any member's Undo history; contact support to restore them. **Deleting a column is permanent**: its values are removed from every row and cannot be restored.

## Errors

Errors use one shape:

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{ "error": { "code": "invalid_value", "message": "Invalid value for column … (number)" } }
```

Use `code` in your code and treat `message` as an explanation.

| Status | Common codes |
| - | - |
| `400` | `invalid_request`, `invalid_json`, `unknown_column`, `read_only_column`, `invalid_value`, `invalid_cursor` |
| `401` | `invalid_api_key` |
| `403` | `subscription_required` |
| `404` | `table_not_found`, `row_not_found`, `column_not_found` |
| `409` | `table_name_conflict`, `column_label_conflict`, `table_operation_conflict`, `active_enrichment` |
| `413` | `request_body_too_large`, `row_too_large` |
| `429` | `rate_limited`, `write_in_progress`, `daily_quota_exceeded` |
| `503` | `capacity_busy`, `service_unavailable` |

## Next step

Review [Authentication](https://docs.airscale.io/api-reference/authentication.md), then [create your first table](https://docs.airscale.io/api-reference/tables/create-table.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.