Autopilot and proposals

After each run, a recurring Content Research Agent 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) and proposes short-lived timely keywords for them.

  • suggest: proposals wait for you to apply or dismiss. 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 them. Cadence changes, pauses, and extra runs always wait for you.
  • cognition_enabled: false stops reviews and proposals. The agent keeps collecting.
Proposal typeWhat it proposes
keyword_refreshSwap stale keywords
filter_changeCollect more broadly
timely_keywordsAdd short-lived keywords for a breaking story
cadence_changeRun daily (costs more)
pausePause the agent
early_runAn extra run now, billed like any other
event_detectedAn alert, not a change. Dismiss it once read.

GET/v1/agents/:id/proposals

List proposals

The changes this agent has proposed, newest first. Free. Types are explained under How autonomy works.

  • Name
    status
    Type
    string
    Description

    pending, applied, auto_applied, dismissed, or reverted. An unknown value returns an empty list, not an error.

  • Name
    limit
    Type
    integer
    Description

    1 to 100. Default 50.

Request

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

Response

{
  "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"
      }
    ]
  }
}

POST

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.

Request

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

PUT/v1/agents/:id/autonomy

Set autonomy

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

  • Name
    autonomy_level
    Type
    string
    Description

    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.

  • Name
    cognition_enabled
    Type
    boolean
    Description

    false stops self-review and proposals. true turns them back on.

Request

PUT
/v1/agents/:id/autonomy
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 }'

GET/v1/agents/:id/events

Get 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 webhook fires as soon as one is confirmed.

  • Name
    limit
    Type
    integer
    Description
    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.

Request

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

Response

{
  "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/v1/agents/:id/activity

Get 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).

  • Name
    limit
    Type
    integer
    Description
    1 to 100. Default 20.

Request

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

Response

{
  "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"
      }
    ]
  }
}

Was this page helpful?