A2A
Verified connections to agents you do not own — passport verification, policy on both sides, and immediate blocking.
A2A is agent-to-agent: your agent invoking an agent in another organization, or theirs invoking yours. Both directions go through the gateway, so the same twelve-stage pipeline applies to a remote caller as to a local one.
A connection is unusable until its passport verifies
You register the remote party's expected public key. The connection starts
PENDING and stays unusable until verify confirms their passport against that
key.
Which means you cannot be talked into trusting a peer by them simply claiming an identity. You registered a key; the passport either matches it or it does not.
#Register a connection
bashcurl -X POST https://veefore.example.com/v1/a2a/connections \
-H "Authorization: Bearer $VEEFORE_API_KEY" \
-H 'content-type: application/json' \
-d '{
"key": "partner-logistics",
"name": "Logistics partner shipment agent",
"remote_agent_id": "agt_partner_01ABC",
"remote_endpoint_url": "https://agents.partner.example.com/a2a",
"remote_public_key": "MCowBQYDK2VwAyEA…",
"capabilities": ["shipment.query", "shipment.update"]
}'
capabilities is what you are willing to invoke on them, or accept from them. It
is not what they claim to offer — it is your side of the contract.
Get remote_public_key out of band. Their exported passport includes it:
bashcurl -s https://agents.partner.example.com/v1/passports/agt_partner_01ABC/export
Out of band means out of band
Fetching the key from the same endpoint you are about to trust proves nothing — whoever controls that endpoint controls both halves. Exchange it through a channel that is independently authenticated: a signed email, a shared document with access control, an existing mutual-TLS link, a phone call.
This is the one step where a shortcut undoes the whole mechanism.
#Verify
bashcurl -X POST https://veefore.example.com/v1/a2a/connections/a2a_01ABC/verify \
-H "Authorization: Bearer $VEEFORE_API_KEY"
Fetches the remote passport and verifies its signature against the key you
registered. On success the connection becomes usable; on failure it stays
PENDING and the reason is recorded.
Re-verify when they rotate. A passport that stops verifying is a connection that stops working, which is the correct outcome and worth being able to recognise quickly.
#Invoke
tsconst decision = await agent.veefore.a2aInvoke({
connection: 'partner-logistics',
capability: 'shipment.query',
action: 'query',
payload: { trackingId: 'TRK-8812' },
});
pythondecision = agent.veefore.a2a_invoke(
connection="partner-logistics",
capability="shipment.query",
action="query",
payload={"trackingId": "TRK-8812"},
)
Over the wire: POST /gateway/v1/a2a/invoke. Full pipeline, full action record,
full audit trail. You can also address a peer by remoteAgentId and supply a
passport inline, which is the shape used when a peer presents itself to you
rather than the reverse.
#Verifying a passport someone presents to you
bashcurl -X POST https://veefore.example.com/v1/passports/verify-external \
-H "Authorization: Bearer $VEEFORE_API_KEY" \
-H 'content-type: application/json' \
-d '{ "passport": "…" }'
Verifies the signature against the issuer's published platform key. It tells you the document is authentic and unaltered.
It does not tell you they are in good standing
Only the issuer knows whether that agent is currently revoked, suspended or under investigation. A passport is a snapshot, and snapshots go stale.
Use passport verification for who, trust evidence and your own policy for whether. They answer different questions and you generally want both.
#Block
bashcurl -X POST https://veefore.example.com/v1/a2a/connections/a2a_01ABC/block \
-H "Authorization: Bearer $VEEFORE_API_KEY" \
-H 'content-type: application/json' \
-d '{ "reason": "Partner reported a compromise of their agent fleet" }'
Immediate, and it applies to in-flight sessions. Refused with
A2A_CONNECTION_BLOCKED.
Blocking is the control to reach for when a partner tells you they have a problem. It is reversible, unlike revoking your own agent, so there is no reason to hesitate.
#Policy on A2A
tool.kind and tool.protocol are A2A, and the trust fields are available,
so you can be as conservative as the relationship warrants:
json{
"id": "rule-a2a-requires-verified-org",
"name": "A2A requires a verified counterparty",
"priority": 870,
"enabled": true,
"when": {
"kind": "group",
"id": "g-a2a-unverified",
"operator": "and",
"children": [
{
"kind": "condition",
"id": "c-protocol",
"field": "tool.protocol",
"operator": "eq",
"value": "A2A"
},
{
"kind": "condition",
"id": "c-org-verified",
"field": "trust.organization_verified",
"operator": "is_false"
}
]
},
"then": {
"decision": "BLOCK",
"reason": "A2A invocation requires a verified counterparty organization."
}
}
Amount ceilings are worth applying here too. A partner integration that legitimately handles small claims does not need the authority to handle a large one, and a bounded ceiling limits what a compromise on their side can do on yours.
#Inbound
When a remote agent invokes you, the same rules apply in reverse: the connection must exist and be verified, their passport must verify, the capability must be one you registered, and your policy decides. A remote caller gets no shortcut through the pipeline.
That symmetry is why A2A goes through the gateway rather than being an API your service exposes directly. One pipeline, one audit trail, one place to look.
#Practical advice
Register the narrowest capability set that works. shipment.query is a
different relationship from shipment.*.
Set a ceiling. Even where amounts are small, a bound limits a compromise on their side.
Re-verify on a schedule. Not only when something breaks. A connection that silently stopped verifying is a connection you are not using and have not noticed.
Record trust evidence about them. ORGANIZATION_VERIFICATION with an expiry
turns "we checked them once" into something policy can test and that lapses
visibly.