Documentation
Everything you need to publish tools or build an agent that pays per call.
For Tool Providers
1. Connect your wallet
Go to /dashboard and connect your Solana wallet (Phantom, Solflare). Your tools are tied to your wallet address — only you can manage them.
2. Create a tool
Give it a name, point it to your API URL, set a price, and define the expected request/response format. ZAP wraps your API with x402 payment verification automatically.
// Your API stays exactly as-is. Example: // GET https://api.yourapp.com/data // ZAP creates a paid endpoint: // POST /api/tool/your_tool_name // Agents call your tool through ZAP: // 1. Agent signs payment intent (Ed25519) // 2. ZAP verifies signature + on-chain session // 3. ZAP proxies request to your API // 4. ZAP records the call + amount owed to you // 5. You get paid in USDC at settlement
3. Get paid
Each call is tracked in a Ledger PDA on Solana, specific to your wallet. At settlement, USDC is transferred from the agent's escrow directly to your wallet. No intermediary.
4. Monitor
Your dashboard shows every call, earnings per tool, and agent activity — all filtered to your wallet. Other providers can't see your data.
For Agent Developers
1. Discover tools
Browse /explore or query the API:
GET /api/public/tools GET /api/public/tools?q=price GET /api/public/tools?tier=1
2. Open a session (3 on-chain txs)
The agent deposits USDC into an escrow and delegates the session to the Ephemeral Rollup. This is the only time the agent touches the blockchain.
// 1. init_session — deposits USDC into escrow PDA
await program.methods.initSession(new BN(500000)) // $0.50 USDC
.accounts({ agent: wallet.publicKey })
.rpc();
// 2. delegate_session — hand off to Ephemeral Rollup
await program.methods.delegateSession()
.accounts({ payer: wallet.publicKey, pda: sessionPDA })
.rpc();
// 3. deactivate_session — when done (can be called later)
await program.methods.deactivateSession()
.accounts({ agent: wallet.publicKey })
.rpc();3. Call tools (no on-chain tx)
For each tool call, sign a payment intent with Ed25519. No transaction, no gas. The server verifies instantly and returns the result.
import nacl from "tweetnacl";
import bs58 from "bs58";
const intent = {
session: "SESSION_PDA_ADDRESS",
nonce: 1, // increment per call
amount: "1000", // tool price in USDC base units
resource: "get_price", // tool name
timestamp: Math.floor(Date.now() / 1000),
};
const message = Buffer.from(JSON.stringify(intent));
const signature = nacl.sign.detached(message, keypair.secretKey);
const header = Buffer.from(JSON.stringify({
intent,
signature: Buffer.from(signature).toString("base64"),
publicKey: bs58.encode(keypair.publicKey.toBytes()),
})).toString("base64");
const res = await fetch("/api/tool/get_price", {
method: "POST",
headers: {
"Content-Type": "application/json",
"payment-signature": header,
},
body: JSON.stringify({ mint: "So111...112" }),
});
const { result, meta } = await res.json();
// result = { found: true, priceUsd: 172.50 }
// meta.payment = { verified: true, onChain: true }4. Call tools from different providers
One session, multiple providers. Each provider gets their own Ledger PDA tracking what they're owed. The agent doesn't need to know or care.
// Same session, different providers, different prices
await callTool("search_solana_token", { symbol: "SOL" }, "1000"); // Provider A
await callTool("chuck_norris", {}, "5000"); // Provider B
await callTool("fear_greed_index", {}, "1000"); // Provider C
await callTool("wallet_scan", { address: "..." }, "10000"); // Provider A
// On-chain ledgers created automatically:
// Ledger [session, Provider A] → $0.011 owed (2 calls)
// Ledger [session, Provider B] → $0.005 owed (1 call)
// Ledger [session, Provider C] → $0.001 owed (1 call)5. What if the tool returns 402?
Missing or invalid payment signature returns 402 with the price info:
// 402 response:
{
"error": "Payment required",
"x402Version": 1,
"price": "1000",
"priceLabel": "$0.001"
}How Settlement Works
ZAP uses Solana Ephemeral Rollups (MagicBlock) and a per-provider Ledger system for multi-provider settlement: