Trust Layer
W3C DID identity, Verifiable Credentials, mutual notarization, and reputation scoring for AI agents.
Overview
Aira's trust layer extends the agent registry with standards-based identity and trust:
- DID Identity — every agent gets a W3C DID (did:web)
- Verifiable Credentials — Aira issues signed VCs attesting agent capabilities
- Mutual Notarization — bilateral signing for high-stakes actions
- Reputation — computed trust score from notarized transaction history
All built on W3C DID Core v1.1, W3C Verifiable Credentials v2.0, Ed25519 signatures, and RFC 3161 timestamps. No blockchain.
DID Identity
Every registered agent automatically gets a W3C-compliant DID:
did:web:airaproof.com:agents:{agent_slug}Resolves publicly at:
https://airaproof.com/agents/{agent_slug}/did.jsonThe DID document follows the W3C DID Core v1.1 specification:
{
"@context": ["https://www.w3.org/ns/did/v1", "https://w3id.org/security/suites/ed25519-2020/v1"],
"id": "did:web:airaproof.com:agents:my-agent",
"verificationMethod": [{
"id": "did:web:airaproof.com:agents:my-agent#key-1",
"type": "Ed25519VerificationKey2020",
"controller": "did:web:airaproof.com:agents:my-agent",
"publicKeyMultibase": "z6Mkf5rGMoatrSj1f..."
}],
"authentication": ["did:web:airaproof.com:agents:my-agent#key-1"],
"assertionMethod": ["did:web:airaproof.com:agents:my-agent#key-1"],
"service": [{
"id": "did:web:airaproof.com:agents:my-agent#aira",
"type": "AiraNotarization",
"serviceEndpoint": "https://airaproof.com/api/v1"
}]
}Key Rotation
aira.rotate_agent_keys("my-agent")await aira.rotateAgentKeys("my-agent");Previous keys are retained in the DID document for historical verification but removed from authentication.
A2A Agent Card
Published at /agents/{slug}/.well-known/agent-card.json — compatible with the Google A2A protocol. The agent card includes the DID reference, supported capabilities, and service endpoint for cross-platform agent discovery.
Verifiable Credentials
Aira issues a W3C Verifiable Credential for each agent, signed with Ed25519:
{
"@context": ["https://www.w3.org/2018/credentials/v1", "https://airaproof.com/credentials/v1"],
"type": ["VerifiableCredential", "AiraAgentCredential"],
"issuer": "did:web:airaproof.com",
"issuanceDate": "2026-03-15T10:00:00Z",
"credentialSubject": {
"id": "did:web:airaproof.com:agents:my-agent",
"capabilities": ["email", "chat", "tickets"],
"organizationId": "org-uuid",
"registeredAt": "2026-03-15T10:00:00Z"
},
"credentialStatus": {
"id": "https://airaproof.com/credentials/status/1#42",
"type": "StatusList2021Entry",
"statusPurpose": "revocation",
"statusListIndex": "42",
"statusListCredential": "https://airaproof.com/credentials/status/1"
},
"proof": {
"type": "Ed25519Signature2020",
"created": "2026-03-15T10:00:00Z",
"verificationMethod": "did:web:airaproof.com#key-1",
"proofPurpose": "assertionMethod",
"proofValue": "z3FXQjecWufY46..."
}
}Issue & Verify
vc = aira.get_agent_credential("my-agent")
result = aira.verify_credential(vc)
print(result["valid"]) # Trueconst vc = await aira.getAgentCredential("my-agent");
const result = await aira.verifyCredential(vc);
console.log(result.valid); // trueRevocation
aira.revoke_credential("my-agent", reason="Agent deprecated")await aira.revokeCredential("my-agent", { reason: "Agent deprecated" });StatusList2021
Revocation status is published at /credentials/status/{list_id} using the W3C StatusList2021 specification. Any third party can check revocation status without contacting Aira directly.
Mutual Notarization
For high-stakes actions, both parties co-sign. This creates a bilateral cryptographic receipt where neither party can later deny participation.
Flow
- Agent A initiates a mutual signing request, specifying the action and counterparty DID.
- Agent B reviews the payload, signs it, and completes the request.
- Aira seals both signatures with an RFC 3161 timestamp into a tamper-proof receipt.
Python
# Agent A initiates
request = aira.request_mutual_sign(
action_uuid="act-uuid",
counterparty_did="did:web:partner.com:agents:their-agent"
)
# Agent B completes
receipt = aira.complete_mutual_sign(
action_uuid="act-uuid",
did="did:web:partner.com:agents:their-agent",
signature="z...",
signed_payload_hash="sha256:..."
)TypeScript
// Agent A initiates
const request = await aira.requestMutualSign({
actionId: "act-uuid",
counterpartyDid: "did:web:partner.com:agents:their-agent",
});
// Agent B completes
const receipt = await aira.completeMutualSign({
actionId: "act-uuid",
did: "did:web:partner.com:agents:their-agent",
signature: "z...",
signedPayloadHash: "sha256:...",
});Canonicalization
Payload canonicalization uses JCS (RFC 8785) to ensure deterministic serialization before signing. Both signatures plus the RFC 3161 timestamp are included in the sealed receipt.
Reputation Score
Every agent accumulates a verifiable reputation score (0-100), computed deterministically from on-chain transaction history.
Components
| Component | Weight |
|---|---|
| Action volume | 20% |
| Mutual signing completion rate | 30% |
| Dispute rate | 25% |
| VC validity | 15% |
| Account age | 10% |
Tiers
| Tier | Score Range |
|---|---|
| Unverified | 0 -- 30 |
| Provisional | 31 -- 60 |
| Trusted | 61 -- 80 |
| Verified | 81 -- 100 |
Query Reputation
rep = aira.get_reputation("my-agent")
print(rep["score"]) # 84
print(rep["tier"]) # "Verified"const rep = await aira.getReputation("my-agent");
console.log(rep.score); // 84
console.log(rep.tier); // "Verified"The score is deterministic and independently verifiable via the score_hash field. Recalculating the score from the public notarization history must produce the same hash.
Endpoint Verification
Actions that involve external API calls are verified against the organization's endpoint whitelist:
- Whitelisted — notarize normally
- Not whitelisted — blocked (strict mode) or flagged (permissive mode)
- TLS fingerprint — recorded on first call and verified on subsequent calls
Known providers (Stripe, OpenAI, Anthropic, Google, AWS) get automatic signature verification against their published public keys.
Configure Endpoint Policy
aira.set_endpoint_policy(
mode="strict", # or "permissive"
whitelist=["https://api.stripe.com", "https://api.openai.com"],
)await aira.setEndpointPolicy({
mode: "strict", // or "permissive"
whitelist: ["https://api.stripe.com", "https://api.openai.com"],
});