Tenzro Testnet is live. Get testnet TNZO
← Back to Tutorials
AI AgentsAdvanced

Build an AI Agent That Pays for Services

Build an autonomous AI agent from scratch with its own identity, wallet, and payment capabilities. This tutorial covers the complete agent economy workflow: identity registration, wallet provisioning, service discovery via A2A protocol, and autonomous payments using MPP. By the end, you'll have an agent that can pay for AI inference per token generated.

What We're Building

We're building an AI agent that can:

This is the foundation of the agent economy: autonomous entities that can find services, negotiate prices, pay for consumption, and verify receipts—all without human intervention for each transaction.

Prerequisites

  • Basic understanding of JSON-RPC APIs
  • Familiarity with public/private key cryptography
  • curl or equivalent HTTP client
  • Access to Tenzro testnet (public endpoints, no auth required)

Estimated time: 45 minutes

Architecture Overview

Here's the complete flow we'll implement:

┌─────────────────────────────────────────────────────────────────┐
 Step 1: Identity Registration                                  
 Human Guardian  tenzro_registerIdentity  Guardian DID        
 Guardian  Create Machine Identity  Agent DID + DelegationScope
└─────────────────────────────────────────────────────────────────┘
                              
┌─────────────────────────────────────────────────────────────────┐
 Step 2: Wallet Provisioning                                    
 Agent DID  tenzro_createWallet  MPC Wallet (2-of-3)          
 Faucet  Fund Agent Wallet  100 TNZO                          
└─────────────────────────────────────────────────────────────────┘
                              
┌─────────────────────────────────────────────────────────────────┐
 Step 3: Service Discovery (A2A Protocol)                       
 Agent  GET /.well-known/agent.json  Agent Card               
 Agent Card: skills=[wallet, identity, inference, ...]           
└─────────────────────────────────────────────────────────────────┘
                              
┌─────────────────────────────────────────────────────────────────┐
 Step 4: Payment for Inference (MPP)                            
 Agent  Request Inference  HTTP 402 Challenge                 
 Agent  Create MPP Credential  Send with Retry                
 Provider  Verify  Stream Tokens  Update Vouchers            
 Provider  Complete  Final Receipt                            
└─────────────────────────────────────────────────────────────────┘
                              
┌─────────────────────────────────────────────────────────────────┐
 Step 5: Micropayment Channels (Per-Token Billing)              
 Agent  Open Channel  Lock 10 TNZO Escrow                     
 Provider  Generate Token  Signed Update (+0.01 TNZO)         
 Provider  Generate Token  Signed Update (+0.02 TNZO)         
 ...                                                             
 Provider  Complete  Close Channel  On-Chain Settlement      
└─────────────────────────────────────────────────────────────────┘

Step 1: Create the Agent's Identity

Every AI agent on Tenzro needs a decentralized identity (DID) following the Tenzro Decentralized Identity Protocol (TDIP). Agents cannot self-register—they must be created by a human guardian who sets spending limits and permissions via a DelegationScope.

1a. Register the Human Guardian

First, the human user (you) needs a guardian identity:

curl -X POST https://rpc.tenzro.network \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "tenzro_registerIdentity",
    "params": [{
      "identity_type": "human",
      "display_name": "Alice (Agent Guardian)",
      "key_type": "ed25519"
    }],
    "id": 1
  }'

# Response:
{
  "jsonrpc": "2.0",
  "result": {
    "did": "did:tenzro:human:550e8400-e29b-41d4-a716-446655440001",
    "status": "active",
    "private_key": "ed25519:5J7X9Y2Z... (keep this secret!)",
    "public_key": "ed25519:B8C9D0E1...",
    "created_at": "2026-03-24T10:00:00Z"
  },
  "id": 1
}

Important: Save the private_key securely. You'll need it to sign operations on behalf of your guardian identity. In production, this would be stored in a hardware wallet or secure enclave—never in plaintext.

1b. Create the Machine Identity with Delegation Scope

Now create the agent's machine identity. The guardian sets a DelegationScope that constrains what the agent can do:

curl -X POST https://rpc.tenzro.network \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "tenzro_registerIdentity",
    "params": [{
      "identity_type": "machine",
      "controller_did": "did:tenzro:human:550e8400-e29b-41d4-a716-446655440001",
      "display_name": "InferenceBot Alpha",
      "key_type": "secp256k1",
      "delegation_scope": {
        "max_transaction_value": "10.00",
        "max_daily_spend": "100.00",
        "allowed_operations": ["InferenceRequest", "Transfer"],
        "allowed_contracts": [],
        "allowed_payment_protocols": ["Mpp", "X402"],
        "allowed_chains": ["tenzro"],
        "time_bound": {
          "expires_at": "2026-06-24T00:00:00Z"
        }
      }
    }],
    "id": 2
  }'

