---
title: A2A
description: 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.

:::security 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

```bash
curl -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:

```bash
curl -s https://agents.partner.example.com/v1/passports/agt_partner_01ABC/export
```

:::warning 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

```bash
curl -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

:::tabs

:::tab TypeScript
```ts
const decision = await agent.veefore.a2aInvoke({
  connection: 'partner-logistics',
  capability: 'shipment.query',
  action: 'query',
  payload: { trackingId: 'TRK-8812' },
});
```
:::

:::tab Python
```python
decision = 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

```bash
curl -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.

:::note 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

```bash
curl -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.

## Related

:::cards

:::card Agent Passport | /concepts/passport
The document being verified, and its limits.
:::

:::card Trust evidence | /concepts/trust
Deciding whether a verified peer is one you want.
:::

:::card A2A API | /reference/api/a2a
Register, verify, block.
:::

:::card A2A architecture | /architecture/adr/0010-a2a-architecture
Why invocation goes through the gateway.
:::

:::
