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

# Automations

> Run your own scripts inside CallVA - on a call's events, on a schedule, over HTTP or on demand - with project variables and secrets, run history and logs, and runs traced back to the call they handled.

An automation is a script that CallVA hosts and runs for one project. Use it to react to a finished call, sync results into a CRM, send a follow-up SMS, prepare a batch of calls every night, or hand an agent fresh data in the middle of a conversation - without running a server of your own.

Automations run on [Windmill](https://www.windmill.dev), the workflow engine embedded in CallVA. You never talk to Windmill directly: you create, deploy, run and read automations through the CallVA API, the [CLI](https://docs.callva.io/cli.md) or [MCP](https://docs.callva.io/mcp.md), and CallVA keeps each project's scripts, variables and runs in a folder of its own.

```bash theme={null}
export CALLVA_API="https://api.callva.io/api/v1/external"
export CALLVA_TOKEN="<your API token>"
```

Permissions: `automations.read` to list and read automations and runs, `automations.create`, `automations.update` (also deploying code), `automations.delete`, and `automations.manage` to run an automation and manage its HTTP triggers. Variables have `variables.read`, `variables.create`, `variables.update`, `variables.delete`. See [Authentication](https://docs.callva.io/authentication.md).

## How an automation runs

```mermaid theme={null}
flowchart LR
    subgraph Start["What starts a run"]
        E["Call event webhook<br/>call.ended, ..."]
        T["Agent tool or<br/>start-of-call config URL"]
        S["Webhook schedule<br/>target_type: automation"]
        X["Your system<br/>or POST /automations/{id}/run"]
    end
    E -->|HTTP trigger URL| R
    T -->|HTTP trigger URL| R
    X --> R
    S -->|no arguments| R
    R["Run (job)<br/>args matched to main() by name"] --> V["Reads variables<br/>and secrets"]
    R --> O["Result + logs<br/>GET /automations/{id}/runs/{jobId}"]
    R -->|"PUT /calls/{id}"| C["Call record<br/>fields written back"]
    O --> P["GET /calls/{id}/automation-runs<br/>when args carry call.id"]
```

There are four ways in:

| Way | How | Arguments the script receives |
| - | - | - |
| On demand | [Run an automation](https://docs.callva.io/api-reference/automations/run-an-automation.md) | The `input` object you send. |
| Over HTTP | An [HTTP trigger](#http-triggers) gives the automation a URL. Anything that can POST JSON can start it: an agent's [call event webhook](https://docs.callva.io/guides/webhooks.md#call-event-webhooks), an agent's `http_request` tool during a call, the agent's custom config URL at the start of a call, or an outside system. | The JSON body of the request. |
| On a schedule | A [webhook schedule](https://docs.callva.io/guides/webhooks.md#webhook-schedules) with `target_type: "automation"` and an `automation_id`. | None: every parameter takes its default. |
| From another automation | Import its exported function by path, or start it as a sub-job. | Whatever the caller passes. |

Over HTTP and on demand, the JSON object's top-level keys are matched to the parameters of the script's `main` **by name**. Key order does not matter, a missing key takes the parameter's default, and keys `main` does not declare are carried in the run's `args` but not passed in. So a script receiving a call event webhook declares the envelope keys it needs:

```typescript theme={null}
// Receives the call.ended envelope: { event, id, timestamp, call, agent, livekit, recording, ... }
export async function main(event: string = "", call: { id?: string; status?: string } = {}) {
  if (event !== "call.ended" || !call.id) return { status: "skipped", reason: "not a finished call" };
  // ...
}
```

## The runtime

* **Language.** Write TypeScript for Deno and deploy it with `"language": "deno"`. A new automation starts from a TypeScript scaffold; the code endpoint also accepts `bun`, `python3`, `bash`, `go` and `nativets`. Deno scripts import npm packages with `npm:` specifiers, for example `npm:windmill-client@1`.
* **Sandbox.** Outbound `fetch()` is allowed; there is no host filesystem. Other scripts of the same project can be imported by path.
* **Timeout.** Every run has the same ceiling, set by the platform and not per automation. [Get the automation runtime](https://docs.callva.io/api-reference/automations/get-the-automation-runtime.md) reports it as `max_timeout_seconds`.
* **Versions.** Each code deploy is a new immutable version identified by a `hash`. Roll back by deploying the earlier code again. Right after a deploy, Windmill resolves the script's dependencies for a few seconds before it can run.

```bash theme={null}
curl "$CALLVA_API/automations/runtime-info" \
  -H "Authorization: Bearer $CALLVA_TOKEN" \
  -H "Accept: application/json"
```

```json theme={null}
{
  "success": true,
  "message": "Runtime info retrieved successfully",
  "data": {
    "engine": "windmill",
    "version": "CE v1.680.0",
    "workspace": "dev",
    "docs": "https://www.windmill.dev/docs",
    "llms_txt": "https://www.windmill.dev/llms.txt",
    "typescript_docs": "https://www.windmill.dev/docs/getting_started/scripts_quickstart/typescript",
    "variables_docs": "https://www.windmill.dev/docs/core_concepts/variables_and_secrets",
    "jobs_docs": "https://www.windmill.dev/docs/core_concepts/jobs",
    "scripts_runtime": "deno",
    "max_timeout_seconds": 600
  }
}
```

The values above are what the development environment answers; read your own before relying on a timeout.

## Variables and secrets

Variables hold the configuration and credentials your scripts read at run time: API keys, base URLs, labels. Never put a secret in a script's source.

Each variable belongs to the project and lives at `f/proj_<last 12 hex digits of the project id>/<NAME>`. Names are upper case letters, digits and underscores, starting with a letter. `is_secret` defaults to `true`; a secret's value is never returned by the API once stored.

[Create a variable](https://docs.callva.io/api-reference/variables/create-a-variable.md):

```bash theme={null}
curl -X POST "$CALLVA_API/variables" \
  -H "Authorization: Bearer $CALLVA_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"name": "OUTCOME_LABEL", "value": "reviewed", "description": "Label the tagging automation writes", "is_secret": false}'
```

```json Response 201 theme={null}
{
  "success": true,
  "message": "Variable created successfully",
  "data": {
    "name": "OUTCOME_LABEL",
    "path": "f/proj_61ffbf9e4ef2/OUTCOME_LABEL",
    "description": "Label the tagging automation writes",
    "is_secret": false
  }
}
```

[List variables](https://docs.callva.io/api-reference/variables/list-variables.md) returns every variable of the project at once, without pagination. Only non-secret variables carry their `value`:

```bash theme={null}
curl "$CALLVA_API/variables" \
  -H "Authorization: Bearer $CALLVA_TOKEN" \
  -H "Accept: application/json"
```

```json theme={null}
{
  "success": true,
  "message": "Variables retrieved successfully",
  "data": [
    {
      "name": "OUTCOME_LABEL",
      "path": "f/proj_61ffbf9e4ef2/OUTCOME_LABEL",
      "description": "Label the tagging automation writes",
      "is_secret": false,
      "value": "reviewed"
    }
  ]
}
```

[Update](https://docs.callva.io/api-reference/variables/update-a-variable.md) and [delete](https://docs.callva.io/api-reference/variables/delete-a-variable.md) address a variable by its full path; a path outside the project's folder is refused with `403`. An empty `value` clears the variable.

```bash theme={null}
curl -X PATCH "$CALLVA_API/variables/f/proj_61ffbf9e4ef2/OUTCOME_LABEL" \
  -H "Authorization: Bearer $CALLVA_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"value": "reviewed-by-automation"}'
```

```json theme={null}
{ "success": true, "message": "Variable updated successfully" }
```

A script reads a variable by path with the Windmill client:

```typescript theme={null}
import * as wmill from "npm:windmill-client@1";

const label = await wmill.getVariable("f/proj_61ffbf9e4ef2/OUTCOME_LABEL");
```

To let a script call CallVA, create an API token for the project and store it as a secret variable (for example `CALLVA_API_KEY`), with the API base URL beside it as a non-secret one (`CALLVA_API_URL`). The token's role decides what the script may do.

## Build, run and read an automation

**1. Create the automation**

[Create an automation](https://docs.callva.io/api-reference/automations/create-an-automation.md) with a `name` and an optional `description`. CallVA deploys a scaffold script at a path derived from the name, so the automation can run straight away.

```bash theme={null}
curl -X POST "$CALLVA_API/automations" \
  -H "Authorization: Bearer $CALLVA_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"name": "Tag finished call", "description": "Labels a call once it has ended"}'
```

```json Response 201 theme={null}
{
  "success": true,
  "message": "Automation created successfully",
  "data": {
    "id": "01a1c74f-0c67-7217-a394-d12abd710843",
    "project_id": "01a1c749-5525-731a-ab9f-61ffbf9e4ef2",
    "tenant_id": "01a1c749-5387-7002-8154-5a7913629e6e",
    "name": "Tag finished call",
    "description": "Labels a call once it has ended",
    "windmill_workspace": "dev",
    "windmill_path": "f/proj_61ffbf9e4ef2/tag_finished_call",
    "windmill_script_hash": "e7afc8ed1cc3d3c0",
    "is_active": true,
    "created_by": null,
    "created_at": "2026-11-10T21:13:28.000000Z",
    "updated_at": "2026-11-10T21:13:28.000000Z"
  }
}
```

The `windmill_path` is fixed at creation: renaming the automation later does not move it.

**2. Deploy your code**

Write the script. This one takes the call as a nested `call` object - the shape that makes its runs findable under the call - reads a variable, logs with phase tags, and returns a structured result:

```typescript tag_finished_call.ts theme={null}
import * as wmill from "npm:windmill-client@1";

type Call = { id?: string };

export async function main(call: Call = {}, dry_run: boolean = false) {
  const t0 = Date.now();
  console.log(`[INIT] call=${call.id ?? "none"} dry_run=${dry_run}`);

  const label = await wmill.getVariable("f/proj_61ffbf9e4ef2/OUTCOME_LABEL");
  console.log(`[FETCH] label=${label} (${Date.now() - t0}ms)`);

  return { status: dry_run ? "dry_run" : "success", call_id: call.id ?? null, label };
}
```

[Replace the automation's code](https://docs.callva.io/api-reference/automations/replace-an-automations-code.md) with `code` and `language`:

```bash theme={null}
curl -X PUT "$CALLVA_API/automations/01a1c74f-0c67-7217-a394-d12abd710843/code" \
  -H "Authorization: Bearer $CALLVA_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --rawfile code tag_finished_call.ts '{language: "deno", code: $code}')"
```

```json theme={null}
{
  "success": true,
  "message": "Automation code deployed successfully",
  "data": { "hash": "66bea39482c58910" }
}
```

When Windmill refuses the code, the answer carries `errors.deployment_state`: `previous_active` means the version that was live before is still the one that runs.

**3. Read the code back**

[Get an automation's code](https://docs.callva.io/api-reference/automations/get-an-automations-code.md) returns what is live, with its language, hash and timeout:

```bash theme={null}
curl "$CALLVA_API/automations/01a1c74f-0c67-7217-a394-d12abd710843/code" \
  -H "Authorization: Bearer $CALLVA_TOKEN" \
  -H "Accept: application/json"
```

```json theme={null}
{
  "success": true,
  "message": "Automation code retrieved successfully",
  "data": {
    "code": "import * as wmill from \"npm:windmill-client@1\";\n\ntype Call = { id?: string };\n\nexport async function main(call: Call = {}, dry_run: boolean = false) {\n ...",
    "language": "deno",
    "hash": "66bea39482c58910",
    "schema": null,
    "timeout_seconds": 600
  }
}
```

**4. Run it**

[Run an automation](https://docs.callva.io/api-reference/automations/run-an-automation.md). The arguments go in `input`; the answer is the run's `job_id` as soon as the run is queued. An inactive automation answers `422` `Automation is not active`.

```bash theme={null}
curl -X POST "$CALLVA_API/automations/01a1c74f-0c67-7217-a394-d12abd710843/run" \
  -H "Authorization: Bearer $CALLVA_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"input": {"call": {"id": "01a1c757-6d11-729b-8c19-66fd177e26cd"}, "dry_run": true}}'
```

```json theme={null}
{
  "success": true,
  "message": "Automation triggered successfully",
  "data": { "job_id": "01a1c757-8ad6-4429-132d-75981b62c808" }
}
```

**5. Read the run**

[Get an automation run](https://docs.callva.io/api-reference/automations/get-an-automation-run.md) returns its arguments, result, logs and timing:

```bash theme={null}
curl "$CALLVA_API/automations/01a1c74f-0c67-7217-a394-d12abd710843/runs/01a1c757-8ad6-4429-132d-75981b62c808" \
  -H "Authorization: Bearer $CALLVA_TOKEN" \
  -H "Accept: application/json"
```

```json Response (trimmed) theme={null}
{
  "success": true,
  "message": "Run detail retrieved successfully",
  "data": {
    "type": "CompletedJob",
    "id": "01a1c757-8ad6-4429-132d-75981b62c808",
    "created_at": "2026-11-10T21:22:45.589427Z",
    "started_at": "2026-11-10T21:22:45.603290Z",
    "completed_at": "2026-11-10T21:22:45.724603Z",
    "duration_ms": 117,
    "success": true,
    "canceled": false,
    "script_hash": "66bea39482c58910",
    "script_path": "f/proj_61ffbf9e4ef2/tag_finished_call",
    "args": { "dry_run": true, "call": { "id": "01a1c757-6d11-729b-8c19-66fd177e26cd" } },
    "result": { "label": "reviewed-by-automation", "status": "dry_run", "call_id": "01a1c757-6d11-729b-8c19-66fd177e26cd" },
    "logs": "job=01a1c757-8ad6-4429-132d-75981b62c808 tag=deno ...\n\n--- DENO CODE EXECUTION ---\n\n[INIT] call=01a1c757-6d11-729b-8c19-66fd177e26cd dry_run=true\n[FETCH] label=reviewed-by-automation (21ms)",
    "job_kind": "script",
    "language": "deno",
    ...
  }
}
```

A run still in progress has `"type": "QueuedJob"` and no `result` yet; read it again until it is a `CompletedJob`. A failed run has `"success": false`; read its `result` and `logs` for the error.

> [!TIP]
>
> The `callva` CLI wraps the same loop: `callva automations create`, `callva automations deploy <id> --file tag_finished_call.ts`, `callva automations run <id> --args '{"dry_run":true}'`, `callva automations runs <id>` and `callva automations run-detail <id> <job_id>`. See [CLI](https://docs.callva.io/cli.md).

### Writing back to the call

An automation that handles a call usually ends by writing what it found onto the call record, through [Update a call](https://docs.callva.io/api-reference/calls/update-a-call.md). The body is the call's [custom fields](https://docs.callva.io/guides/custom-fields.md) by key; only the fields you send change.

```typescript theme={null}
import * as wmill from "npm:windmill-client@1";

const NS = "f/proj_61ffbf9e4ef2";

async function updateCall(baseUrl: string, apiKey: string, callId: string, fields: Record<string, unknown>) {
  const resp = await fetch(`${baseUrl}/calls/${callId}`, {
    method: "PUT",
    headers: { Authorization: `Bearer ${apiKey}`, Accept: "application/json", "Content-Type": "application/json" },
    body: JSON.stringify(fields),
  });
  if (!resp.ok) throw new Error(`[UPDATE] ${resp.status}: ${await resp.text()}`);
  return resp.json();
}

export async function main(call: { id?: string } = {}, dry_run: boolean = false) {
  if (!call.id) return { status: "failed", error: "no call id" };

  const [apiKey, baseUrl, label] = await Promise.all([
    wmill.getVariable(`${NS}/CALLVA_API_KEY`),
    wmill.getVariable(`${NS}/CALLVA_API_URL`),
    wmill.getVariable(`${NS}/OUTCOME_LABEL`),
  ]);

  const fields = { review_label: label }; // a text custom field defined in the project
  if (dry_run) return { status: "dry_run", call_id: call.id, would_write: fields };

  await updateCall(baseUrl, apiKey, call.id, fields);
  return { status: "success", call_id: call.id, written: fields };
}
```

Return an object with at least a `status` and enough detail to debug a run without redeploying, and default every parameter so the script also runs from a schedule. A mutating script should accept `dry_run` and be tried with it first.

## HTTP triggers

An HTTP trigger gives an automation a URL. [Create an automation trigger](https://docs.callva.io/api-reference/automation-triggers/create-an-automation-trigger.md):

**http\_method** `string` *required*

`post` or `get`.

**request\_type** `string` *required*

`async` answers at once with the run's job id. `sync` waits for the run and answers with its result - use it where the caller needs the answer, such as an agent's custom config URL or a tool the agent calls mid-conversation.

**auth\_method** `string` *required*

`none` or `signature`. With `signature`, `secret` (at least 8 characters) is required and CallVA stores it as a secret variable of the project.

**route\_path** `string`

The last segment of the URL: lower-case letters, digits, `-` and `_`, up to 100 characters. Defaults to the last 12 characters of the automation id. Route paths are shared across the whole automation engine, so pick one that is specific to you.

```bash theme={null}
curl -X POST "$CALLVA_API/automations/01a1c74f-0c67-7217-a394-d12abd710843/triggers" \
  -H "Authorization: Bearer $CALLVA_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"auth_method": "none", "http_method": "post", "request_type": "async", "route_path": "docs-tag-finished-call"}'
```

```json Response 201 (trimmed) theme={null}
{
  "success": true,
  "message": "HTTP trigger created successfully",
  "data": {
    "path": "f/proj_61ffbf9e4ef2/trigger_docs-tag-finished-call",
    "script_path": "f/proj_61ffbf9e4ef2/tag_finished_call",
    "mode": "enabled",
    "route_path": "docs-tag-finished-call",
    "request_type": "async",
    "authentication_method": "none",
    "http_method": "post",
    "authentication_resource_path": null,
    "workspaced_route": false,
    "webhook_url": "https://<automation host>/api/r/docs-tag-finished-call",
    ...
  }
}
```

`webhook_url` is the address to call; its host is the automation engine of the CallVA environment you work in, and the API returns the full address. An async trigger answers with the job id; a sync trigger answers with the run's result:

```bash async theme={null}
curl -X POST "$TRIGGER_URL" \
  -H "Content-Type: application/json" \
  -d '{"event": "call.ended", "call": {"id": "01a1c757-6d11-729b-8c19-66fd177e26cd", "status": "completed"}, "dry_run": true}'
# 201
# 01a1c757-f3be-a34c-3791-fb7873637401
```

```bash sync theme={null}
curl -X POST "$TRIGGER_URL" \
  -H "Content-Type: application/json" \
  -d '{"call": {"id": "01a1c757-6d11-729b-8c19-66fd177e26cd"}, "dry_run": true}'
# 200
# {"label": "reviewed-by-automation", "status": "dry_run", "call_id": "01a1c757-6d11-729b-8c19-66fd177e26cd"}
```

To run an automation on a call's events, put its trigger URL in the agent's `custom_webhook_url` and choose the events in `custom_webhook_events` (see [Call event webhooks](https://docs.callva.io/guides/webhooks.md#configure-the-receiving-url)). Each event then starts one run with the envelope as its arguments, and because the envelope nests the call under `call`, every such run appears under the call.

[List automation triggers](https://docs.callva.io/api-reference/automation-triggers/list-automation-triggers.md), [update one](https://docs.callva.io/api-reference/automation-triggers/update-an-automation-trigger.md) (`http_method`, `request_type`, `route_path`, `auth_method`, `secret`), [turn one on or off](https://docs.callva.io/api-reference/automation-triggers/toggle-an-automation-trigger.md) and [delete one](https://docs.callva.io/api-reference/automation-triggers/delete-an-automation-trigger.md) address it by its `path`. A disabled trigger answers its URL with `404`. A change to a trigger can take a few seconds to reach its URL.

```bash theme={null}
curl -X POST "$CALLVA_API/automations/01a1c74f-0c67-7217-a394-d12abd710843/triggers/f/proj_61ffbf9e4ef2/trigger_docs-tag-finished-call/toggle" \
  -H "Authorization: Bearer $CALLVA_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"enabled": false}'
```

```json theme={null}
{ "success": true, "message": "Trigger mode updated successfully", "data": { "enabled": false } }
```

> [!WARNING]
>
> A trigger with `auth_method: "none"` runs for anyone who knows its URL. A trigger created with `auth_method: "signature"` currently refuses every request with `404` (`Resource ... not found`), so it cannot be used yet. Until it can, treat the URL as the secret: use a long, unguessable `route_path`, and have the script confirm what it is told (for example by reading the call from the API) before it changes anything.

## Runs

Three views list runs. Each run carries Windmill's job fields; the project-wide views add a normalised `status` (`success`, `failed`, `running`, `queued`, `canceled`), a `triggered_by` (`webhook` for HTTP-trigger runs; runs started through the API and by a schedule are both reported as `schedule`; `api` for the rest, such as the dependency jobs after a deploy), and the `automation_id` and `automation_name` it belongs to.

### One automation's runs

[List an automation's runs](https://docs.callva.io/api-reference/automations/list-an-automations-runs.md), newest first. Pages have no `total`; page with `page` and `per_page` (default 20) until a page comes back short. The list also contains the short `dependencies` jobs Windmill runs after each deploy (`job_kind: "dependencies"`).

```bash theme={null}
curl "$CALLVA_API/automations/01a1c74f-0c67-7217-a394-d12abd710843/runs?per_page=3" \
  -H "Authorization: Bearer $CALLVA_TOKEN" \
  -H "Accept: application/json"
```

```json Response (trimmed) theme={null}
{
  "success": true,
  "message": "Automation runs retrieved successfully",
  "data": [
    {
      "type": "CompletedJob",
      "id": "01a1c757-f3be-a34c-3791-fb7873637401",
      "created_at": "2026-11-10T21:23:12.445563Z",
      "duration_ms": 95,
      "success": true,
      "script_path": "f/proj_61ffbf9e4ef2/tag_finished_call",
      "args": null,
      "job_kind": "script",
      ...
    },
    {
      "type": "CompletedJob",
      "id": "01a1c757-a50f-adaf-96f9-4a253ce3767c",
      "created_at": "2026-11-10T21:22:52.302577Z",
      "duration_ms": 104,
      "success": true,
      "job_kind": "script",
      ...
    },
    ...
  ],
  "pagination": { "current_page": 1, "per_page": 3, "total": null, "last_page": null, "from": 1, "to": 3 }
}
```

This view leaves `args` empty; read a run's arguments with the run detail or the project-wide view below.

### Every automation's runs

[List all automation runs](https://docs.callva.io/api-reference/automations/list-all-automation-runs.md) in the project, with filters:

| Query parameter | Meaning |
| - | - |
| `automation` | One automation's id. |
| `status` | `success`, `failed`, `running`, `queued`, `canceled`. |
| `triggered_by` | `webhook`, `schedule` or `api`. |
| `started_after`, `started_before` | Time range. |
| `args`, `result` | JSON containment filters on arguments and result, as a JSON string, for example `args={"call":{"id":"..."}}`. Invalid JSON is refused with `422`. |
| `include_args` | `true` to include each run's `args`. |
| `sort` | `-started_at` (default, newest first) or `started_at`. |
| `page`, `per_page` | `per_page` defaults to 30, at most 1000. `total` counts within the newest 1000 runs. |

```bash theme={null}
curl "$CALLVA_API/automations/runs?automation=01a1c74f-0c67-7217-a394-d12abd710843&triggered_by=webhook&include_args=true&per_page=1" \
  -H "Authorization: Bearer $CALLVA_TOKEN" \
  -H "Accept: application/json"
```

```json Response (trimmed) theme={null}
{
  "success": true,
  "message": "Automation runs retrieved successfully",
  "data": [
    {
      "type": "CompletedJob",
      "id": "01a1c757-f3be-a34c-3791-fb7873637401",
      "created_by": "HTTP-f/proj_61ffbf9e4ef2/trigger_docs-tag-finished-call",
      "created_at": "2026-11-10T21:23:12.445563Z",
      "duration_ms": 95,
      "success": true,
      "script_path": "f/proj_61ffbf9e4ef2/tag_finished_call",
      "args": {
        "dry_run": true,
        "call": { "id": "01a1c757-6d11-729b-8c19-66fd177e26cd", "status": "completed" },
        "event": "call.ended"
      },
      "status": "success",
      "triggered_by": "webhook",
      "automation_id": "01a1c74f-0c67-7217-a394-d12abd710843",
      "automation_name": "Tag finished call",
      ...
    }
  ],
  "pagination": { "current_page": 1, "last_page": 5, "per_page": 1, "total": 5, "from": 1, "to": 1 }
}
```

### Runs for one call

[List a call's automation runs](https://docs.callva.io/api-reference/automations/list-a-calls-automation-runs.md) finds every run whose arguments contain `{"call": {"id": "<call id>"}}`, with `include_args` on by default. It answers `404` when the call is not in the project.

```bash theme={null}
curl "$CALLVA_API/calls/01a1c757-6d11-729b-8c19-66fd177e26cd/automation-runs" \
  -H "Authorization: Bearer $CALLVA_TOKEN" \
  -H "Accept: application/json"
```

```json Response (trimmed) theme={null}
{
  "success": true,
  "message": "Automation runs retrieved successfully",
  "data": [
    {
      "id": "01a1c757-f3be-a34c-3791-fb7873637401",
      "created_by": "HTTP-f/proj_61ffbf9e4ef2/trigger_docs-tag-finished-call",
      "args": { "event": "call.ended", "dry_run": true, "call": { "id": "01a1c757-6d11-729b-8c19-66fd177e26cd", "status": "completed" } },
      "status": "success",
      "triggered_by": "webhook",
      "automation_name": "Tag finished call",
      ...
    },
    ...
    {
      "id": "01a1c757-8ad6-4429-132d-75981b62c808",
      "created_by": "label-job-09d11565",
      "args": { "dry_run": true, "call": { "id": "01a1c757-6d11-729b-8c19-66fd177e26cd" } },
      "status": "success",
      "triggered_by": "schedule",
      "automation_name": "Tag finished call",
      ...
    }
  ],
  "pagination": { "current_page": 1, "last_page": 1, "per_page": 30, "total": 4, "from": 1, "to": 4 }
}
```

The last run was started with `POST /automations/{id}/run` and is still reported as `schedule`; see the note on `triggered_by` above.

Only runs that received the call as a nested `call` object with an `id` are found. A run started with a flat `call_id`, or with no call at all, is not. For an agent tool that starts an automation mid-call, send `{"call": {"id": "{{context.call_id}}"}}` in the tool's request body; the voice runtime fills in the live call id. A batch or sweep that touches many calls has no single call to name, so it takes no `call` parameter.

## Manage automations

| Operation | Endpoint |
| - | - |
| [List automations](https://docs.callva.io/api-reference/automations/list-automations.md) | `GET /automations`, filters `name`, `status` (`active`, `inactive`), `sort` (`name`, `created_at`, `is_active`, `-` for descending), `per_page` (default 15, at most 100). Each row carries `has_webhook` (whether it has an HTTP trigger). |
| [Get an automation](https://docs.callva.io/api-reference/automations/get-an-automation.md) | `GET /automations/{id}`, with the live `timeout_seconds`. |
| [Update an automation](https://docs.callva.io/api-reference/automations/update-an-automation.md) | `PUT /automations/{id}` with `name`, `description`, `is_active`, `settings`. An inactive automation refuses runs and its schedules skip it. |
| [Delete an automation](https://docs.callva.io/api-reference/automations/delete-an-automation.md) | `DELETE /automations/{id}` archives the script and removes the automation. |

```bash theme={null}
curl -X PUT "$CALLVA_API/automations/01a1c74f-0c67-7217-a394-d12abd710843" \
  -H "Authorization: Bearer $CALLVA_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"is_active": false}'
```

```json Response (trimmed) theme={null}
{
  "success": true,
  "message": "Automation updated successfully",
  "data": { "id": "01a1c74f-0c67-7217-a394-d12abd710843", "name": "Tag finished call", "is_active": false, ... }
}
```

```bash theme={null}
curl -X DELETE "$CALLVA_API/automations/01a1c74f-0c67-7217-a394-d12abd710843" \
  -H "Authorization: Bearer $CALLVA_TOKEN" \
  -H "Accept: application/json"
```

```json theme={null}
{ "success": true, "message": "Automation deleted successfully" }
```

## Related

> [card] [Webhooks](https://docs.callva.io/guides/webhooks.md)
>
> Call event payloads, and schedules that run an automation at set times.

> [card] [Custom fields](https://docs.callva.io/guides/custom-fields.md)
>
> The call fields an automation writes back to.


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