# Automations with the API

> Create automations from premades or a trigger and steps, change them, switch them on and off, and read their run log and credits with an API key.

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

Build [automations](https://docs.theavoxai.com/automation) from your own code or an AI assistant. Every save is checked
exactly as in the dashboard's builder: each step's settings, the `{{...}}` values each message
uses, and the tables, columns, templates, Flows and apps the automation points at. Needs
`automations:read` / `automations:write` (deleting also needs **Delete automations** for the
person who set the key's permissions). Basics: [Builder API quick start](https://docs.theavoxai.com/avox-api/builder).

The JavaScript examples use the `avox()` helper from [Builder API reference](https://docs.theavoxai.com/avox-api/reference).

## How an automation is made

An automation is a **trigger** (`triggerType` and its `triggerConfig`) and a list of **steps**
(`actions`, each `{ "actionType", "actionConfig" }`, run in order). Every new automation is a
**draft**: it runs only after `POST /api/v1/automations/{automationId}/activate`, which needs at
least one step, no problems, an unpaused Switchboard, approved templates, published Flows, and
room in your plan's automations that are on.

The trigger types, step types and their settings are the ones the builder shows; the full list
is in `GET /api/v1/catalog` (`types.triggerTypes`, `types.actionTypes`) and the schemas are in
[/openapi.json](https://docs.theavoxai.com/openapi.json). See [Automation](https://docs.theavoxai.com/automation) and
[Automations with tables and Flows](https://docs.theavoxai.com/automation/tables) for what each does. The fastest and
safest start is a premade.

Table and column ids in a step's settings are the ids from `GET /api/v1/tables/{tableId}` (not
the keys). Messages use values like `{{contact.first_name}}`, `{{row.price}}` (a table trigger's
row) or `{{order.status|unknown}}` (an earlier Find a row step named `order`, with a fallback).

An automation's fields: `id`, `name`, `status` (`draft`, `active`, `paused`), `triggerType`,
`triggerConfig`, `premadeId`, `stepCount`, `createdAt`, `updatedAt`, `etag`, and with a single
automation, `actions` and `canvas`.

### GET /api/v1/automations

Query: `status`, `limit` (1 to 100), `cursor`.

**curl**

```bash
curl "https://api.avox.com/api/v1/automations?status=active" -H "Authorization: Bearer $AVOX_API_KEY"
```

**JavaScript**

```js
const { data } = await avox("/automations");
```

### POST /api/v1/automations

Creates a draft automation, all or nothing (it's made only when its steps can be saved). Counts
against your plan's automations; send an `Idempotency-Key`.

**From a premade** (ids in `GET /api/v1/catalog`): `premadeId`, and optionally `name`,
`timeZone` (for date and table triggers) and `utcOffsetMinutes` (for Business hours). The premade
is fitted to your Switchboard exactly as the dashboard does it: your table made from the premade
table it needs, your connected app, your approved template made from the Avox template it was
written for. When something's missing, the answer is `automation_not_ready` and `details` lists
each missing table (with the `premadeId` to create it from), app or approved template, and
nothing is made.

**From a trigger and steps:** `name`, `triggerType`, `triggerConfig`, and optionally `actions`.

**curl**

```bash
curl -X POST https://api.avox.com/api/v1/automations \
  -H "Authorization: Bearer $AVOX_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 4e8d2c6a-0b1f-4d7e-9c3a-5f6e7d8c9b0a" \
  -d '{
    "name": "Opening hours reply",
    "triggerType": "keyword",
    "triggerConfig": { "keywords": ["hours", "timing", "open"] },
    "actions": [
      { "actionType": "send_text", "actionConfig": { "body": "Hi {{contact.first_name|there}}! We are open 10 am to 8 pm, Monday to Saturday." } }
    ]
  }'
```

**JavaScript**

```js
const { ok, data, error } = await avox("/automations", {
  method: "POST",
  headers: { "Idempotency-Key": crypto.randomUUID() },
  body: JSON.stringify({ premadeId: "booking_reminder_day", timeZone: "Asia/Kolkata" }),
});
if (!ok && error.code === "automation_not_ready") {
  for (const d of error.details) console.log(d.path, d.message); // what to create first
}
```

Answers `201` with `{ automation, problems }`. `problems` (also in `warnings`) are things that
must be fixed before it can be switched on, each with the step (`actions[2]` or `trigger`) and an
AVX code, like a table that was archived or a template variable with no value.

### GET /api/v1/automations/\{automationId\}

The automation with its trigger and steps, and its current `problems`.

**curl**

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

**JavaScript**

```js
const { data } = await avox(`/automations/${automationId}`);
```

### PATCH /api/v1/automations/\{automationId\}

Changes `name`, `triggerType` (always with its `triggerConfig`), `triggerConfig`, `actions` (the
whole list: steps you leave out are removed) and `canvas`. Changing the steps ends runs that are
waiting for a reply. Switch it on or off with the endpoints below, not here. Send `If-Match` with
the automation's ETag.

**curl**

```bash
curl -X PATCH https://api.avox.com/api/v1/automations/AUTOMATION_ID \
  -H "Authorization: Bearer $AVOX_API_KEY" \
  -H "Content-Type: application/json" \
  -H 'If-Match: "Lp2..."' \
  -d '{ "name": "Opening hours reply (weekdays)" }'
```

**JavaScript**

```js
const { data: current } = await avox(`/automations/${id}`);
const actions = [...current.automation.actions, { actionType: "send_text", actionConfig: { body: "Anything else?" } }];
await avox(`/automations/${id}`, { method: "PATCH", headers: { "If-Match": current.automation.etag }, body: JSON.stringify({ actions }) });
```

### POST /api/v1/automations/\{automationId\}/activate

Switches it on. Refused with `automation_not_ready` (problems, no steps, a template that isn't
approved, a Flow that isn't published; `details` names the step), `switchboard_paused`, or
`plan_limit_reached` (all the automations your plan allows are on).

**curl**

```bash
curl -X POST https://api.avox.com/api/v1/automations/AUTOMATION_ID/activate -H "Authorization: Bearer $AVOX_API_KEY"
```

**JavaScript**

```js
const { ok, error } = await avox(`/automations/${id}/activate`, { method: "POST" });
```

### POST /api/v1/automations/\{automationId\}/deactivate

Switches it off (status `paused`); runs waiting for a reply end.

**curl**

```bash
curl -X POST https://api.avox.com/api/v1/automations/AUTOMATION_ID/deactivate -H "Authorization: Bearer $AVOX_API_KEY"
```

**JavaScript**

```js
await avox(`/automations/${id}/deactivate`, { method: "POST" });
```

### DELETE /api/v1/automations/\{automationId\}

Deletes it for good, with its "Used by" links on tables and templates. Needs
**Delete automations**.

**curl**

```bash
curl -X DELETE https://api.avox.com/api/v1/automations/AUTOMATION_ID -H "Authorization: Bearer $AVOX_API_KEY"
```

**JavaScript**

```js
await avox(`/automations/${id}`, { method: "DELETE" });
```

## Run log and credits

### GET /api/v1/automations/\{automationId\}/runs

Every run, newest first: the contact, what started it, when, how it ended and why, credits and
steps, plus counts per outcome. Query: `from`, `to` (times with their offset, at most 366 days
apart), `outcome`, `trigger`, `limit` (10, 25, 50 or 100), `cursor`.

**curl**

```bash
curl "https://api.avox.com/api/v1/automations/AUTOMATION_ID/runs?limit=25" -H "Authorization: Bearer $AVOX_API_KEY"
```

**JavaScript**

```js
const { data } = await avox(`/automations/${id}/runs?limit=50`);
```

### GET /api/v1/automations/\{automationId\}/runs/\{runId\}

One run step by step: each step, its values, the messages it sent with their status, the rows
it read or wrote, and why it stopped (with the AVX code).

**curl**

```bash
curl https://api.avox.com/api/v1/automations/AUTOMATION_ID/runs/RUN_ID -H "Authorization: Bearer $AVOX_API_KEY"
```

**JavaScript**

```js
const { data } = await avox(`/automations/${id}/runs/${runId}`);
```

### GET /api/v1/automations/\{automationId\}/credits

Credits used this period and all time, per run, per step that costs credits, per day (in `tz`,
an IANA time zone, default UTC), its share of the Switchboard's credits, and next month at the
current pace.

**curl**

```bash
curl "https://api.avox.com/api/v1/automations/AUTOMATION_ID/credits?tz=Asia/Kolkata" -H "Authorization: Bearer $AVOX_API_KEY"
```

**JavaScript**

```js
const { data } = await avox(`/automations/${id}/credits?tz=UTC`);
```

## Errors you might see

| Code | What to do |
| --- | --- |
| [`invalid_payload`](https://docs.theavoxai.com/api/errors#invalid_payload) | Fix the step or trigger setting `details` names, like `actions[1].actionConfig.body`. |
| [`automation_invalid`](https://docs.theavoxai.com/api/errors#automation_invalid) | A `{{...}}` value doesn't exist at that step: fix the name or add a fallback. |
| [`automation_not_ready`](https://docs.theavoxai.com/api/errors#automation_not_ready) | Make what `details` lists (a table, an approved template, a published Flow, a connected app), then try again. |
| [`switchboard_paused`](https://docs.theavoxai.com/api/errors#switchboard_paused) | An Admin resumes the Switchboard first. |
| [`plan_limit_reached`](https://docs.theavoxai.com/api/errors#plan_limit_reached) | Delete or switch off an automation, or move to a bigger plan. |

## Related