# Response:
{
  "jsonrpc": "2.0",
  "result": {
    "did": "did:tenzro:machine:550e8400-e29b-41d4-a716-446655440001:a1b2c3d4",
    "status": "active",
    "controller_did": "did:tenzro:human:550e8400-e29b-41d4-a716-446655440001",
    "private_key": "secp256k1:K9L0M1N2... (agent's signing key)",
    "public_key": "secp256k1:O3P4Q5R6...",
    "delegation_scope": { ... },
    "created_at": "2026-03-24T10:05:00Z"
  },
  "id": 2
}

This DelegationScope means the agent can:

The agent's DID includes the guardian's DID as the controller: did:tenzro:machine:550e8400...440001:a1b2c3d4. Anyone can verify the trust chain by resolving the DIDs.

Step 2: Provision the Agent's Wallet

The agent needs a wallet to hold funds and sign payment transactions. Tenzro uses MPC (multi-party computation) threshold wallets: 2-of-3 key shares, meaning any 2 shares can sign but no single share is enough. This provides security even if one share is compromised.

2a. Create the MPC Wallet

curl -X POST https://rpc.tenzro.network \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "tenzro_createWallet",
    "params": [{
      "owner_did": "did:tenzro:machine:550e8400-e29b-41d4-a716-446655440001:a1b2c3d4",
      "threshold": 2,
      "total_shares": 3,
      "key_type": "secp256k1"
    }],
    "id": 3
  }'

# Response:
{
  "jsonrpc": "2.0",
  "result": {
    "wallet_id": "wallet_9f8e7d6c5b4a",
    "address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb4",
    "public_key": "secp256k1:0x04a1b2c3...",
    "threshold": 2,
    "total_shares": 3,
    "owner_did": "did:tenzro:machine:550e8400-e29b-41d4-a716-446655440001:a1b2c3d4",
    "created_at": "2026-03-24T10:10:00Z"
  },
  "id": 3
}

The wallet's Ethereum-style address is 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb4. The 3 MPC key shares are stored securely:

To sign a transaction, the agent combines share 1 (which it controls) with share 2 (obtained by proving its DID to the guardian service). This 2-of-3 threshold is sufficient to create a valid signature.

2b. Fund the Wallet via Faucet

For testnet, we'll use the faucet to give the agent 100 TNZO:

curl -X POST https://api.tenzro.network/api/faucet \
  -H "Content-Type: application/json" \
  -d '{
    "address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb4"
  }'

# Response:
{
  "success": true,
  "amount": "100.0",
  "tx_hash": "0x1a2b3c4d5e6f7890abcdef1234567890abcdef12",
  "message": "Sent 100 TNZO to 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb4"
}

2c. Verify Balance

curl -X POST https://rpc.tenzro.network \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "tenzro_getBalance",
    "params": ["0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb4"],
    "id": 4
  }'

# Response:
{
  "jsonrpc": "2.0",
  "result": "0x56bc75e2d63100000",  # 100 TNZO in hex wei
  "id": 4
}

# Convert hex to decimal:
# 0x56bc75e2d63100000 = 100000000000000000000 wei = 100 TNZO

The agent now has 100 TNZO and can make up to 10 transactions at the max $10 limit before needing to be refunded.

Step 3: Discover Services via A2A Protocol

The Agent-to-Agent (A2A) protocol is how AI agents discover each other's capabilities. Every agent publishes an Agent Card at /.well-known/agent.json describing its skills.

3a. Fetch the Tenzro Network Agent Card

curl https://a2a.tenzro.network/.well-known/agent.json | jq .

# Response:
{
  "agent_id": "tenzro-network-a2a-v1",
  "name": "Tenzro Network Agent",
  "description": "Primary A2A interface for Tenzro Network services",
  "version": "1.0.0",
  "capabilities": {
    "protocols": ["a2a-v1", "mcp-v1"],
    "skills": [
      {
        "id": "wallet",
        "name": "Wallet Operations",
        "description": "Create wallets, check balances, send transactions"
      },
      {
        "id": "identity",
        "name": "Identity Management",
        "description": "Register and resolve DIDs, manage credentials"
      },
      {
        "id": "inference",
        "name": "AI Inference",
        "description": "Submit inference requests to registered model providers"
      },
      {
        "id": "settlement",
        "name": "Payment Settlement",
        "description": "Process payments, escrow, and micropayment channels"
      },
      {
        "id": "verification",
        "name": "Cryptographic Verification",
        "description": "Verify ZK proofs, TEE attestations, signatures"
      }
    ]
  },
  "endpoints": {
    "rpc": "https://a2a.tenzro.network/a2a",
    "stream": "https://a2a.tenzro.network/a2a/stream"
  },
  "payment": {
    "methods": ["mpp", "x402"],
    "currencies": ["TNZO", "USDC"]
  }
}

