Skip to main content

Overview

Arcana implements a two-tier payment system: users pay the backend upfront for queries, and the backend pays individual agents per-call using x402. This page walks through the complete payment flow.
Currency: All payments use USDC on Base Sepolia testnet.

Payment Architecture

Two-Tier Payment Model

Step-by-Step Flow

1. User Initiates Query

The user types a question in the chat interface:
"What's the current price of Bitcoin and best yield opportunities for BTC?"

2. Frontend Initiates Payment

1

Wallet Connection

Frontend checks that user has:
  • Connected wallet (MetaMask, Coinbase Wallet, etc.)
  • Sufficient USDC balance ($0.03 minimum)
  • Connected to Base Sepolia network
2

Payment Transaction

Frontend constructs a USDC transfer transaction:
const tx = await usdcContract.transfer(
  backendWalletAddress,
  parseUnits('0.03', 6) // 0.03 USDC (6 decimals)
);
3

User Signs

User signs the transaction in their wallet and submits to blockchain
4

Wait for Confirmation

Frontend polls for transaction confirmation (typically 2-5 seconds on Base)
import { parseUnits } from 'viem';
import { useWriteContract, useWaitForTransactionReceipt } from 'wagmi';

const USDC_ADDRESS = '0x036CbD53842c5426634e7929541eC2318f3dCF7e';
const BACKEND_WALLET = '0x...';
const QUERY_PRICE = parseUnits('0.03', 6); // 0.03 USDC

// 1. Submit payment transaction
const { data: txHash, writeContract } = useWriteContract();

await writeContract({
  address: USDC_ADDRESS,
  abi: USDC_ABI,
  functionName: 'transfer',
  args: [BACKEND_WALLET, QUERY_PRICE],
});

// 2. Wait for confirmation
const { data: receipt } = useWaitForTransactionReceipt({
  hash: txHash,
});

// 3. Send query to backend
const response = await fetch('/api/query', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    query: userQuery,
    txHash: txHash,
    wallet: userAddress,
  }),
});

3. Backend Verifies Payment

Before processing any query, the backend verifies the payment transaction:
1

Fetch Transaction Receipt

const receipt = await publicClient.getTransactionReceipt({
  hash: txHash
});
2

Check Status

if (receipt.status !== 'success') {
  throw new Error('Transaction failed');
}
3

Verify Amount

Parse transfer logs to confirm amount >= $0.03 USDC
4

Verify Recipient

Ensure payment was sent to backend wallet address
5

Check Replay

Verify transaction hasn’t been used for a previous query
If payment verification fails, the backend returns an error immediately without processing the query.

4. AI Orchestration & Agent Selection

Once payment is verified, the backend uses Gemini to analyze the query:
const geminiResponse = await gemini.generateContent({
  contents: [{
    role: 'user',
    parts: [{
      text: `Analyze this crypto query and determine which agents to call:
      
      Query: "${userQuery}"
      
      Available agents:
      - oracle: Token prices and market data
      - scout: On-chain analytics, gas prices, wallet analysis
      - news: Latest crypto news and trending topics
      - yield: DeFi yield opportunities
      - tokenomics: Token supply, vesting, unlock schedules
      - nft: NFT collection analytics
      - perp: Perpetual futures market data
      
      Respond with JSON: { "agents": ["agent1", "agent2"], "reasoning": "..." }`
    }]
  }]
});

5. Backend Calls Agents via x402

For each selected agent, the backend executes a paid x402 call:
1

Policy Check

Before calling, verify:
  • Agent is not frozen
  • Endpoint is allowlisted
  • Spend limits not exceeded
  • Circuit breaker is closed
2

Preflight Request

Call agent endpoint to get payment requirement:
GET /api/x402/oracle/price?symbol=BTC

402 Payment Required
PAYMENT-REQUIRED: eyJhY2NlcHRzIjpbeyJuZXR3b3JrIjoi...
3

Submit Payment

Pinion runtime submits on-chain payment using CDP wallet:
const paymentTx = await cdpWallet.transfer({
  to: agentWallet,
  amount: '0.01',
  token: 'USDC'
});
4

Retry with Proof

Retry the request with payment proof:
GET /api/x402/oracle/price?symbol=BTC
X-Payment: {payment-proof}

200 OK
{ "symbol": "BTC", "price": 97234.50 }
All agent payments happen in parallel when possible to minimize latency.

