Skip to content
Console
Browse documentation
Guide

Drive one registered agent

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

On this page

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.

get_agent_asset (anectico asset get <id>) returns every saved driver setting in driver_configuration, including disabled settings. Its withheld_fields names the connection secret; the secret is never returned. Reading sends no message.

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.

Ask your agent

"Enable driving for the checkout agent with the saved credential. Then send it this one message: 'Check order 1842 and tell me its current state'."

"Did the message with request id <request-id> arrive? Do not send it again."

Job MCP tool or action CLI command
Save the target agent's bearer token create_connection (write action) anectico connections create
Enable or disable driving for one agent configure_agent_driver (write action) anectico asset driver
Send exactly one message drive_agent (write action, leaves Anectico) anectico asset drive
Read what happened to a message, without sending anything get_drive_attempt (read action) anectico drive-attempts get

Enabling and sending preview first and apply only with the confirm_token that the preview returns. Your agent can run the whole workflow. The message leaves Anectico, so read the preview before you confirm it. A drive attempt has no proof page. Its audit record is the evidence; see Read the outcome.

Before you start

You need:

  • a project and an agent asset ID from GET /api/v1/assets (or anectico asset list);
  • 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.

Set the REST connection variables before running the examples:

export ANECTICO_API_URL="https://app.anectico.com"
export ANECTICO_API_KEY="an_..."

This is your Anectico key, not the target agent's bearer token. Keep both out of source control and shell transcripts. Replace angle-bracket placeholders in URLs and JSON with your actual IDs.

1. Save the agent credential

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

curl -sS "$ANECTICO_API_URL/api/v1/connections" \
  -H "X-Anectico-API-Key: $ANECTICO_API_KEY" \
  -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:

curl -sS -X PUT \
  "$ANECTICO_API_URL/api/v1/assets/<asset-id>/driver" \
  -H "X-Anectico-API-Key: $ANECTICO_API_KEY" \
  -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 public HTTPS on port 443 and cannot contain embedded credentials, a query string, or a fragment. Private, loopback, link-local and metadata addresses are refused, including names that resolve to any such address. Anectico rechecks DNS when connecting, dials only a checked public address, and refuses redirects. 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

curl -sS -X POST \
  "$ANECTICO_API_URL/api/v1/assets/<asset-id>/drive" \
  -H "X-Anectico-API-Key: $ANECTICO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "scope": {"project_id": "<project-id>"},
    "request_id": "<a new UUID for this message>",
    "message_text": "Check order 1842 and tell me its current state"
  }'

request_id is required: generate a new UUID for every message you intend to send, and keep it until you know the outcome. See Retry safely for why. 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 or its destination is no longer eligible, including a private DNS answer. 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, by the attempt id or by your own request_id:

curl -sS \
  "$ANECTICO_API_URL/api/v1/agent-drive-attempts/<attempt-id>?project_id=<project-id>" \
  -H "X-Anectico-API-Key: $ANECTICO_API_KEY"
curl -sS \
  "$ANECTICO_API_URL/api/v1/agent-drive-attempts?request_id=<request-id>&project_id=<project-id>" \
  -H "X-Anectico-API-Key: $ANECTICO_API_KEY"

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.

Retry safely

A drive sends a message to a system outside Anectico, so a failed or timed-out call does not mean nothing was sent. The request_id is what lets you find out instead of guessing:

  • The first call with a request_id sends the message. Every later call with the same request_id in the same project sends nothing and returns the attempt already recorded for it, with "duplicate": true. Resending the identical request is therefore always safe.
  • A duplicate response never includes reply_json, because reply content is not retained. Only the first response carries the reply.
  • Reusing a request_id for a different message, context id, task id or agent returns 409.
  • Reading GET /api/v1/agent-drive-attempts?request_id=... tells you what happened without the possibility of sending anything.

If the recorded outcome is still DRIVE_OUTCOME_STARTED, the earlier send is in flight or was interrupted between sending and recording its result: the message may or may not have reached the agent, and only the agent can tell you which. Anectico does not send it again and cannot cancel it. Generate a new request_id only when you have decided that a second message is acceptable.

From the CLI or an MCP agent

The same workflow, with the same retry contract:

anectico asset driver <asset-id> --enable --endpoint https://agent.example.com/a2a \
  --connection-id <connection-id> --confirm-token <token>
REQUEST_ID="$(uuidgen)"   # keep it: re-running with it is always safe
anectico asset drive <asset-id> --request-id "$REQUEST_ID" --message "Check order 1842" --confirm-token <token>
anectico drive-attempts get --request-id "$REQUEST_ID"
anectico asset driver <asset-id> --disable --confirm-token <token>

The CLI never makes up a --request-id for you, because an id generated on each run would be new on every retry.

An MCP agent uses configure_agent_driver, drive_agent and the read action get_drive_attempt. drive_agent goes through execute_external_action because the message leaves Anectico. It shows a preview and needs the returned confirm_token. The agent's reply is returned once, marked as untrusted, and never kept.

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.