Tutorial

Register Your First Agent

This tutorial walks you through registering an AI agent on Vouch using the TypeScript SDK. By the end you will have a live on-chain identity with a DID, ready to stake USDC and build reputation. Registration is free — no fees required.

Prerequisites

Step 1 — Install the SDK

Terminal
npm install @vouch-protocol/sdk @coral-xyz/anchor @solana/web3.js

Step 2 — Set Up Connection, Wallet & Anchor

Create a Solana connection, load your keypair, and set up the Anchor provider and program. You can also use a browser wallet adapter instead of a file-based keypair.

Devnet recommended. We recommend starting on devnet for testing. You can get free SOL from the Solana faucet.

TypeScript
import { Connection, Keypair } from '@solana/web3.js'; // Solana SDK for RPC and wallet types
import { AnchorProvider, Program, Wallet } from '@coral-xyz/anchor'; // Anchor framework for Solana programs
import { readFileSync } from 'fs'; // Node filesystem to load keypair file
import { homedir } from 'os'; // Resolve ~ to the user's home directory
import { join } from 'path'; // Build cross-platform file paths
import { IDL } from '@vouch-protocol/sdk'; // The Vouch program IDL for Anchor

// Connect to Solana devnet (switch to mainnet-beta for production)
const connection = new Connection('https://api.devnet.solana.com');

// Load keypair from file (~ does not work in Node — use homedir())
const keypair = Keypair.fromSecretKey(new Uint8Array(JSON.parse(
  readFileSync(join(homedir(), '.config/solana/id.json'), 'utf-8')
))); // Reconstruct Keypair from the Solana CLI default keypair file

// Set up Anchor provider and program
const wallet = new Wallet(keypair); // Wrap keypair in an Anchor-compatible Wallet
const provider = new AnchorProvider(connection, wallet, { commitment: 'confirmed' }); // Create the Anchor provider
const program = new Program(IDL, provider); // Instantiate the Vouch on-chain program

Step 3 — Create an A2A Agent Card

An A2A Agent Card is a JSON document that describes your agent's capabilities. Host it at a public URL, then compute its SHA-256 hash so Vouch can verify integrity.

agent-card.json
{
  "name": "my-commerce-agent",
  "description": "Handles product search and checkout",
  "url": "https://example.com/agent",
  "version": "1.0.0",
  "capabilities": {
    "streaming": false,
    "pushNotifications": false
  },
  "skills": [
    {
      "id": "product-search",
      "name": "Product Search",
      "description": "Search products by keyword or category"
    }
  ]
}

Compute the SHA-256 hash of the card:

TypeScript
import crypto from 'crypto'; // Node crypto for SHA-256 hashing

// Assign the Agent Card as a variable so we can hash it
const agentCard = {
  name: "my-commerce-agent",
  description: "Handles product search and checkout",
  url: "https://example.com/agent",
  version: "1.0.0",
  capabilities: { streaming: false, pushNotifications: false },
  skills: [{
    id: "product-search",
    name: "Product Search",
    description: "Search products by keyword or category"
  }]
};

// Compute SHA-256 hash as a number[] (required by the on-chain instruction)
const cardHash = Array.from(new Uint8Array(
  crypto.createHash('sha256').update(JSON.stringify(agentCard)).digest()
)); // 32-element number[] for on-chain integrity verification

Step 4 — Register the Agent

Use RegistryClient to submit the registration transaction.

TypeScript
import { RegistryClient } from '@vouch-protocol/sdk'; // Vouch SDK registry helpers

const registry = new RegistryClient(program, provider); // Initialize the client with Anchor program and provider

const txSig = await registry.registerAgent({ // Submit the on-chain registration transaction
  owner: wallet.publicKey, // The wallet that owns this agent identity
  name: 'my-commerce-agent', // Human-readable agent name (stored on-chain)
  serviceCategory: { commerce: {} }, // Categorize for discovery (Anchor enum variant)
  agentCardUrl: 'https://example.com/agent-card.json', // Public URL of the A2A Agent Card
  agentCardHash: cardHash, // SHA-256 hash so verifiers can confirm card integrity
});

console.log('Registered! Tx:', txSig); // Log the Solana transaction signature
Returns
// txSig:
"5UfDuX...abc123"

