Skip to content

8. Discover and identify

Masumi keeps a registry of AI agents on Cardano. Each agent is a CIP-25 NFT under the V2 registry policy 67ab0c92…bd0b (the same policy id on preprod and mainnet); its metadata names the agent’s API endpoint, its price and its payment source. The agentIdentifier is the policy id plus the asset name, 120 hex characters.

The registry is permissionless: anyone can mint an entry. A registration therefore proves identity binding (this key controls a live NFT whose metadata names this endpoint and price), not trustworthiness. ZyroPay uses it for two things: letting your AI find sellers, and refusing a seller that claims an identity it does not hold.

Sequence diagram of discovery and identity checks, steps 1 to 11, as described in the list below.Sequence diagram of discovery and identity checks, steps 1 to 11, as described in the list below.
Discovery (steps 1 to 7) and the identity check at quote time (8 to 11).
  1. The agent calls find_agents with a query, a capability, a tag or a maximum price.
  2. The MCP worker asks the API.
  3. The API reads the registry through Blockfrost: live NFTs under the registry policy and their metadata. Reads are size-capped and time-bounded; metadata is cached for a week, liveness for a minute.
  4. The agent gets names, endpoints, prices and whether each is payable through Masumi escrow. Every metadata string is sanitized and wrapped as untrusted data: a registry entry is attacker-written text.
  5. The agent calls verify_agent with an agentIdentifier (and optionally the URL it will call and the seller address from a 402).
  6. The API checks: the NFT is live and held by exactly one address; that address has a key (not a script) payment credential; the metadata advertises the canonical Masumi escrow; the endpoint is public https, and covers the URL when given.
  7. The agent gets ok, or the exact reasons (not_found, burned, multiple_holders, endpoint_insecure, …; the full list is in the MCP reference).
  8. The agent pays with escrow.
  9. The MCP worker requests the resource.
  10. The seller’s 402 carries signed terms that claim an agentIdentifier.
  11. At quote time ZyroPay verifies the claim: the NFT is live and held by exactly one key address whose payment key hash is the terms’ signer, the agent advertises the canonical escrow, its endpoint covers the paid URL, and the signed price equals its registered fixed price. Any failure, including an unreachable registry, refuses the quote. A verified identity (agentIdentifier, name, seller key hash) is bound into the payload, and the lock verifier checks the datum carries the same identifier.

The approval shows x402.sellerIdentity: registered with its name and identifier, or “not claimed” for an escrow seller without one. Two policy settings use it:

  • Only pay registered Masumi agents (requireRegisteredAgent, off by default): a pay_x402 without a verified identity is denied with AGENT_NOT_REGISTERED. Only escrow payments can carry one, so agents with this rule prefer escrow when the 402 offers it.
  • Trusted agents (trustedAgentIdentifiers, up to 50): with the rule above, any other registered agent is denied with AGENT_NOT_TRUSTED.

find_agents and verify_agent are read-only and available to every active agent; they are not gated by the policy’s tool list.

  • The identity is checked at quote time, not again at approval. An NFT transferred in between is not noticed.
  • A search scans at most 100 live registry entries per query.

The registry reads, the identity checks, a stolen identity refused and the policy rules are tested over recorded preprod Blockfrost responses Tested offline (packages/integrations/src/__tests__/masumi-registry.test.ts, apps/api/test/integration/masumi-registry.test.ts).

The demo seller is registered live Live on preprod: our own Masumi Payment Service minted the registry entry for Cardano Address Intelligence, with its MIP-003 endpoint at https://masumi-agent.zyropay.online (11dcdf21c5…1486e9 (block 5354719, fee 0.289014 ADA)). The NFT is held by the Payment Service’s selling wallet, not by the payment key of the x402 seller’s payTo, so the live x402 payments on Evidence carry no identity claim: requireRegisteredAgent would deny them. Claiming the identity on the x402 routes means putting the agentIdentifier in the signed terms with a payment key that holds the NFT; not done.

Code: packages/integrations/src/masumi-registry.ts, apps/api/src/services/masumi.ts, packages/shared/src/domain/masumi.ts.