The agent now knows that Tenzro Network offers inference services and supports MPP payments in TNZO. Perfect for our use case.

3b. Send an A2A Task

Let's send a task to request AI inference. A2A uses JSON-RPC 2.0:

curl -X POST https://a2a.tenzro.network/a2a \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "tasks/send",
    "params": {
      "skill": "inference",
      "action": "request",
      "inputs": {
        "model": "gpt-4",
        "prompt": "Explain quantum computing in one sentence.",
        "max_tokens": 50
      },
      "requester_did": "did:tenzro:machine:550e8400-e29b-41d4-a716-446655440001:a1b2c3d4"
    },
    "id": 5
  }'

# Response:
{
  "jsonrpc": "2.0",
  "result": {
    "task_id": "task_k9j8h7g6f5",
    "status": "payment_required",
    "payment_challenge": {
      "protocol": "mpp",
      "amount": "2.50",
      "currency": "TNZO",
      "session_id": "mpp_sess_a1b2c3d4",
      "challenge_nonce": "0x9f8e7d6c5b4a3f2e1d0c9b8a7f6e5d4c",
      "expires_at": "2026-03-24T10:25:00Z"
    }
  },
  "id": 5
}

The inference provider responds with a payment challenge. The agent must create an MPP credential to proceed.

Step 4: Pay for Inference Using MPP

Machine Payments Protocol (MPP) is session-based: open a session, accumulate charges as the service is consumed (per token for AI inference), then settle at the end. This is more efficient than paying per token on-chain.

4a. Create MPP Credential

The agent creates a credential proving it can pay:

# Agent's wallet signs the challenge nonce
SIGNATURE=$(echo -n "mpp_sess_a1b2c3d4:0x9f8e7d6c5b4a3f2e1d0c9b8a7f6e5d4c" | \
  openssl dgst -sha256 -sign agent_wallet_key.pem | base64)

curl -X POST https://a2a.tenzro.network/a2a \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "tasks/send",
    "params": {
      "task_id": "task_k9j8h7g6f5",
      "payment_credential": {
        "protocol": "mpp",
        "session_id": "mpp_sess_a1b2c3d4",
        "payer_did": "did:tenzro:machine:550e8400-e29b-41d4-a716-446655440001:a1b2c3d4",
        "payer_address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb4",
        "amount": "2.50",
        "currency": "TNZO",
        "signature": "'"$SIGNATURE"'"
      }
    },
    "id": 6
  }'

4b. Provider Verifies and Starts Inference

# Response:
{
  "jsonrpc": "2.0",
  "result": {
    "task_id": "task_k9j8h7g6f5",
    "status": "processing",
    "inference": {
      "model": "gpt-4",
      "tokens_generated": 0,
      "cost_per_token": "0.05",
      "total_cost": "0.00"
    },
    "session": {
      "id": "mpp_sess_a1b2c3d4",
      "vouchers": []
    }
  },
  "id": 6
}

4c. Stream Tokens with Per-Token Charges

As the model generates tokens, the provider issues vouchers—signed micropayment receipts—for each token:

# Agent polls or subscribes to SSE stream at /a2a/stream
curl https://a2a.tenzro.network/a2a/stream?task_id=task_k9j8h7g6f5

# Server-Sent Events stream:
event: token
data: {"token": "Quantum", "cost": "0.05", "total": "0.05"}

event: voucher
data: {"session_id": "mpp_sess_a1b2c3d4", "amount": "0.05", "signature": "0x1a2b3c..."}

event: token
data: {"token": " computing", "cost": "0.05", "total": "0.10"}

event: voucher
data: {"session_id": "mpp_sess_a1b2c3d4", "amount": "0.10", "signature": "0x4d5e6f..."}

# ... continues for 48 tokens ...

event: complete
data: {
  "task_id": "task_k9j8h7g6f5",
  "tokens_generated": 48,
  "total_cost": "2.40",
  "response": "Quantum computing uses quantum bits (qubits) that exist in superposition states to perform certain calculations exponentially faster than classical computers.",
  "receipt": {
    "session_id": "mpp_sess_a1b2c3d4",
    "amount": "2.40",
    "settled": true,
    "tx_hash": "0x7g8h9i0j1k2l3m4n5o6p7q8r9s0t1u2v3w4x5y6z",
    "timestamp": "2026-03-24T10:20:15Z"
  }
}