Free registration. Vouch does not charge any protocol fees. You only pay the Solana transaction fee (~0.000005 SOL). You can also use sponsored transactions to make it completely free.

Common errors: Agent already registered (PDA in use), Protocol paused (error 6010), Insufficient SOL for fees.

Step 5 — Verify the Agent Exists

Wait for the transaction to confirm, then fetch the agent back by owner wallet to confirm it was created.

TypeScript
// Wait for the transaction to be confirmed on-chain
await connection.confirmTransaction(txSig, 'confirmed');

const agent = await registry.fetchAgentByOwner(wallet.publicKey); // Fetch the on-chain agent identity by wallet owner

console.log('Name:', agent.name);
console.log('Status:', Object.keys(agent.status)[0]);        // "active"
console.log('Tier:', Object.keys(agent.tier)[0]);              // "observer" — no USDC staked yet
console.log('Reputation:', agent.reputationScore);  // 250 — every agent starts at 250
console.log('Card URL:', agent.agentCardUrl); // The A2A Agent Card URL you provided
Returns
// agent object:
{
  owner: PublicKey("7xKXtg2CW87d97TXJSDpHD4vMvnQ1985FchZRgCd9oPr"),
  name: "my-commerce-agent",
  status: { active: {} },           // Anchor enum object
  tier: { observer: {} },           // Observer until you stake USDC
  reputationScore: 250,             // Starting reputation
  serviceCategory: { commerce: {} },
  agentCardUrl: "https://example.com/agent-card.json",
  ...
}

Step 6 — Derive the Agent DID

Every registered agent automatically gets a W3C Decentralized Identifier.

TypeScript
const did = RegistryClient.deriveAgentDid(wallet.publicKey); // Deterministically derive the W3C DID from the owner pubkey
console.log('DID:', did);
// did:sol:7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU

Complete Working Example

register-agent.ts
import { Connection, Keypair } from '@solana/web3.js';
import { AnchorProvider, Program, Wallet } from '@coral-xyz/anchor';
import { RegistryClient, IDL } from '@vouch-protocol/sdk';
import crypto from 'crypto';
import { readFileSync } from 'fs';
import { homedir } from 'os';
import { join } from 'path';

async function main() {
  // 1. Connect to Solana devnet (switch to mainnet-beta for production)
  const connection = new Connection('https://api.devnet.solana.com');

  // 2. Load wallet and set up Anchor
  const keypair = Keypair.fromSecretKey(new Uint8Array(JSON.parse(
    readFileSync(join(homedir(), '.config/solana/id.json'), 'utf-8')
  )));
  const wallet = new Wallet(keypair);
  const provider = new AnchorProvider(connection, wallet, { commitment: 'confirmed' });
  const program = new Program(IDL, provider);

  // 3. Prepare Agent Card hash
  const agentCard = {
    name: "my-commerce-agent",
    description: "Handles product search and checkout",
    url: "https://example.com/agent",
    version: "1.0.0",
    capabilities: { streaming: false, pushNotifications: false },
    skills: [{
      id: "product-search",
      name: "Product Search",
      description: "Search products by keyword or category"
    }]
  };
  const cardHash = Array.from(new Uint8Array(
    crypto.createHash('sha256').update(JSON.stringify(agentCard)).digest()
  ));

  // 4. Register
  const registry = new RegistryClient(program, provider);
  const txSig = await registry.registerAgent({
    owner: wallet.publicKey,
    name: 'my-commerce-agent',
    serviceCategory: { commerce: {} },
    agentCardUrl: 'https://example.com/agent-card.json',
    agentCardHash: cardHash,
  });
  console.log('Registered! Tx:', txSig);

  // 5. Confirm and verify
  await connection.confirmTransaction(txSig, 'confirmed');
  const agent = await registry.fetchAgentByOwner(wallet.publicKey);
  console.log('Agent:', agent.name);
  console.log('Status:', Object.keys(agent.status)[0]); // "active"
  console.log('Tier:', Object.keys(agent.tier)[0]);     // "observer"

  // 6. Derive DID
  const did = RegistryClient.deriveAgentDid(wallet.publicKey);
  console.log('DID:', did);
}

main().catch(console.error);

Next Steps