# Builder API quick start

> Build tables, rows, Flows, templates and automations with an Avox API key: permissions, limits, paging, versions and retries.

Source: https://docs.theavoxai.com/avox-api/builder

The **builder API** lets your own code, or an AI assistant you trust, do what you do in the
dashboard's Tables, Flows, Templates and Automation pages: create a table and fill it, write a
template and send it to WhatsApp for review, make and publish a Flow, build an automation and
switch it on. It uses the same Avox API keys as [sending messages](https://docs.theavoxai.com/avox-api), with permissions
you choose per key.

> **Tip**
>
> Using an AI assistant? Give it your key and the page
> [API for AI assistants](https://docs.theavoxai.com/avox-api/ai-assistants): it tells the assistant exactly how to work.

##  Set it up

**1. Create a key with the permissions you need**

In **Settings > API Keys**, click **Create a key**, pick the number, name the key, and under
**What this key may do** set each area to **Off**, **Read** or **Write**. You can only give a key
what you may do yourself. Confirm with the code we email you, then copy the key: it's shown once.
Every key belongs to a WhatsApp number, so the API needs one connected: if the number is removed,
its keys stop with [`connection_not_found`](https://docs.theavoxai.com/api/errors#connection_not_found). If Avox switched a
part off for your account (Tables, for example), its calls answer
[`feature_disabled`](https://docs.theavoxai.com/api/errors#feature_disabled).

**2. Check the key**

Call `GET /api/v1/me`. It shows the key's Switchboard, permissions and every limit with what's used.

**3. Build**

Create a table, add rows, and carry on with templates, Flows and automations. Each area has its
own page: [Tables and rows](https://docs.theavoxai.com/avox-api/tables), [Flows](https://docs.theavoxai.com/avox-api/flows),
[Templates](https://docs.theavoxai.com/avox-api/templates), [Automations](https://docs.theavoxai.com/avox-api/automations).

**curl**

```bash
curl https://api.avox.com/api/v1/me \
  -H "Authorization: Bearer $AVOX_API_KEY"

curl -X POST https://api.avox.com/api/v1/tables \
  -H "Authorization: Bearer $AVOX_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 3c1d6c4e-2f7a-4f0b-9e3a-1b2c3d4e5f60" \
  -d '{
    "name": "Price list",
    "columns": [
      { "key": "item", "name": "Item", "type": "text", "required": true, "unique": true },
      { "key": "price", "name": "Price", "type": "currency", "required": true, "options": { "currency": "INR" } }
    ]
  }'
```

**JavaScript**

```js
const API = "https://api.avox.com/api/v1";
const headers = { Authorization: `Bearer ${process.env.AVOX_API_KEY}`, "Content-Type": "application/json" };

const me = await (await fetch(`${API}/me`, { headers })).json();
console.log(me.data.key.scopes, me.data.limits.tables);

const res = await fetch(`${API}/tables`, {
  method: "POST",
  headers: { ...headers, "Idempotency-Key": crypto.randomUUID() },
  body: JSON.stringify({
    name: "Price list",
    columns: [
      { key: "item", name: "Item", type: "text", required: true, unique: true },
      { key: "price", name: "Price", type: "currency", required: true, options: { currency: "INR" } },
    ],
  }),
});
const { ok, data, error } = await res.json();
if (!ok) throw new Error(`${error.code}: ${error.message}`);
console.log(data.table.id, data.table.etag);
```

## Permissions (scopes)

Each key holds a list of scopes. Keys made before scopes existed hold `send` only, so nothing an
existing key could do changes.

| Scope | Lets the key |
| --- | --- |
| `send` | Send WhatsApp messages with `POST /api/messages/send` ([Avox API](https://docs.theavoxai.com/avox-api)). |
| `tables:read` / `tables:write` | See tables and their columns / create, rename, archive, restore and delete tables, and add, change or delete columns. |
| `rows:read` / `rows:write` | Read, filter and search rows / add, change and delete rows, and import CSV. |
| `flows:read` / `flows:write` | See Flows, their JSON, live data settings, request logs and answers / create, change drafts, publish, deprecate and change live data settings. |
| `templates:read` / `templates:write` | See templates and their review status / create, edit and delete templates. |
| `automations:read` / `automations:write` | See automations, their run log and credits / create, change, switch on and off and delete automations. |

A write scope includes reading the same area. `GET /api/v1/me` and `GET /api/v1/catalog` work
with any key.

A key acts with the permissions of the person who last set its scopes. If that person leaves the
Switchboard or loses a permission (for example **Create and edit tables**), the key's calls in
that area answer `scope_owner_no_access` until an Admin sets its permissions again. Deleting
needs the matching delete permission too (**Delete templates**, **Delete Flows**,
**Delete automations**).

> **Warning**
>
> Write permissions let anything holding the key change your Switchboard. Give them only
> to code or an assistant you trust, keep the key out of browsers and shared files, and revoke it
> when you're done.

## Requests and answers

- **Base address:** `https://api.avox.com/api/v1`. Send `Authorization: Bearer <key>` on every
  request, and JSON bodies with `Content-Type: application/json`.
- **Field names** in bodies and answers use camelCase, the same names the dashboard uses
  (`flowJson`, `triggerType`, `updatedAt`).
- **Success:** `{ "ok": true, "request_id": "req_...", "data": { ... } }`, plus `next_cursor` on
  lists and `warnings` (things to know, nothing failed) when there are some.
- **Errors:** `{ "ok": false, "error": { "code", "message", "docs_url", "request_id", "details" } }`.
  `details` names each field to fix (`path`) with a `message`, and sometimes a short `code`. Every
  code is on [API errors](https://docs.theavoxai.com/api/errors).
- **Ids:** tables can also be addressed by their API name (`slug`), columns by their key. Ids
  from another Switchboard never match: they answer `not_found`.

## Paging

Lists take `limit` and `cursor`. Pass the `next_cursor` of one page as `cursor` to get the next;
`next_cursor` is `null` on the last page. A cursor belongs to its list and filters: changing the
filters with an old cursor answers `invalid_cursor`.

## Versions: ETag and If-Match

Every table, Flow, template and automation answer carries an `ETag` header (and an `etag` field).
To change something safely, send it back as `If-Match`. If anyone changed the item since you read
it, the change is refused with `412 version_conflict` and nothing is written. Read it again and
retry. Rows use their `updatedAt`: send it with each row you change (`rows[].updatedAt`), and the
whole request is refused if any of those rows changed.

## Retries: Idempotency-Key

Every create (tables, rows, row deletes, CSV imports, Flows, templates, automations) accepts an
`Idempotency-Key` header: 1 to 255 visible characters, a UUID per new item works well. Retrying
with the same key and the same body returns the first answer (with `Idempotent-Replayed: true`)
and makes nothing twice. The same key with a different body answers `idempotency_conflict`.
Keys last 24 hours and belong to the key and its rotations. See
[Idempotency](https://docs.theavoxai.com/avox-api/idempotency).

## Limits

- **Your plan's daily builder calls**, reads and writes counted apart, for the whole Switchboard
  (UTC day). `GET /api/v1/me` shows them; every answer has `Avox-Daily-Limit` and
  `Avox-Daily-Remaining` headers. Over the limit: `builder_quota_exceeded` with `Retry-After` until
  midnight UTC. Sending messages doesn't count.
- **Everything your plan already limits** applies exactly as in the dashboard: tables, rows per
  table, Flows, templates, automations (and how many can be on at once), and live data requests a
  month. A request that would go over is refused whole with `plan_limit_reached`.
- **Short bursts** are braked per key and per Switchboard: `rate_limited` with `Retry-After`.
- **Bodies** are capped per endpoint (up to 1,000 rows, or an 8 MB CSV): `payload_too_large`.

See [Plans](https://docs.theavoxai.com/plans) for what each plan includes.

## Test keys

A test key (`avx_test_...`) reads and checks for real (`/me`, `/catalog`, lists, `validate`, a CSV
your code, then switch to a live key.

## Things that stay in the dashboard

Connecting numbers, billing, team members, API keys and their permissions, uploading a sample file
for a template's media header, a Flow's own-server signing secret, and connecting apps.

## Related
