# Autopilot and proposals

> A recurring Content Research Agent reviews each run and proposes changes to itself. Approve them one by one, or let autopilot apply the low-risk ones.

Source: https://dev.virlo.ai/docs/agents/autopilot
Markdown: https://dev.virlo.ai/docs/agents/autopilot.md
Section: Content Research Agents

## About the Virlo API (applies to every page)

- Base URL: `https://api.virlo.ai/v1`. Every request needs the header `Authorization: Bearer YOUR_API_KEY` (keys start with `virlo_tkn_`).
- Responses are JSON inside a `data` field, except the `/v1/webhooks` endpoints, which return the object or array directly. Field names are snake_case.
- Prices are in US dollars from a prepaid balance. 1 credit = $0.01. The `X-Cost` response header on each successful response is the exact charge. Errors are free.
- Slow jobs return an ID. Check its status every 15 seconds (or whatever `retry_after_seconds` says) until `finalized` is `true`.
- All docs pages: https://dev.virlo.ai/llms.txt. Every page in one file: https://dev.virlo.ai/llms-full.txt. MCP server for AI assistants: https://dev.virlo.ai/api/mcp/mcp.

---

After each run, a recurring [Content Research Agent](https://dev.virlo.ai/docs/agents) reviews its results and suggests changes to itself, called **proposals**. Approve them one by one, or let autopilot apply the low-risk ones.

**At a glance**

- **What it does:** Suggests fresher keywords, broader filters, or a new schedule, and flags breaking stories in the agent's niche. One-time agents do none of this.
- **You send:** The agent's `id`. To act, a proposal's `id`, or the autonomy level you want.
- **You get back:** Proposals, each with a `rationale` and a before-and-after `diff`, plus the agent's events and activity log.
- **Cost:** Free. Applying `early_run` (one extra run) or `cadence_change` (daily runs) adds run charges.

---

## How autonomy works

A recurring agent also watches for breaking stories in its niche ([events](https://dev.virlo.ai/docs/agents/autopilot#get-agent-events)) and proposes short-lived **timely keywords** for them.

- `suggest`: proposals wait for you to [apply or dismiss](https://dev.virlo.ai/docs/agents/autopilot#act-on-proposal). Agents you create through the API start here, with `autopilot_unlocked: false`. Approving one proposal by hand (any type except `early_run`) unlocks autopilot for that agent only. Agents created in the Virlo app start on autopilot, already unlocked.
- `autopilot`: the agent applies low-risk changes itself (keyword refreshes that pass the quality check, timely keywords, and changes that only widen collection). They show as `auto_applied`, and you can [revert](https://dev.virlo.ai/docs/agents/autopilot#act-on-proposal) them. Cadence changes, pauses, and extra runs always wait for you.
- `cognition_enabled: false` stops reviews and proposals. The agent keeps collecting.

| Proposal `type` | What it proposes |
| - | - |
| `keyword_refresh` | Swap stale keywords |
| `filter_change` | Collect more broadly |
| `timely_keywords` | Add short-lived keywords for a breaking story |
| `cadence_change` | Run daily (costs more) |
| `pause` | Pause the agent |
| `early_run` | An extra run now, billed like any other |
| `event_detected` | An alert, not a change. Dismiss it once read. |

---

## List proposals

**Endpoint:** `GET https://api.virlo.ai/v1/agents/:id/proposals`

The changes this agent has proposed, newest first. Free. Types are explained under [How autonomy works](https://dev.virlo.ai/docs/agents/autopilot#autonomy).

- `status` (string, optional): `pending`, `applied`, `auto_applied`, `dismissed`, or `reverted`. An unknown value returns an empty list, not an error.
- `limit` (integer, optional): 1 to 100. Default `50`.

**cURL request:**

```bash
curl -G https://api.virlo.ai/v1/agents/{agent_id}/proposals \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d status=pending
```

**Response 200:**

```json
{
  "data": {
    "agent_id": "a1f3c8e2-0b7d-4a91-9c2e-2f5d6b8e1a44",
    "count": 1,
    "proposals": [
      {
        "id": "b94357b3-0c3b-4289-87c7-648beb1fe31f",
        "content_research_agent_id": "a1f3c8e2-0b7d-4a91-9c2e-2f5d6b8e1a44",
        "type": "timely_keywords",
        "source": "event",
        "rationale": "Detected \"New protein cereal launch\" in your niche. Adding 1 timely keyword.",
        "diff": {
          "before": { "timely_keywords": [] },
          "after": {
            "event_id": "c12fc742-7c5d-44fd-9b9c-765710147980",
            "timely_additions": [
              { "keyword": "protein cereal launch", "expires_at": "2026-10-08T23:52:21.405+00:00" }
            ]
          },
          "event": { "title": "New protein cereal launch", "salience": 8 }
        },
        "status": "pending",
        "created_at": "2026-10-01T23:52:25.448948+00:00",
        "decided_at": null,
        "updated_at": "2026-10-01T23:52:25.448948+00:00"
      }
    ]
  }
}
```

---

## Apply, dismiss, or revert a proposal

Three free calls, under `/v1/agents/:id/proposals/:proposal_id/`. Applying an `early_run` starts an extra run, billed like any other.

- `POST .../apply` approves a pending proposal and makes the change.
- `POST .../dismiss` rejects a pending proposal.
- `POST .../revert` undoes an applied or auto-applied change.

Only `pending` proposals can be applied or dismissed, and only applied or auto-applied ones reverted. Otherwise you get `400`, such as `Proposal ... is already applied`. `event_detected` has nothing to apply, so dismiss it. Applying `early_run` returns `400` if the agent ran in the last 24 hours or your balance can't cover the run.

**cURL request:**

```bash
curl -X POST https://api.virlo.ai/v1/agents/{agent_id}/proposals/{proposal_id}/apply \
  -H "Authorization: Bearer YOUR_API_KEY"
```

---

## Set autonomy

**Endpoint:** `PUT https://api.virlo.ai/v1/agents/:id/autonomy`

Choose how much the agent may change on its own. Send at least one field. Free.

- `autonomy_level` (string, optional): `suggest` or `autopilot`. `autopilot` works only after you approve one proposal by hand on this agent. Before that you get `400`: `Autopilot is locked. Approve at least one suggestion first to unlock it.`
- `cognition_enabled` (boolean, optional): `false` stops self-review and proposals. `true` turns them back on.

**Self-review off request:**

```bash
curl -X PUT https://api.virlo.ai/v1/agents/{agent_id}/autonomy \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "cognition_enabled": false }'
```

**Autopilot on request:**

```bash
# Works only after you've approved one proposal on this agent.
curl -X PUT https://api.virlo.ai/v1/agents/{agent_id}/autonomy \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "autonomy_level": "autopilot" }'
```

---

## Get events

**Endpoint:** `GET https://api.virlo.ai/v1/agents/:id/events`

Breaking stories a recurring agent spotted in its niche, such as a launch or a controversy. Free. Active events come first, most important first. The [`content_research_agent.event.detected`](https://dev.virlo.ai/docs/webhooks#supported-events) webhook fires as soon as one is confirmed.

- `limit` (integer, optional): 1 to 100. Default `50`.

**Full field reference**

- `source`: `corpus_burst` (spotted in your agent's videos) or `news_scan` (from the news, then confirmed on the platforms).
- `salience`: importance from 0 to 10.
- `status`: `candidate`, `confirmed` (active), `dismissed`, or `expired`.
- `evidence`: `url` and `views` are `null` when the evidence is your agent's own videos.

**cURL request:**

```bash
curl -G https://api.virlo.ai/v1/agents/{agent_id}/events \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d limit=50
```

**Response 200:**

```json
{
  "data": {
    "agent_id": "a1f3c8e2-0b7d-4a91-9c2e-2f5d6b8e1a44",
    "count": 1,
    "events": [
      {
        "id": "c12fc742-7c5d-44fd-9b9c-765710147980",
        "title": "New protein cereal launch",
        "summary": "A major cereal brand launched a 20g-protein cereal, and taste tests are spreading.",
        "source": "news_scan",
        "salience": 8,
        "status": "confirmed",
        "keywords": ["protein cereal launch"],
        "evidence": [
          {
            "url": "https://example.com/protein-cereal-launch",
            "views": null,
            "description": "Cereal brand announces a 20g-protein cereal"
          }
        ],
        "detected_at": "2026-10-01T23:52:14.965821+00:00",
        "confirmed_at": "2026-10-01T23:52:15.102+00:00",
        "expires_at": "2026-10-08T23:52:21.405+00:00"
      }
    ]
  }
}
```

---

## Get activity

**Endpoint:** `GET https://api.virlo.ai/v1/agents/:id/activity`

The agent's log of what it noticed and decided, newest first. Free. Empty for one-time agents, and possibly right after a recurring agent's first run.

Each entry has `content`, `created_at`, and a `category`: usually `observation`, `decision`, or `milestone`, sometimes `user_pref` (a note about your preferences).

- `limit` (integer, optional): 1 to 100. Default `20`.

**cURL request:**

```bash
curl -G https://api.virlo.ai/v1/agents/{agent_id}/activity \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d limit=20
```

**Response 200:**

```json
{
  "data": {
    "agent_id": "a1f3c8e2-0b7d-4a91-9c2e-2f5d6b8e1a44",
    "count": 1,
    "activity": [
      {
        "content": "This run collected 283 videos, and 71% were on target. No-cook recipes drove most of the reach.",
        "category": "observation",
        "created_at": "2026-10-04T02:31:04.325401+00:00"
      }
    ]
  }
}
```

---

More in Content Research Agents:

- [Overview](https://dev.virlo.ai/docs/agents.md)
- [Intent cookbook](https://dev.virlo.ai/docs/intent-cookbook.md)
- [Data Intelligence](https://dev.virlo.ai/docs/intelligence.md)
