Carry signed receipts across A2A agent flows: declare PEAC support in your Agent Card, attach receipts to task metadata, and extract/verify them on the receiving side.
PEAC integrates with A2A at the metadata layer. Receipts travel as Evidence Carriers inside A2A TaskStatus metadata, using the reverse-DNS extension URI org.peacprotocol. No A2A protocol changes are required; PEAC uses the standard metadata extension mechanism.
Compatibility: @peac/mappings-a2a targets A2A v1.0.0 (shipped in v0.12.3). A2A v0.3.0 compat shim is retained through v0.12.x; removal scheduled for v0.13.0.
- Node.js >= 22.0.0
@peac/mappings-a2a,@peac/protocol,@peac/crypto
pnpm add @peac/mappings-a2a @peac/protocol @peac/cryptoimport { generateKeypair } from '@peac/crypto';
import { issue } from '@peac/protocol';
import { attachReceiptToTaskStatus, type A2ATaskStatusLike } from '@peac/mappings-a2a';
import { computeReceiptRef } from '@peac/schema';
const { publicKey, privateKey } = await generateKeypair();
// Issue a receipt
const { jws } = await issue({
iss: 'https://gateway.example.com',
kind: 'evidence',
type: 'org.peacprotocol/payment',
extensions: {
'org.peacprotocol/commerce': {
payment_rail: 'stripe',
amount_minor: '5000',
currency: 'USD',
},
},
privateKey,
kid: 'gateway-key',
});
// Attach to A2A TaskStatus
const taskStatus: A2ATaskStatusLike = { state: 'completed', metadata: {} };
const ref = await computeReceiptRef(jws);
attachReceiptToTaskStatus(taskStatus, [{ receipt_ref: ref, receipt_jws: jws }]);
// taskStatus.metadata now contains the PEAC carrierA gateway agent issues one receipt per A2A task state transition (submitted, working, completed), building a verifiable chain.
See examples/a2a-gateway-pattern for the full runnable demo.
import { extractReceiptFromTaskStatusAsync } from '@peac/mappings-a2a';
import { verifyLocal } from '@peac/protocol';
const extracted = await extractReceiptFromTaskStatusAsync(taskStatus);
if (extracted) {
for (const carrier of extracted.receipts) {
if (!carrier.receipt_jws) continue;
const result = await verifyLocal(carrier.receipt_jws, publicKey);
console.log(result.valid ? 'Verified' : `Failed: ${result.code}`);
}
}Add the PEAC extension to your A2A Agent Card so peers know you support receipts:
{
"name": "My Agent",
"url": "https://agent.example.com",
"capabilities": {
"extensions": [
{
"uri": "org.peacprotocol",
"required": false,
"description": "PEAC evidence receipts for verifiable interaction records"
}
]
}
}Check for PEAC support: hasPeacExtension(agentCard) returns true if declared.
| Option | Type | Required | Description |
|---|---|---|---|
receipt_ref |
string |
Yes | SHA-256 hash of the compact JWS (computeReceiptRef()) |
receipt_jws |
string |
Yes | The compact JWS receipt |
receipt_url |
string |
No | Optional HTTPS locator hint (not auto-fetched) |
Transport size limit: 64 KB for MCP/A2A/UCP embed.
No receipts found after extraction:
Verify the metadata key is org.peacprotocol (not org.peacprotocol/receipt). Check hasPeacExtension() on the agent card.
Receipt ref mismatch:
The receipt_ref must equal sha256(receipt_jws). Use computeReceiptRef() from @peac/schema.
Verification fails with E_ISS_NOT_CANONICAL:
The iss field must be https:// (ASCII, RFC 3986) or did: (DID Core). No other schemes are accepted.
- Agent Identity for ActorBinding and proof types
- Workflow Correlation for multi-step DAG linking
- Evidence Carrier Contract for transport details
- A2A Protocol for the upstream specification