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

# Run an Automation

> Start and track an Automation run for one contact.

<Note>
  **Private Beta.** New organizations are enabled by default. An organization administrator must create a scoped API key in Brightalk Settings before requests can authenticate. This documentation and the OpenAPI contract define the available scope and limits.
</Note>

This flow selects an active dashboard-managed Automation, starts it for one contact, and tracks the asynchronous Automation run API resource.

## Prerequisites

* A server-side `bt_live_` key with the exact pair `automations:run` and `automations:read`.
* An active Automation visible to the organization and one existing or inline contact reference.
* A unique, nonsecret `Idempotency-Key` for the logical run.
* An understanding that the Automation—not the API request—owns its agent, waits, retry rules, and branching.

## Select an active Automation

List summaries with `automations:read`, then select an item whose `status` is `active`.

Save JavaScript samples as `.mjs` or run them in an ESM project. Their top-level `await` requires ESM, and Node 18 or later provides the built-in `fetch` they use.

<CodeGroup>
  ```curl theme={null}
  curl --request GET 'https://api.brightalk.ai/automations?status=active&limit=20' \
    --header "Authorization: Bearer $BRIGHTALK_API_KEY" \
    --header "Brightalk-Version: 2026-07-16"
  ```

  ```javascript theme={null}
  const response = await fetch("https://api.brightalk.ai/automations?status=active&limit=20", {
    method: "GET",
    headers: {
      Authorization: `Bearer ${process.env.BRIGHTALK_API_KEY}`,
      "Brightalk-Version": "2026-07-16",
    },
  });
  console.log(response.status, await response.json());
  ```

  ```python theme={null}
  import os
  import requests

  response = requests.request(
      "GET",
      "https://api.brightalk.ai/automations?status=active&limit=20",
      headers={
      "Authorization": f"Bearer {os.environ['BRIGHTALK_API_KEY']}",
      "Brightalk-Version": "2026-07-16",
      },
  )
  print(response.status_code, response.json())
  ```
</CodeGroup>

Current launch summaries declare no API inputs:

```json theme={null}
{
  "data": [
    {
      "id": "atm_demo_001",
      "name": "Renewal follow-up",
      "description": "Calls one contact and records the outcome.",
      "status": "active",
      "input_fields": []
    }
  ],
  "next_cursor": null
}
```

## Start the run

Because `input_fields` is empty, omit `input` as the canonical sample does, or send `{}` only.

<Warning>
  Starting an Automation can place real PSTN calls according to its dashboard-managed definition. Verify the Automation, contact, configured behavior, and timing before sending this mutation.
</Warning>

<CodeGroup>
  ```curl theme={null}
  curl --request POST 'https://api.brightalk.ai/automation-runs' \
    --header "Authorization: Bearer $BRIGHTALK_API_KEY" \
    --header "Brightalk-Version: 2026-07-16" \
    --header "Content-Type: application/json" \
    --header "Idempotency-Key: createAutomationRun-example-001" \
    --data '{"automation_id":"atm_demo_001","contact_id":"con_demo_001"}'
  ```

  ```javascript theme={null}
  const response = await fetch("https://api.brightalk.ai/automation-runs", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.BRIGHTALK_API_KEY}`,
      "Brightalk-Version": "2026-07-16",
      "Content-Type": "application/json",
      "Idempotency-Key": "createAutomationRun-example-001",
    },
    body: JSON.stringify({"automation_id":"atm_demo_001","contact_id":"con_demo_001"}),
  });
  console.log(response.status, await response.json());
  ```

  ```python theme={null}
  import os
  import requests

  response = requests.request(
      "POST",
      "https://api.brightalk.ai/automation-runs",
      headers={
      "Authorization": f"Bearer {os.environ['BRIGHTALK_API_KEY']}",
      "Brightalk-Version": "2026-07-16",
      "Content-Type": "application/json",
      "Idempotency-Key": "createAutomationRun-example-001",
      },
      json={"automation_id":"atm_demo_001","contact_id":"con_demo_001"},
  )
  print(response.status_code, response.json())
  ```
</CodeGroup>

Only a nonempty `input_fields` declaration returned by the API permits input, and then only the exactly named fields may be sent.

## Expected response

The API returns `202 Accepted`. Save the Automation run API resource `id`.

```json theme={null}
{
  "id": "run_demo_001",
  "automation_id": "atm_demo_001",
  "contact_id": "con_demo_001",
  "input": {},
  "queued_at": "2026-07-20T01:00:00Z",
  "created_at": "2026-07-20T01:00:00Z",
  "updated_at": "2026-07-20T01:00:00Z",
  "status": "queued"
}
```

## Poll and cancel

| Action | Endpoint                                | Next action                                                                                        |
| ------ | --------------------------------------- | -------------------------------------------------------------------------------------------------- |
| Poll   | `GET /automation-runs/{run_id}`         | Use backoff while `queued`, `running`, or `waiting`; stop at `completed`, `failed`, or `cancelled` |
| Cancel | `POST /automation-runs/{run_id}/cancel` | Prevent queued work or request cancellation between step boundaries                                |

Polling needs `automations:read`; cancellation needs `automations:run`. Cancellation accepts an optional `Idempotency-Key` and remains best-effort for a step already executing.

## Common errors

| Error                     | What to check                                                                           |
| ------------------------- | --------------------------------------------------------------------------------------- |
| `insufficient_scope`      | The key has `automations:run` for start/cancel and `automations:read` for list/poll     |
| `resource_not_found`      | The Automation and contact belong to and are visible to this organization               |
| `resource_state_conflict` | The selected Automation is `active` and the requested transition fits current run state |
| `validation_error`        | `input` is omitted or `{}` while `input_fields` is empty                                |
| `duplicate_active_run`    | Use the safe `existing_run_id` details to retrieve the already active run               |
| `idempotency_conflict`    | A reused key has the same Automation, contact, and semantic body                        |
