A2A Protocol
The Agent-to-Agent (A2A) Protocol is a message-based communication standard for AI agents, based on Google's Agent Payments Protocol (AP2). AutopayOS implements A2A for secure, interoperable agent communication.
Overview
A2A enables agents to:
- Discover each other's capabilities
- Exchange structured messages
- Request and grant permissions
- Execute payments across trust boundaries
Diagram
┌──────────────┐ ┌──────────────┐
│ Shopping │ A2A Messages │ Merchant │
│ Agent │◀──────────────────▶│ Agent │
└──────────────┘ └──────────────┘
│ │
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ AutopayOS │ │ Merchant │
│ Gateway │ │ Server │
└──────────────┘ └──────────────┘Agent discovery
Agents discover each other using Agent Cards at well-known URLs.
Agent Card endpoint
GET https://agent.example.com/.well-known/agent-card.json
AutopayOS Agent Card
JSON
{
"@context": "https://schema.org/",
"@type": "SoftwareApplication",
"name": "AutopayOS Payment Agent",
"description": "Secure payment authorization for AI agents",
"url": "https://api.autopayos.com",
"provider": {
"@type": "Organization",
"name": "AutopayOS"
},
"capabilities": [
"merchant",
"payment-processor",
"intent-issuer",
"cart-validator"
],
"protocols": ["ap2", "a2a"],
"endpoints": {
"a2a": "https://api.autopayos.com/a2a/gateway",
"discovery": "https://api.autopayos.com/.well-known/agent-card.json"
},
"authentication": {
"methods": ["api-key", "did-auth", "oauth2"]
}
}Fetch Agent Card
TypeScript
const response = await fetch('https://api.autopayos.com/.well-known/agent-card.json');
const agentCard = await response.json();
console.log('Capabilities:', agentCard.capabilities);
console.log('A2A Endpoint:', agentCard.endpoints.a2a);Message structure
A2A messages follow a standard format:
JSON
{
"jsonrpc": "2.0",
"method": "a2a/message",
"params": {
"message": {
"id": "msg_abc123",
"type": "IntentMandate",
"from": "did:key:z6MkAgentDid...",
"to": "did:key:z6MkAutoPayOS...",
"created": "2025-12-17T10:00:00Z",
"body": {
// Message-specific payload
}
}
},
"id": "req_xyz789"
}| Field | Description |
|---|---|
id | Unique message identifier |
type | Message type (IntentMandate, CartMandate, etc.) |
from | Sender DID |
to | Recipient DID |
created | ISO 8601 timestamp |
body | Message payload |
Message types
IntentMandate
Request permission to make purchases:
JSON
{
"type": "IntentMandate",
"body": {
"agentDid": "did:key:z6MkAgent...",
"principalDid": "did:key:z6MkUser...",
"request": {
"maxAmount": 100.00,
"currency": "USD",
"vendorHints": {
"domain": "amazon.com",
"mcc": "5411"
}
},
"expiresAt": "2025-12-17T11:00:00Z"
}
}IntentResult
Response to IntentMandate:
JSON
{
"type": "IntentResult",
"body": {
"allowed": true,
"intentVc": {
"type": ["VerifiableCredential", "IntentMandate"],
"credentialSubject": {
"mandateId": "intent_abc123",
"maxAmount": 100.00
},
"proof": { ... }
},
"attestation": {
"policyId": "pol_xyz",
"policyHash": "sha256:..."
}
}
}CartMandate
Submit a verified cart:
JSON
{
"type": "CartMandate",
"body": {
"intentVc": { ... },
"cartVc": {
"type": ["VerifiableCredential", "CartMandate"],
"credentialSubject": {
"merchant": "amazon.com",
"items": [
{ "name": "USB Cable", "price": 12.99, "quantity": 2 }
],
"total": 25.98,
"currency": "USD"
},
"proof": { ... }
}
}
}CartResult
Response to CartMandate:
JSON
{
"type": "CartResult",
"body": {
"allowed": true,
"approvalToken": "apt_abc123...",
"railDecision": {
"rail": "STRIPE",
"reason": "Optimal for merchant"
}
}
}PaymentMandate
Execute payment with approval:
JSON
{
"type": "PaymentMandate",
"body": {
"approvalToken": "apt_abc123...",
"userAuthorization": "sig_xyz..."
}
}PaymentResult
Response with Payment Mandate VC:
JSON
{
"type": "PaymentResult",
"body": {
"pmVc": {
"type": ["VerifiableCredential", "PaymentMandate"],
"credentialSubject": {
"mandateId": "pm_xyz789",
"amount": 25.98,
"currency": "USD"
},
"proof": { ... }
},
"railResponse": {
"rail": "STRIPE",
"paymentIntentId": "pi_..."
}
}
}Send A2A messages
Using the SDK
TypeScript
import { A2AClient } from '@autopayos/a2a-client';
const a2a = new A2AClient({
endpoint: 'https://api.autopayos.com/a2a/gateway',
agentDid: 'did:key:z6MkMyAgent...',
privateKey: myPrivateKey,
});
// Send IntentMandate
const result = await a2a.send({
type: 'IntentMandate',
to: 'did:key:z6MkAutoPayOS...',
body: {
agentDid: 'did:key:z6MkMyAgent...',
principalDid: 'did:key:z6MkUser...',
request: {
maxAmount: 100.00,
currency: 'USD',
},
},
});
console.log('Intent approved:', result.body.allowed);Using cURL
Bash
curl https://api.autopayos.com/a2a/gateway \
-H "Content-Type: application/json" \
-H "X-Agent-DID: did:key:z6MkMyAgent..." \
-d '{
"jsonrpc": "2.0",
"method": "a2a/message",
"params": {
"message": {
"id": "msg_123",
"type": "IntentMandate",
"from": "did:key:z6MkMyAgent...",
"to": "did:key:z6MkAutoPayOS...",
"body": {
"agentDid": "did:key:z6MkMyAgent...",
"principalDid": "did:key:z6MkUser...",
"request": {
"maxAmount": 100.00,
"currency": "USD"
}
}
}
},
"id": "req_1"
}'Session management
A2A sessions track multi-message conversations:
Diagram
Session (contextId: ctx_abc123)
│
├── Message 1: IntentMandate
│ └── Response: IntentResult
│
├── Message 2: CartMandate
│ └── Response: CartResult
│
└── Message 3: PaymentMandate
└── Response: PaymentResultCreate session
TypeScript
const session = await a2a.createSession({
contextId: `session_${Date.now()}`,
agentDid: 'did:key:z6MkMyAgent...',
userDid: 'did:key:z6MkUser...',
});Track session
TypeScript
const status = await a2a.getSession(contextId);
console.log('Status:', status.status);
console.log('Messages:', status.messageCount);
console.log('Intent:', status.intentMandateId);
console.log('Permit:', status.permitId);Error handling
A2A errors follow JSON-RPC format:
JSON
{
"jsonrpc": "2.0",
"error": {
"code": -32000,
"message": "Policy violation",
"data": {
"reasonCodes": ["AMOUNT_OVER_CAP", "MERCHANT_NOT_ALLOWED"],
"details": {
"requested": 500.00,
"cap": 100.00
}
}
},
"id": "req_1"
}Error codes
| Code | Description |
|---|---|
-32700 | Parse error |
-32600 | Invalid request |
-32601 | Method not found |
-32602 | Invalid params |
-32000 | Policy violation |
-32001 | Authentication failed |
-32002 | Session expired |
-32003 | Rate limited |
Security
Message signing
All A2A messages should be signed:
TypeScript
const signedMessage = await a2a.signMessage({
type: 'IntentMandate',
body: { ... },
}, privateKey);
// Message includes proof
console.log(signedMessage.proof);
// {
// type: "Ed25519Signature2020",
// verificationMethod: "did:key:z6Mk...#key-1",
// jws: "eyJhbGciOiJFZERTQSJ9..."
// }Verify signatures
TypeScript
const isValid = await a2a.verifyMessage(message);
if (!isValid) {
throw new Error('Invalid message signature');
}DID authentication
Authenticate using DID:
Bash
curl https://api.autopayos.com/a2a/gateway \
-H "X-Agent-DID: did:key:z6MkMyAgent..." \
-H "X-DID-Proof: eyJhbGciOiJFZERTQSJ9..."Complete flow example
TypeScript
import { A2AClient } from '@autopayos/a2a-client';
async function completePurchase() {
const a2a = new A2AClient({
endpoint: 'https://api.autopayos.com/a2a/gateway',
agentDid: myAgentDid,
privateKey: myPrivateKey,
});
// Step 1: Request permission
const intentResult = await a2a.send({
type: 'IntentMandate',
body: {
agentDid: myAgentDid,
principalDid: userDid,
request: {
maxAmount: 50.00,
currency: 'USD',
vendorHints: { domain: 'amazon.com' },
},
},
});
if (!intentResult.body.allowed) {
throw new Error(`Denied: ${intentResult.body.reasonCodes}`);
}
// Step 2: Get cart from merchant
const cartVc = await getCartFromMerchant('amazon.com');
// Step 3: Verify cart
const cartResult = await a2a.send({
type: 'CartMandate',
body: {
intentVc: intentResult.body.intentVc,
cartVc: cartVc,
},
});
if (!cartResult.body.allowed) {
throw new Error(`Cart rejected: ${cartResult.body.reasonCodes}`);
}
// Step 4: Execute payment
const paymentResult = await a2a.send({
type: 'PaymentMandate',
body: {
approvalToken: cartResult.body.approvalToken,
},
});
console.log('Payment complete!');
console.log('Mandate:', paymentResult.body.pmVc);
return paymentResult;
}AP2 compatibility
AutopayOS A2A is compatible with Google's AP2 specification:
| AP2 Feature | AutopayOS Support |
|---|---|
| Agent Cards | Full support |
| IntentMandate | Full support |
| CartMandate | Full support |
| PaymentMandate | Full support |
| DID authentication | Full support |
| VC signatures | Ed25519Signature2020 |
Next steps
- Building agents — Create an A2A-compatible agent
- API Reference — Complete endpoint documentation
- SDKs — TypeScript and Python libraries