6. Response Synthesis

The backend collects agent responses and uses Gemini to synthesize a coherent answer:
const synthesis = await gemini.generateContent({
  contents: [{
    role: 'user',
    parts: [{
      text: `Original query: "${userQuery}"
      
      Agent responses:
      
      Oracle: ${JSON.stringify(oracleResponse)}
      Yield: ${JSON.stringify(yieldResponse)}
      
      Synthesize a natural language response that answers the user's question.`
    }]
  }]
});

7. Frontend Displays Response

The frontend receives the complete response with:
{
  "answer": "Bitcoin is currently trading at $97,234.50 (+2.34% in 24h). For BTC yield opportunities...",
  "agentsCalled": [
    { "agent": "oracle", "cost": "$0.01", "latency": "245ms" },
    { "agent": "yield", "cost": "$0.01", "latency": "892ms" }
  ],
  "totalCost": "$0.02",
  "userPayment": {
    "amount": "$0.03",
    "txHash": "0x...",
    "explorerUrl": "https://sepolia.basescan.org/tx/0x..."
  }
}

Payment Receipts

All payments are logged to Supabase for audit and analytics:
CREATE TABLE payment_receipts (
  id UUID PRIMARY KEY,
  tx_hash TEXT UNIQUE NOT NULL,
  wallet TEXT NOT NULL,
  amount TEXT NOT NULL,
  session_id UUID,
  query TEXT,
  agents_called TEXT[],
  created_at TIMESTAMP DEFAULT NOW()
);

Error Handling

Causes:
  • Transaction not confirmed
  • Insufficient payment amount
  • Wrong recipient address
  • Transaction already used
Response:
{
  "error": "Payment verification failed",
  "reason": "Insufficient payment: sent 0.02 USDC, required 0.03 USDC",
  "txHash": "0x..."
}
Causes:
  • Agent offline or unresponsive
  • Payment failed or rejected
  • Circuit breaker open
  • Policy violation
Handling:
  • Try alternative provider if available
  • Return partial response without failed agent
  • Inform user which agents failed
Example:
{
  "answer": "Bitcoin is currently at $97,234.50. (Yield data unavailable)",
  "warnings": ["Yield agent is temporarily unavailable"]
}
Cause: Backend CDP wallets run out of USDC for agent paymentsResponse:
{
  "error": "Service temporarily unavailable",
  "reason": "Insufficient backend balance for agent calls",
  "retryAfter": 300
}
Resolution: Admin must fund backend wallets via treasury endpoints
Cause: User or backend exceeds rate limitsResponse:
{
  "error": "Rate limit exceeded",
  "retryAfter": 60,
  "limit": "10 requests per minute"
}

Cost Breakdown

Here’s a typical cost breakdown for a user query:

Example: Multi-Agent Query

Query: “What’s the price of ETH and best yield opportunities?”
PaymentRecipientAmountPurpose
User → BackendBackend Wallet$0.03Query processing, AI orchestration
Backend → OracleOracle Agent$0.01ETH price lookup
Backend → YieldYield Agent$0.01Yield opportunities
Total$0.05Complete query cost
Backend typically spends 0.010.01-0.02 per query on agent calls, keeping the difference to cover infrastructure and AI costs.

Treasury Management

The backend provides admin endpoints for managing wallet balances:
GET /treasury/balance/:address

{
  "address": "0x...",
  "balances": {
    "USDC": "15.42",
    "ETH": "0.05"
  }
}
Treasury endpoints require admin authentication via x-admin-key header.

Monitoring & Analytics

The dashboard provides real-time visibility into payment flows:

User Payments

  • Total revenue from user queries
  • Payment success rate
  • Failed payment reasons
  • Top paying users

Agent Costs

  • Spend per agent
  • Agent call frequency
  • Cost per query breakdown
  • Margin analysis

Settlement Tracking

  • Pending settlements
  • Confirmed payments
  • Facilitator status
  • Dispute resolution

Wallet Health

  • Backend balance alerts
  • Agent wallet balances
  • Funding recommendations
  • Transaction history

Next Steps

x402 Protocol

Deep dive into the x402 protocol specification

Agent Marketplace

Explore the 7 specialized agents

Architecture

Review the complete system architecture

Build docs developers (and LLMs) love