# Drive one registered agent

> Send one explicit A2A message to an agent you registered and inspect the recorded outcome.

Canonical page: https://anectico.com/docs/agents/drive-an-agent/


Anectico can send one message to one agent you have registered and return its A2A reply. This is an
explicit action: nothing runs on a schedule, no extra turns are invented, and one request sends
exactly the text you provide.

Driving is off until you enable one agent for one project and select a saved credential. The drive
request itself never accepts a URL. Anectico holds the agent's current endpoint and selected
credential stable for each outbound call, refuses redirects, and records who requested the attempt,
which endpoint was resolved, and what happened.

## Before you start

You need:

- a project and an agent asset ID from `GET /api/v1/assets`;
- the agent's absolute HTTPS A2A JSON-RPC endpoint;
- the bearer token that agent expects; and
- an API key with `connections:write` to save the token and `agents:write` to configure and drive.

Keep `agents:read` if the same key must retrieve an attempt later. A project-scoped key remains
pinned to its project even if a different project ID appears in a request body.

## 1. Save the agent credential

Create an encrypted, write-only connection for the bearer token:

```bash
curl -sS https://app.anectico.com/api/v1/connections \
  -H "Authorization: Bearer $ANECTICO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "provider": "a2a",
    "kind": "api_key",
    "display_name": "checkout agent",
    "secret": "<agent bearer token>"
  }'
```

Keep the returned `id`. The response says `has_secret: true` but never returns the token.

## 2. Register the endpoint and opt in

Enable this asset for this project with the saved connection:

```bash
curl -sS -X PUT \
  https://app.anectico.com/api/v1/assets/<asset-id>/driver \
  -H "Authorization: Bearer $ANECTICO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "scope": {"project_id": "<project-id>"},
    "endpoint": "https://agent.example.com/a2a",
    "connection_id": "<connection-id>",
    "enabled": true
  }'
```

The asset must be an agent asset in the same project. The endpoint must use HTTPS and cannot contain
embedded credentials, a query string, or a fragment. Enabling fails if the saved credential is
missing or inactive. The endpoint and credential selection change together; a failed configuration
keeps the prior pair. No outbound message is sent by this step.

Disable later with the same route and `{"scope":{"project_id":"<project-id>"},"enabled":false}`.
The absence of a configuration is also disabled; there is no default-on state.

## 3. Send exactly one message

```bash
curl -sS -X POST \
  https://app.anectico.com/api/v1/assets/<asset-id>/drive \
  -H "Authorization: Bearer $ANECTICO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "scope": {"project_id": "<project-id>"},
    "message_text": "Check order 1842 and tell me its current state"
  }'
```

`message_text` is required and is limited to 65,536 UTF-8 bytes before encoding. Optional
`context_id` and `task_id` are forwarded to agents that use those A2A correlation fields and are
limited to 1,024 UTF-8 bytes each. The complete encoded A2A request, including its envelope and JSON
escaping, may not exceed 64 KiB. There is deliberately no `endpoint` field; supplying one is
rejected. Each call has a 15-second deadline, accepts at most a 1 MiB response, and counts toward a
limit of 10 attempts per project per minute.

A successful response contains `reply_json`, decoded as either an A2A message or task, plus an
`attempt` record. In the REST JSON representation, `reply_json` is base64 because the contract carries
the bounded JSON as bytes; base64-decode it before parsing the A2A object. The message and reply
bodies are not copied into the attempt record; their SHA-256 digests are.

## Read the outcome

The `attempt.outcome` value distinguishes what you should do next:

| Outcome | Meaning | Next action |
| --- | --- | --- |
| `DRIVE_OUTCOME_SUCCEEDED` | The agent returned a valid A2A message or task. | Use `reply_json`. |
| `DRIVE_OUTCOME_REFUSED_NOT_ENABLED` | This project and agent were not opted in. | Enable them explicitly. |
| `DRIVE_OUTCOME_REFUSED_CREDENTIAL_MISSING` | The selected credential is missing or inactive. | Restore or replace it, then enable again. |
| `DRIVE_OUTCOME_REFUSED_RATE_LIMITED` | The project used its current minute allowance. | Wait for the next minute; do not loop. |
| `DRIVE_OUTCOME_REFUSED_TARGET_INVALID` | The asset is no longer an eligible registered target. | Review the asset and its declared endpoint. |
| `DRIVE_OUTCOME_REFUSED_REQUEST_TOO_LARGE` | The final encoded A2A request exceeded 64 KiB. | Shorten the message or correlation IDs. |
| `DRIVE_OUTCOME_AGENT_ERROR` | The endpoint answered but rejected or malformed the A2A exchange. | Inspect the agent's protocol behavior. |
| `DRIVE_OUTCOME_UNREACHABLE` | No A2A response was obtained before the deadline. | Check routing and availability, then retry deliberately. |

An internal inability to read or record a prerequisite is returned as an unavailable API call, not
as one of the customer-actionable refusals above.

Retrieve the durable audit record later:

```bash
curl -sS \
  "https://app.anectico.com/api/v1/agent-drive-attempts/<attempt-id>?project_id=<project-id>" \
  -H "Authorization: Bearer $ANECTICO_TOKEN"
```

The record includes the authenticated actor, asset, outcome, timestamps, content digests, and the
resolved endpoint when destination resolution occurred. The endpoint is empty when the refusal came
first — for example, an agent that was never enabled — because no destination was selected. The
record does not expose the bearer token, request text, or reply text.

Agent replies are untrusted. If a reply reflects the saved bearer token, Anectico discards the
entire reply, returns `DRIVE_OUTCOME_AGENT_ERROR`, and records `credential_reflected` as the safe
detail code. No reply bytes or reply digest are returned or stored for that attempt.

## Verify the safety boundary

Use two visibly different test URLs: the endpoint declared on the asset and an `endpoint` field in a
drive body. The drive body must return `400`; only a subsequent drive without that field may reach
the declared endpoint. This verifies the destination is asset-owned rather than request-selected.

- [Connect an agent with A2A](/docs/agents/connect-a2a) — let another agent call Anectico
- [Replay a real recorded session](/docs/agents/replay-a-recorded-session) — compare the same person's turns against a registered agent
- [Agent inventory](/docs/agents/agent-inventory) — find and review registered assets
- [Permissions and safety](/docs/agents/permissions-and-safety) — narrow the driving credential
