Trulioo · A2A extension

Know Your Agent (KYA) - A2A Extension v1

The normative definition of the Trulioo KYA trust block carried on an A2A Agent Card. This URL is the extension identifier - an A2A client that sees this uri resolves it here.

https://identity.trulioo.com/a2a/kya/v1

Attachment

KYA attaches as an AgentExtension under capabilities.extensions[] (never a top-level card field). The whole card is signed in signatures[].

{
  "capabilities": {
    "extensions": [{
      "uri": "https://identity.trulioo.com/a2a/kya/v1",
      "description": "Trulioo KYA verified-identity attestation.",
      "required": true,
      "params": { /* KYA block - see schema.json */ }
    }]
  }
}

The KYA block (params)

params has three members, two of them required. attestation is the authoritative compact JWS a verifier MUST check; display is a non-authoritative mirror of the signed claims, for rendering only.

{
  "attestation": "<compact JWS>",   // typ=kya-attestation+jwt, alg=EdDSA - THE source of truth
  "display": {                     // mirror of the JWS payload; do NOT trust independently
    "verified": true,
    "verified_as_of": "2026-07-02T00:00:00Z",
    "allowed_scopes": ["purchase"],   // signed mandate scope
    "issuer": "https://identity.trulioo.com",
    "fingerprint": "<sha256, binds to the card>"
  }
}

The JWS payload (decode attestation) carries the header claims iss, sub (=fingerprint), iat, exp plus the same block fields flattened. display is exactly that payload minus the JWT envelope.

The dap reference (optional, v3)

A third, OPTIONAL member points at the agent's Digital Agent Profile. It is a reference, never an inlined credential.

{
  "dap": {
    "vct": "https://identity.trulioo.com/vct/agent-profile.1",
    "suite": "ats-v2",
    "issuer": "https://identity.trulioo.com",   // PIN this JWKS
    "verify_endpoint": "https://identity.trulioo.com/kya/dap/verify",
    "presentation_endpoint": "https://agent.example.com/dap/present"  // AGENT-hosted, optional
  }
}

Why not embed the passport: an agent card is a long-lived, cacheable document served to everyone, while a DAP is a ≤600s credential that only means anything when presented with a Key-Binding JWT bound to one verifier's audience and nonce. Inlining one would ship bytes past their exp, discard the holder-of-key proof (any card reader could replay the credential as its own), and destroy selective disclosure. presentation_endpoint is agent-hosted and is never defaulted to an identity.trulioo.com URL: only the agent holds the cnf private key, so the issuer cannot present on its behalf.

Normative rules

Verify an agent

Fetch the issuer keys, then verify the attestation offline; or look up by fingerprint (public, no key):

# issuer signing keys
curl -s "https://identity.trulioo.com/.well-known/jwks.json"

# public look-up (independent re-check by fingerprint)
curl -s "https://identity.trulioo.com/kya/attestation/<fingerprint>"
Status: draft normative (v1). Breaking changes bump the /v1 path segment; new OPTIONAL members do not - agent_id/build_id (v2) and dap (v3) were added this way, so "v2"/"v3" name the claim generation, not a new URI. A v1-only verifier reading a v3 block sees only the members it knew and behaves identically. Note the widening is one-way: params and display are additionalProperties: false, so the schema must name a member before any card emits it. The namespace URI (https://identity.trulioo.com/a2a/kya/v1) is the contract - a stable identifier string-matched by relying parties, served from the issuer host. Source: commerce/halo/docs/kya-a2a-extension-spec.md.