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

# API changes, October 2026

> Workflows become agents and the run's error_message becomes error in the Agents release, and every rename in API 0.126.0, with what to use instead.

Two October releases change the API in ways that break existing clients:

* The [Agents release](#agents-release) replaces workflows with agents and
  renames the run's `error_message` to `error`.
* [API 0.126.0](#naming-rules) renames parameters, fields, paths
  and webhook fields to follow one set of naming rules.

## Agents release

The Agents release replaces workflows with [agents](https://docs.axilio.ai/agents/overview.md). An
agent's revision is either code, like a workflow's, or instructions: a task
in plain English that a model works through on the phone. Runs can now start
from an ad hoc task, pause for a person, take follow-ups on the same phone,
and run on a schedule. Workflows are not carried over: recreate each one as a
code agent.

The old routes and names stop working in this release. There is no
compatibility period, so update your code and clients before you upgrade.

### Upgrade to CLI 0.14

CLI 0.14.0 follows this release. See
[Upgrade from an earlier CLI](https://docs.axilio.ai/cli.md#upgrade-from-an-earlier-cli) for its breaking changes.

```bash theme={null}
brew upgrade axilio
```

### Upgrade the SDKs

Python SDK 0.23.0 and Go SDK v0.16.0 follow this release, and earlier versions
can't call the removed paths. In Python, `client.workflows` is now
`client.agents`, runs start with `client.runs.start()`, and
`client.session(workflow_id=...)` is gone.

```bash theme={null}
pip install --upgrade axilio
go get github.com/axilioai/platform-go@v0.16.0
```

### Actions on text that matches several elements

When a locator reads the screen (accessibility off, or `strategy="vision"`), an
action on text that matches several elements now raises `ActionTimeoutError` and
lists the matches, instead of acting on the first. Scripts that relied on the
first match need `first()`, `nth()`, `exact` or more specific text. See
[Locators](https://docs.axilio.ai/driver/locator.md).

### Removed paths

| Before | Now |
| - | - |
| `POST /workflows`, `GET /workflows`, `GET`, `PATCH` and `DELETE /workflows/{workflow_id}` | The same operations on `/agents` and `/agents/{agent_id}`. An agent takes `code` or `instructions`. |
| `POST /workflows/{workflow_id}/runs` | `POST /runs` with `agent_id` for one run, or `POST /runs:batchCreate` for up to 1,000. |
| `GET /workflows/{workflow_id}/code` | `GET /agents/{agent_id}/revisions/{revision_id}`, whose `code` holds the script. The agent's `current_revision_id` names the current one. |
| `POST /workflows/{workflow_id}/revisions` with `source` | `POST /agents/{agent_id}/revisions` with `kind` (`code` or `instructions`) and `code` or `instructions`. |
| `GET /workflows/{workflow_id}/revisions[/{revision_id}]` | `GET /agents/{agent_id}/revisions[/{revision_id}]` |
| `POST /workflows/{workflow_id}/revisions/{revision_id}:restore` | `POST /agents/{agent_id}:rollback` with `{"revision_id": "..."}` |
| `GET /workflows/{workflow_id}/run-stats` | `GET /runs/metrics?group_by=agent` |
| `GET /runs/history` | Archived run records have no list endpoint now. `GET /runs` lists recent runs, and `GET /runs/metrics` counts them over a window. |

### Renamed and removed fields

| Where | Before | Now |
| - | - | - |
| Run | `error_message` | `error` |
| Run | `workflow_id`, `workflow_name` | `agent_id`, `agent_name`. An ad hoc run has neither. |
| Run start | `runs[]` entries with `variables` as a one-element list | One `POST /runs` body per run, with `variables` as an object. Batches send `requests[]`. |
| `GET /runs` | `workflow_id` | `agent_id` |
| Session (list item and detail) | `workflow_id`, `workflow_name`; `source` `workflow` | `agent_id`, `agent_name`; `source` `agent` |
| Session `allocated_by` | `workflow_editor` | Removed. The values are `dashboard_run`, `api_run` and `interactive`. |
| `GET /phones/sessions`, `GET /usage/sessions` | `workflow_id` filter; `order_by` field `workflow_id` on usage | `agent_id` |
| Usage session | `workflow_id` | `agent_id` |
| `POST /phones:allocate` | `workflow_id` | Removed. |
| Allocation response | `workflow_started_at` | `allocated_at` |
| Release response | `workflow_id` | `agent_id` |
| Plans (`GET /billing/plans`) | `limits.max_workflows` | `limits.max_agents` |

The CLI's `runs watch -o json` ends with `error` in place of `error_message`:

```json theme={null}
{"error":null,"run_id":"...","status":"completed","watch_end":true}
```

### Changed behavior

* A run has a `mode`: `agent` when a model drives it, `code` when a script
  runs. Every former workflow run is a code run.
* A run can be `paused`, which joins the run status enum and the `status`
  filter on `GET /runs`.
* `POST /runs` returns `409` while your organization is at its concurrency
  limit.
* After an agent-mode run's turn ends, or after you cancel a running or
  paused agent-mode run, the run holds its phone for `keep_alive_seconds`: 120
  seconds by default on `POST /runs`, 0 in a batch. A shared phone bills for
  that time. Release it with `POST /phones/{phone_id}:deallocate` and the run's
  `session_id`, or set `keep_alive_seconds: 0`. See
  [Pause and follow up](https://docs.axilio.ai/agents/pause-and-follow-up.md#release-the-phone-early).

### New endpoints and fields

* Agents: `/agents`, their revisions, `:rollback`, and
  `/revisions/{revision_id}:promote` for a fix a repair proposed. See
  [Create an agent](https://docs.axilio.ai/agents/create.md).
* Runs: `POST /runs` takes an ad hoc `task` or an `agent_id`, `targets`,
  `network`, `keep_alive_seconds` and limits. `:pause`, `:resume` and
  `:sendMessage` pause, answer and follow up. See
  [Run a task or an agent](https://docs.axilio.ai/agents/run.md).
* A run carries `mode`, `task`, `output`, `result_text`, `usage`,
  `input_request`, `repair`, `turn`, `turns`, `keep_alive_expires_at` and
  `stream_url`. `GET /runs` filters by `schedule_id`, `mode` and
  `device_class`.
* `GET /realtime/runs/{run_id}/events` streams a run, and
  `GET /runs/{run_id}/events`, `/steps` and `/script` read its events, model
  steps and executed code. See [Monitor runs](https://docs.axilio.ai/agents/monitor.md).
* Schedules: `/agents/{agent_id}/schedules`, with `:pause`, `:resume` and
  `:run`. See [Schedule an agent](https://docs.axilio.ai/agents/schedules.md).
* Metrics: `GET /runs/metrics` and `GET /sessions/metrics`, on the
  [metrics contract](#metrics). `GET /usage/metrics` adds the `agent`,
  `model`, `api_key`, `schedule` and `device_class` groups, and the
  `session_seconds`, `input_tokens` and `output_tokens` measures.
* `GET /usage/inferences` adds the `agent_chat` endpoint: one model step of an
  agent-mode run.
* `GET /models` lists the models an agent can use.

### Agent webhook payloads

| Events | Before | Now |
| - | - | - |
| `run.*` | `workflow_id` | `agent_id`, plus `mode`, `revision_id`, `schedule_id`, `repaired` and `turn` |
| `session.started`, `session.ended` | `workflow_id` | `agent_id` |

New events: `run.paused`, `run.resumed`, `schedule.paused`, `schedule.ended`
and `schedule.occurrence_skipped`. A run with follow-ups fires `run.started`
and its end event once per turn. See [Webhook events](https://docs.axilio.ai/webhooks/events.md).

## Naming rules

API 0.126.0 makes the REST API follow one set of naming rules everywhere. Some
parameters, response fields, paths and webhook fields have new names. The old
names stop working in this release, so update your code and upgrade your
clients. The same release puts every metrics endpoint on one contract (see
[Metrics](#metrics)).

### Upgrade your clients

The SDK and CLI releases that follow API 0.126.0 use the new names. Earlier
releases call the old ones and fail.

```bash theme={null}
pip install -U axilio
go get github.com/axilioai/platform-go@latest
brew upgrade axilio
```

### The rules

| Concept | Rule |
| - | - |
| Sort | One `order_by=<field> [asc\|desc]`, for example `order_by=created_at desc` (URL-encoded as `created_at%20desc`). The direction defaults to `desc`. |
| Filters | Named after the field they match: `status`, never `status_filter`. Most filters repeat to match several values. |
| Search | Free text is `search`. |
| Time windows | `<field>_after` and `<field>_before`, over the field they filter, for example `allocated_after`. |
| Metrics | Every `GET /{area}/metrics` takes the same window and returns `{"points": [...]}`. See [Metrics](#metrics). |
| Timestamps | Every timestamp field ends in `_at`. |
| Money | Every amount is in microdollars: 1,000,000 = \$1.00, so cents × 10,000. Fields end in `_microdollars`. |
| Updates | `PATCH`, with only the fields you are changing. |
| Actions | A `:verb` on the resource, for example `POST /files/{file_id}:complete`. |
| Paths | A `POST` creates in a collection or runs a `:verb`. A subset of a list is a filter, never a path segment. |
| Spelling | Runs and sessions say `cancelled` (`cancelled_at`). Billing keeps Stripe's `canceled`. |

### Paths and methods

The Agents release later removed the workflow routes in this table. See
[Removed paths](#removed-paths).

| Before | Now |
| - | - |
| `GET /runs/stats/{workflow_id}` | `GET /workflows/{workflow_id}/run-stats` |
| `POST /workflows/{workflow_id}/code/restore` with `revision_id` in the body | `POST /workflows/{workflow_id}/revisions/{revision_id}:restore`, no body |
| `PATCH /phones/{phone_id}/nickname` | `PATCH /phones/{phone_id}` with `{"nickname": "..."}` |
| `POST /files/{file_id}/complete` | `POST /files/{file_id}:complete` |
| `POST /workflows/{workflow_id}/code` | `POST /workflows/{workflow_id}/revisions` |
| `POST /phones/sessions/{session_id}/live-view-token` | `POST /phones/sessions/{session_id}:createLiveViewToken` |
| `POST /phones/sessions/{session_id}/telemetry-token` | Removed. Read `GET /realtime/sessions/{session_id}/events` with your API key; see [Live Telemetry](https://docs.axilio.ai/telemetry/live.md). |
| `GET /phones/apps/supported` | `GET /phones/supported-apps` |
| `GET /phones/sessions/active` | `GET /phones/sessions?status=active` |
| `PUT /billing/auto-recharge` | `PATCH /billing/auto-recharge` |
| `PUT /billing/usage-alerts` | `PATCH /billing/usage-alerts` |

### Query parameters

| Endpoint | Before | Now |
| - | - | - |
| `GET /runs` | `status_filter`, `trigger_filter` | `status`, `trigger` |
| `GET /runs/history` | `start_date`, `end_date`, `status_filter` | `completed_after`, `completed_before`, `status` |
| `GET /usage/metrics` | `start_date`, `end_date`, `granularity` (`hourly`, `daily`), `timezone` | `period_start_at`, `period_end_at`, `granularity` (`hour`, `day`), `time_zone`, `group_by` |
| `GET /webhooks/metrics` | `range` (`24h`, `7d`, `30d`); points grouped by destination when `endpoint_id` was left out | `period_start_at`, `period_end_at`, `granularity`, `time_zone`; `group_by=endpoint_id` to group by destination |
| `GET /usage/sessions` | `start_date`, `end_date`, `session_status_filter`, `processed_status_filter` | `allocated_after`, `allocated_before`, `session_status`, `processed_status` |
| `GET /usage/sessions` | `order_by` field `duration` | `duration_seconds` |
| `GET /usage/inferences` | `start_date`, `end_date`, `endpoint_filter` | `created_after`, `created_before`, `endpoint` |
| `GET /phones` | `sort`, `order`, `type`, `last_active_after`, `last_active_before` | `order_by`, `phone_type`, `last_heartbeat_after`, `last_heartbeat_before` |
| `GET /phones/sessions` | `sort`, `order`, `started_after`, `started_before`, `ended_after`, `ended_before` | `order_by`, `allocated_after`, `allocated_before`, `deallocated_after`, `deallocated_before` |
| `GET /phones/sessions/{session_id}/files` | `q` | `search` |
| `GET /files` | `sort`, `order`, `q` | `order_by`, `search` |
| `GET /billing/history` | `sort_by`, `sort_order`, `date_from`, `date_to` | `order_by`, `invoiced_after`, `invoiced_before` |
| `GET /billing/phone-rental-subscriptions` | none: every rental in one response | pages with `limit` (default and maximum 100) and `offset`; filters `search`, `status`, `plan_interval`, `cancel_at_period_end`, `payment_status`, `current_period_end_after`, `current_period_end_before`; sorts with `order_by` |

`GET /api-keys` also takes `search`, `created_by_id`, `created_after`, `created_before` and `order_by`. `GET /workflows` also takes `order_by`, whose field is a path into the listed item, for example `order_by=workflow.name asc`. Both are additions, so existing calls keep working.

### Response fields

| Resource | Before | Now |
| - | - | - |
| Phone | `last_heartbeat`, `last_interaction_timestamp` | `last_heartbeat_at`, `last_interaction_at` |
| Session (list item and detail) | `nickname` | `phone_nickname` |
| Run | `canceled_at` | `cancelled_at` |
| Run history item | `run_id`, `org_id`, `canceled_at` | `id`, `organization_id`, `cancelled_at` |
| Usage metrics (costs were US dollars as decimals) | `infra_costs`, `compute_minutes`, `cost_by_product`, the chart series, `period_start`, `period_end`, `granularity` | `points`: one per bucket with `period_start_at`, `total_cost_microdollars`, `session_cost_microdollars` and `inference_cost_microdollars` (and `product` with `group_by=product`). Add the points up for a total. |
| Supported app | `model_status` in upper case (`TRAINED`) | lower case (`trained`) |
| Usage session (`GET /usage/sessions`) | `allocated_by` in upper case (`WORKFLOW_EDITOR`) | lower case (`workflow_editor`), as on `GET /phones/sessions` |
| Balance | `purchased_next_expiry` | `purchased_expires_at` |
| Subscription | `current_period_start`, `current_period_end`, `trial_end`, `pending_downgrade_effective_date`, `monthly_price`, `yearly_price` | `current_period_start_at`, `current_period_end_at`, `trial_end_at`, `pending_downgrade_at`, `monthly_price_microdollars`, `yearly_price_microdollars` |
| Auto-recharge settings | `threshold_cents`, `target_cents` | `threshold_microdollars`, `target_microdollars` |
| Usage-alert settings and active alerts | `threshold_cents`, `balance_cents` | `threshold_microdollars`, `balance_microdollars` |
| Invoice (billing history) | `invoice_date`, `due_date`, `amount_cents`, `amount_dollars`, `formatted_amount`; `billing_cycle` as `month` or `year` on synced invoices | `invoiced_at`, `due_at`, `amount_microdollars`, `amount_display`; `billing_cycle` is always `daily`, `weekly`, `monthly` or `yearly` |
| Phone rental subscription | `current_period_start`, `current_period_end`, `plan_price_cents` | `current_period_start_at`, `current_period_end_at`, `plan_price_microdollars` |
| Phone rental summary | `combined_monthly_cents`; each interval's `monthly_cents`; the upcoming charge's `amount_cents` and `date` | `combined_monthly_microdollars`; `monthly_microdollars`; `amount_microdollars` and `due_at` |
| Webhook delivery metrics point | `time_bucket`, null on an aggregate | `period_start_at`, always set; `endpoint_id` only with `group_by=endpoint_id` |
| Plans (`GET /billing/plans`, public) | `pricing.monthly_price_cents`, `pricing.yearly_price_cents`, `sort_order` | `pricing.monthly_price_microdollars`, `pricing.yearly_price_microdollars`, `display_order` |
| Phone rental plans (`GET /billing/phone-rental-plans`, public) | `price_cents` | `price_microdollars` |
| Model catalog (Argus `GET /models`) | `pricing.input`, `pricing.output` (US dollars per token, as strings); `pricing.per_page` (US dollars per call, as a string) | `pricing.input_microdollars_per_million_tokens`, `pricing.output_microdollars_per_million_tokens`, `pricing.per_page_microdollars` (integers) |

### Metrics

`GET /usage/metrics` and `GET /webhooks/metrics` follow one contract, and
every metrics endpoint added later will too.

| Parameter | Rule |
| - | - |
| `period_start_at`, `period_end_at` | Both optional. The end defaults to now, and the start to 7 days before the end. The start may be at most a year before now. The window holds its start and not its end. |
| `granularity` | `hour` or `day`, default `day`. `hour` is allowed for windows of 7 days or less; a longer one is a 422. |
| `time_zone` | An IANA name such as `America/Los_Angeles`, default `UTC`. A day starts at local midnight and an hour on the local hour. An unknown name is a 422. |
| `group_by` | Optional, one dimension from the endpoint's list: `product` on usage, `endpoint_id` on webhooks. |

The response is `{"points": [...]}`: one point per bucket (and per group),
oldest first, each with `period_start_at` and every measure. A measure is
named for its unit (`_microdollars`, `_ms`, `_rate` from 0 to 1, or a plain
count) and is zero for a bucket with no activity. A latency is null when no
attempt in the bucket recorded one. A webhooks window that needs more buckets than the gateway returns in one read is a 400; shorten it.

### Webhook payloads

| Events | Before | Now |
| - | - | - |
| `run.*` | `canceled_at` | `cancelled_at` |
| `invoice.paid`, `invoice.payment_failed` | `amount_cents`, `invoice_date` | `amount_microdollars`, `invoiced_at` |
| `subscription.*` | `current_period_start`, `current_period_end` | `current_period_start_at`, `current_period_end_at` |
| `phone.rental.*` | `plan_price_cents`, `current_period_start`, `current_period_end` | `plan_price_microdollars`, `current_period_start_at`, `current_period_end_at` |

A phone rental's `canceled_at` and a subscription's `canceled` status keep
Stripe's spelling.

### SDK methods

The SDKs take the new parameter names as arguments (`period_start_at=` in
Python, `PeriodStartAt` in Go). These methods also moved:

| Python before | Python now | Go now |
| - | - | - |
| `client.runs.stats(workflow_id)` | `client.workflows.get_run_stats(workflow_id)` | `api.Workflows.GetRunStats` |
| `client.workflows.restore_revision(workflow_id, revision_id=...)` | `client.workflows.restore_revision(workflow_id, revision_id)` | `api.Workflows.RestoreRevision` with `WorkflowsRestoreRevisionRequest` |
| `client.phones.nickname(...)` | `client.phones.update(phone_id, nickname=...)` | `api.Phones.Update` |
| `client.files.rename(file_id, filename=...)` | `client.files.update(file_id, filename=...)` | `api.Files.Update` |
| `client.workflows.save_code(workflow_id, source=...)` | `client.workflows.create_revision(workflow_id, source=...)` | `api.Workflows.CreateRevision` with `WorkflowCreateRevisionRequest` |
| `client.phones.active_sessions()` | `client.phones.list_sessions(status=["active"])` | `api.Phones.ListSessions` |
| `client.billing.update_auto_recharge(threshold_cents=..., target_cents=...)` | `client.billing.update_auto_recharge(threshold_microdollars=..., target_microdollars=...)` | `api.Billing.UpdateAutoRecharge` with `SubscriptionAutoRechargeSettingsUpdate` |
| `client.billing.update_usage_alerts(threshold_cents=...)` | `client.billing.update_usage_alerts(threshold_microdollars=...)` | `api.Billing.UpdateUsageAlerts` with `SubscriptionUsageAlertSettingsUpdate` |


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