The final cost was 2.40 TNZO (48 tokens × 0.05 TNZO/token), which is under the agent's max_transaction_value of $10 and within its daily budget. The provider settled on-chain with a single transaction instead of 48 separate payments—this is why MPP is efficient for streaming services.

Step 5: Micropayment Channels for Ultra-Low Fees

For even higher frequency payments (e.g., 100,000 tokens/day), even MPP's single settlement per session can add up in gas fees. Micropayment channels solve this by keeping payments entirely off-chain until channel close.

How Micropayment Channels Work

┌─────────────────────────────────────────────────────────────────┐
 Channel Lifecycle                                               
└─────────────────────────────────────────────────────────────────┘

1. OPEN CHANNEL (on-chain transaction)
   Agent  Lock 10 TNZO in escrow contract
   Provider  Acknowledge channel open
   Channel ID: ch_xyz123

2. OFF-CHAIN UPDATES (no blockchain transactions)
   For each token generated:
   - Provider sends signed state update: { channel_id, amount: 0.05, nonce: 1 }
   - Agent verifies signature and stores update
   - Provider generates next token
   - Provider sends signed update: { channel_id, amount: 0.10, nonce: 2 }
   - Agent verifies and stores (discarding old update)
   ... repeat 10,000 times ...

3. CLOSE CHANNEL (on-chain transaction)
   Either party submits latest signed state update to escrow contract
   Contract verifies signature and nonce (must be highest nonce seen)
   Contract releases: 2.40 TNZO  Provider, 7.60 TNZO  Agent refund

Total on-chain transactions: 2 (open + close)
Total off-chain updates: 10,000
Gas savings: 99.98%

Opening a Channel

curl -X POST https://rpc.tenzro.network \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "tenzro_openPaymentChannel",
    "params": [{
      "payer": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb4",
      "payee": "0x9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d3e2f1a0b",
      "amount": "10.0",
      "duration": 86400  # 24 hours
    }],
    "id": 7
  }'

# Response:
{
  "jsonrpc": "2.0",
  "result": {
    "channel_id": "ch_m9n8o7p6q5",
    "payer": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb4",
    "payee": "0x9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d3e2f1a0b",
    "locked_amount": "10.0",
    "current_balance": "0.0",
    "nonce": 0,
    "expires_at": "2026-03-25T10:30:00Z",
    "tx_hash": "0xa1b2c3d4e5f6..."
  },
  "id": 7
}

Off-Chain Updates During Inference

# Provider generates first token, sends signed update:
{
  "channel_id": "ch_m9n8o7p6q5",
  "amount": "0.05",
  "nonce": 1,
  "signature": "0x1a2b3c..."  # Provider's signature over (channel_id, amount, nonce)
}

# Agent verifies:
# 1. Signature is from expected payee (0x9a8b7c...)
# 2. Nonce is incremental (was 0, now 1)
# 3. Amount is <= locked_amount (0.05 <= 10.0)
# 4. Store this update, discard previous

# ... 1000 more tokens generated ...

# Provider sends update after 1000 tokens:
{
  "channel_id": "ch_m9n8o7p6q5",
  "amount": "50.00",  # 1000 tokens * 0.05 TNZO
  "nonce": 1001,
  "signature": "0x9z8y7x..."
}

# Agent notices: 50 TNZO > 10 TNZO locked. Time to close and open new channel!

Closing the Channel

curl -X POST https://rpc.tenzro.network \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "tenzro_closePaymentChannel",
    "params": [{
      "channel_id": "ch_m9n8o7p6q5",
      "final_amount": "10.0",
      "nonce": 1000,
      "signature": "0x8w7v6u..."  # Provider's signature on final state
    }],
    "id": 8
  }'

# Response:
{
  "jsonrpc": "2.0",
  "result": {
    "channel_id": "ch_m9n8o7p6q5",
    "final_amount": "10.0",
    "payer_refund": "0.0",
    "payee_payment": "10.0",
    "tx_hash": "0xz9y8x7w6...",
    "settled_at": "2026-03-24T11:00:00Z"
  },
  "id": 8
}

The channel consumed all 10 TNZO locked in escrow. If the final amount was only 6.50 TNZO, the agent would receive a 3.50 TNZO refund.

Dispute Resolution

What if the provider tries to cheat by submitting an old state update (lower nonce, lower amount) during channel close?

