No single issuer can answer every trust question an AI agent needs to ask. Wallet state, reasoning integrity, behavioral history, job performance. These are different dimensions, verified by different systems, signed by different keys. The multi-attestation format makes them composable. One payload, one verification pass, any combination of issuers.

Update: the count is now nine issuers in the spec, five of them shipping signed wallet binding. The follow-up post is Would You Trust Your Agent? KYA Is Real.

The problem: trust is multi-dimensional

An AI agent about to execute a high-value contract needs to know several things about its counterparty. Does this wallet hold what it claims to hold? Has this agent been flagged for sybil behavior? These are exactly the dimensions that wallet trust profiles capture. Did it reason through the task correctly before acting? Did it deliver on its last three jobs?

No single service covers all of that. And no service should try to. Each dimension requires different data sources, different verification methods, and different expertise. The question is not how to build one issuer that does everything. The question is how to let multiple issuers produce results that a relying party can verify in a single pass.

Without a shared format, each issuer requires its own integration. Your service talks to one API for wallet checks, a different API for trust scores, a third for reasoning verification, a fourth for job history. Four SDKs, four auth mechanisms, four response shapes, four verification flows. Every new issuer you add is another integration to build and maintain.

With a shared format, integration happens once. The relying party implements one verification loop that handles any issuer. New issuers become interchangeable inputs, not new engineering projects. This is the only way multi-issuer systems scale without coordination.

The pattern that emerged independently

Four teams, building four different products, arrived at the same architecture without coordination:

  1. Sign your claims. Each issuer signs its attestation with its own key pair.
  2. Publish your keys. Each issuer hosts a JWKS endpoint so anyone can fetch the public key.
  3. Let relying parties verify offline. No callbacks, no shared infrastructure, no issuer coordination required.

This is the same pattern that made TLS certificates composable. A browser does not need every certificate authority to use the same signing pipeline. It just needs each one to sign with its own key and publish that key where relying parties can find it.

Four dimensions of trust

Dimension Issuer Type What It Verifies
Wallet State InsumerAPI wallet_state On-chain holdings, NFT ownership, token balances across 33 chains. Privacy-preserving: boolean results, not raw amounts.
Reasoning Integrity ThoughtProof reasoning_integrity Adversarial multi-model critique of AI agent reasoning before execution.
Behavioral Trust RNWY behavioral_trust Transparent trust scores for wallets and AI agents, sybil detection, on-chain oracle on Base.
Job Performance Maiat job_performance Job completion verification, deliverable quality, agent reliability scoring.

Each issuer maintains its own signing key, its own JWKS endpoint, and its own attestation schema. They do not share infrastructure. They do not need to agree on anything except the envelope format.

The format

A multi-attestation payload wraps attestations from multiple issuers in a single self-describing envelope. Each entry carries everything a verifier needs: the issuer, the attestation type, the key ID, the algorithm, the JWKS URL, the signed payload, and the signature.

{
  "v": 1,
  "attestations": [
    {
      "issuer": "https://api.insumermodel.com",
      "type": "wallet_state",
      "kid": "insumer-attest-v1",
      "alg": "ES256",
      "jwks": "https://insumermodel.com/.well-known/jwks.json",
      "signed": { ... },
      "sig": "..."
    },
    {
      "issuer": "https://api.thoughtproof.ai",
      "type": "reasoning_integrity",
      "kid": "tp-attestor-v1",
      "alg": "EdDSA",
      "jwks": "https://api.thoughtproof.ai/.well-known/jwks.json",
      "signed": { ... },
      "sig": "..."
    },
    {
      "issuer": "https://rnwy.com",
      "type": "behavioral_trust",
      "kid": "rnwy-trust-v1",
      "alg": "ES256",
      "jwks": "https://rnwy.com/.well-known/jwks.json",
      "signed": { ... },
      "sig": "..."
    },
    {
      "issuer": "https://app.maiat.io",
      "type": "job_performance",
      "kid": "maiat-trust-v1",
      "alg": "ES256",
      "jwks": "https://app.maiat.io/.well-known/jwks.json",
      "signed": { ... },
      "sig": "..."
    }
  ],
  "expired": []
}

The signed field contains each issuer's attestation payload. The sig field contains the signature over that payload. The expired array holds any attestations that were valid at collection time but have since expired.

How verification works

For each attestation in the payload, the verifier does three things:

  1. Fetch the JWKS. Use the jwks URL and kid to retrieve the issuer's public key.
  2. Check the signature. Verify sig against signed using the declared alg (ES256 for P-256, EdDSA for Ed25519).
  3. Check expiry. If the attestation includes an expiration timestamp, confirm it has not passed.

That is the entire verification flow. No callbacks to issuers. No shared secrets. No coordination. The verifier handles both raw P1363 signatures and JWT compact JWS formats, so issuers can use whichever signing approach they prefer.

The important part: a relying party integrates once with the verification format, not separately with each issuer. Four issuers today, ten tomorrow. The verification code does not change. That is what "single verification pass" actually means. Not batching. Not convenience. The elimination of per-issuer integration.

The reference verifier, multi-attest-verify.js, implements this in 546 lines with zero dependencies. It supports ES256 (P-256) and EdDSA (Ed25519) out of the box.

What relying parties decide

The payload is composable. A relying party decides which attestation types it requires based on the risk level of the transaction.

A low-value read operation might require only wallet_state. A mid-value API call might require wallet_state and behavioral_trust. The DJD Agent Score integration demonstrates this pattern in production. A high-value agent contract might require all four dimensions.

The relying party declares its requirements via requiredTypes in its verifier configuration:

const { verifyMultiAttestation } = require('./multi-attest-verify');

const result = await verifyMultiAttestation(payload, {
  requiredTypes: ['wallet_state', 'behavioral_trust']
});

if (result.valid) {
  // Required types present, signatures verified, not expired
}

If any required type is missing, if any signature fails, or if any required attestation has expired, the result is invalid. The relying party does not need to understand how each issuer generated its attestation. It only needs to verify the signature against the published key.

Why this works

The format works because it separates three concerns that are often tangled together:

No issuer needs to know about any other issuer. No relying party needs to integrate with each issuer individually. The format is the integration layer.

Issuer details

The spec and reference implementation

The multi-attestation format specification and reference verifier are open. The verifier is a single file, multi-attest-verify.js, with no runtime dependencies. It fetches JWKS endpoints, validates signatures across both ES256 and EdDSA, handles JWT and raw P1363 formats, and reports which attestation types passed, failed, or expired.

Any team building an attestation service can add their dimension to this format. Sign your claims, publish your JWKS, and declare your type. Relying parties will be able to verify your attestations in the same pass as everyone else's.

Verify your first wallet in 60 seconds

InsumerAPI is free to start. 10 verification credits, 100 daily reads, no credit card.

Get a Free API Key