# Escrow contract logic (simplified):
function closeChannel(
  bytes32 channelId,
  uint256 amount,
  uint256 nonce,
  bytes signature
) public {
  Channel storage channel = channels[channelId];

  // Verify signature is from payee
  require(verify(channelId, amount, nonce, signature, channel.payee));

  // Reject if nonce is lower than previously submitted nonce
  require(nonce > channel.lastNonce, "Old state submitted");

  // If agent has a higher nonce, they can challenge within dispute period
  if (block.timestamp < channel.closeRequestedAt + DISPUTE_PERIOD) {
    // Agent submits their highest nonce update
    // Contract accepts whichever has higher nonce
  }

  // Settle based on highest nonce update
  transfer(channel.payee, amount);
  transfer(channel.payer, channel.lockedAmount - amount);
}

The agent has a dispute period (typically 24 hours) to submit a higher-nonce update if the provider tries to cheat. Since the agent stores all signed updates, it can always prove the true final state.

Complete Architecture

Here's how all the pieces fit together:

┌──────────────────────────────────────────────────────────────┐
                      HUMAN GUARDIAN                          
  DID: did:tenzro:human:550e8400...440001                     
  Controls: 1 machine identity                                
└────────────────────────┬─────────────────────────────────────┘
                         
                          creates (DelegationScope)
                         
┌──────────────────────────────────────────────────────────────┐
                    AI AGENT (Machine Identity)               
  DID: did:tenzro:machine:550e8400...440001:a1b2c3d4          
  Delegation: $10/tx, $100/day, MPP+x402, Tenzro chain        
  Wallet: 0x742d35Cc... (MPC 2-of-3, 100 TNZO)                
└────────────────────────┬─────────────────────────────────────┘
                         
                          (1) Discovers services via A2A
                         
┌──────────────────────────────────────────────────────────────┐
              TENZRO NETWORK A2A AGENT CARD                   
  Skills: wallet, identity, inference, settlement, verify     
  Payments: MPP, x402 (TNZO, USDC)                            
└────────────────────────┬─────────────────────────────────────┘
                         
                          (2) Requests inference
                         
┌──────────────────────────────────────────────────────────────┐
                   INFERENCE PROVIDER                         
  HTTP 402  MPP Challenge (2.50 TNZO, session_id)            
└────────────────────────┬─────────────────────────────────────┘
                         
                          (3) Agent creates MPP credential
                         
┌──────────────────────────────────────────────────────────────┐
                    MPP SESSION                               
  Session ID: mpp_sess_a1b2c3d4                               
  Model: gpt-4 (0.05 TNZO/token)                              
  Vouchers: [...48 signed updates...]                         
  Final cost: 2.40 TNZO                                       
└────────────────────────┬─────────────────────────────────────┘
                         
                          (4) Settlement
                         
┌──────────────────────────────────────────────────────────────┐
                  TENZRO BLOCKCHAIN                           
  Tx: 0x7g8h9i0j... (Agent  Provider: 2.40 TNZO)             
  Receipt: rcpt_xyz123 (cryptographically signed)             
  Agent balance: 97.60 TNZO (100 - 2.40)                      
└──────────────────────────────────────────────────────────────┘

Production Considerations

Key Storage

In this tutorial, we displayed private keys in JSON responses for learning purposes. In production:

Delegation Renewal

After the 90-day delegation expires, the agent must request renewal from its guardian. This forces periodic review of agent behavior:

# Agent attempts payment after expiration
{
  "error": "DelegationExpired",
  "message": "Delegation expired at 2026-06-24T00:00:00Z",
  "renewal_required": true,
  "guardian_did": "did:tenzro:human:550e8400...440001"
}

# Guardian reviews agent spending history, then renews:
curl -X POST https://rpc.tenzro.network \
  -d '{
    "method": "tenzro_renewDelegation",
    "params": [{
      "machine_did": "did:tenzro:machine:550e8400...440001:a1b2c3d4",
      "new_scope": { "expires_at": "2026-09-24T00:00:00Z" }
    }]
  }'

Monitoring and Alerts

Guardians should monitor their controlled agents in real-time:

Multi-Chain Operations

This tutorial used Tenzro chain only. To enable Ethereum or Solana payments, update allowed_chains:

"delegation_scope": {
  "allowed_chains": ["tenzro", "ethereum", "base", "solana"],
  "allowed_payment_protocols": ["Mpp", "X402", "Direct"]
}

# Agent can now pay for Ethereum mainnet API calls via x402 (USDC on Base)
# or use Solana for high-frequency, low-value transactions

Next Steps

You've built a complete AI agent with identity, wallet, and payment capabilities. Here's what to explore next:

Build More with Tenzro

Ready to deploy your agent to production? Explore our documentation and SDKs.