Skip to main content
HomeLanding pagesHow to add payments to a LlamaIndex agent
LANDING PAGE

How to add payments to a LlamaIndex agent

7 min read·Last updated June 2, 2026

LlamaIndex agents in Python pay through a small local Node proxy built on createX402Client from @blockchain0x/x402, because the x402 client ships for Node. Wrap a FunctionTool that calls the proxy; when the upstream returns HTTP 402 the proxy settles in USDC on Base and returns the result. Give each agent its own wallet and set spend limits in the dashboard.

What you will build

A LlamaIndex agent that pays for the tools and data it calls, settled in USDC on Base. The agent loop does not change. You add a FunctionTool that calls a small local proxy, and the proxy handles payment. To the agent it is an ordinary tool returning a result; underneath, a paid call settles through the agent's wallet.

The honest constraint first: the x402 payment client ships for Node, and LlamaIndex agents are usually Python. So the shipped path is a tiny Node proxy that holds the wallet and answers 402 Payment Required, with your FunctionTool calling it over localhost. This is the same pattern the CrewAI and AutoGen guides use. The LlamaIndex integration page is the broader reference, and the payment API product page covers the wider surface.

Why a Node proxy

A sentence on why the proxy is the right move, not a workaround. The package that answers a 402 and settles in USDC, @blockchain0x/x402, is Node-only today. Inventing a Python import that does not exist would just produce code that fails to install. The proxy is a real Node process doing the real x402 work, reachable from Python over a localhost call your agent already knows how to make. It keeps every payment identifier on the verified surface and costs one extra process per wallet. If you happen to run LlamaIndex.TS rather than the Python library, you do not need the proxy at all; you wrap createX402Client directly in a TS tool, the way the LangChain guide does.

Prerequisites

  • A Blockchain0x account with one agent created, so it has a wallet.
  • A sk_test_ API key for this walkthrough.
  • Node 18+ for the proxy (the SDK targets >=18) and Python 3.9+ for LlamaIndex.
BASH
export B0X_API_KEY=sk_test_...   # sk_test_ -> Base Sepolia

Run the x402 proxy

The only Node you write. It builds a fetch that answers 402s and exposes one route your tool can post a URL to.

JAVASCRIPT
// pay-proxy.mjs  ->  npm i @blockchain0x/node @blockchain0x/x402 && node pay-proxy.mjs
import http from "node:http";
import { createClient } from "@blockchain0x/node";
import { createX402Client } from "@blockchain0x/x402/client";

const sdk = createClient({ apiKey: process.env.B0X_API_KEY }); // sk_test_ pins it to Base Sepolia
const fetchWithPay = createX402Client({ sdk });

http
  .createServer(async (req, res) => {
    const chunks = [];
    for await (const c of req) chunks.push(c);
    const { url } = JSON.parse(Buffer.concat(chunks).toString() || "{}");
    try {
      const upstream = await fetchWithPay(url); // settles the 402 in USDC, retries
      res.writeHead(upstream.status, { "content-type": upstream.headers.get("content-type") ?? "text/plain" });
      res.end(await upstream.text());
    } catch (err) {
      res.writeHead(502).end(String(err));
    }
  })
  .listen(8787, () => console.log("pay-proxy on :8787"));

Start it next to your agent: node pay-proxy.mjs. One proxy per agent wallet, each on its own port with its own B0X_API_KEY.

Wrap it in a FunctionTool

In LlamaIndex, a tool is a Python function wrapped as a FunctionTool. Write a function that calls the proxy and hand it to your agent.

PYTHON
import requests
from llama_index.core.tools import FunctionTool
from llama_index.core.agent.workflow import FunctionAgent

def get_quote_realtime(ticker: str) -> str:
    """Fetch a real-time quote for a stock ticker."""
    upstream = f"https://quotes.example.com/v1/quote?ticker={ticker}"
    res = requests.post("http://127.0.0.1:8787", json={"url": upstream}, timeout=30)
    return res.text if res.status_code == 200 else f"Lookup failed: {res.status_code}"

quote_tool = FunctionTool.from_defaults(fn=get_quote_realtime)
agent = FunctionAgent(tools=[quote_tool], llm=your_llm, system_prompt="You are an equity research analyst.")

The agent calls get_quote_realtime like any other tool. The proxy settles the upstream 402 in USDC, the result comes back, and the agent folds it into its reasoning. It never sees the payment.

Pay for retrieval, not just tools

LlamaIndex is built around retrieval, so the most LlamaIndex-specific move is to pay for data, not only for tool calls. Any retrieval that hits a paid source can route through the proxy.

If you query a premium data API as part of building context, wrap that call in a tool or a custom retriever whose outbound request goes through the proxy. The agent then pays per retrieval, settling in USDC, exactly as it would for any other paid call. This turns a paid corpus into something an agent can draw on autonomously: it pulls the data it needs, pays for what it pulls, and the spend limit on its wallet caps the total. A retrieval-heavy agent with no limit can run up cost fast, so this is precisely where the wallet's per-period allowance earns its place, by bounding how much context the agent can buy in a window.

Cache paid results to control cost

When an agent pays per retrieval, the cheapest payment is the one you do not repeat. If the same query comes up twice in a session, paying twice for the identical answer is waste, and a retrieval-heavy agent repeats queries more than you would guess. So cache results on the Python side, keyed by the query, before the call ever reaches the proxy.

PYTHON
_cache: dict[str, str] = {}

def get_quote_cached(ticker: str) -> str:
    """Fetch a quote, reusing a recent paid result if we have one."""
    if ticker in _cache:
        return _cache[ticker]
    result = get_quote_realtime(ticker)  # the paid call through the proxy
    _cache[ticker] = result
    return result

Match the cache lifetime to how fresh the data must be: a real-time quote wants a short window measured in seconds, a reference lookup that changes daily can cache for hours. This is a normal application cache, not a Blockchain0x feature, which is the point: payment happens only on a miss, so your wallet spend tracks genuinely new information rather than repeated questions. Pair it with the per-period allowance below and you have both a soft control (do not re-pay) and a hard one (cannot overspend).

Set spend limits and test

Set the limit in the dashboard, where the wallet enforces it before any payment, and read it back to confirm:

PYTHON
import os, requests

res = requests.get(
    f"https://api.blockchain0x.com/v1/agents/{os.environ['AGENT_ID']}/spend-permissions",
    headers={"Authorization": f"Bearer {os.environ['B0X_API_KEY']}"},
    timeout=30,
)
permissions = res.json()  # per_tx_wei, allowance_wei, period_seconds, ...

Run the loop on Base Sepolia first with a sk_test_ key: fund the agent's wallet with test USDC from a public faucet, start the proxy, and watch a paid tool call settle. Exercise a refused payment by setting a tight per_tx_wei and confirming an over-limit call returns a non-2xx the tool handles. When both paths behave, swap to a sk_live_ key for Base mainnet.

Common pitfalls

Three traps.

Exposing the proxy beyond localhost. It holds a wallet key and pays whatever URL it is handed. Bind it to 127.0.0.1 and treat it like the credential it is.

Unbounded retrieval spend. A retrieval-heavy agent paying per query can spend quickly. Set a per-period allowance that reflects how much context buying you are willing to fund in a window.

Putting the budget in the system prompt. A budget in the prompt is a suggestion a crafted input can talk past. The dashboard spend limit is the real boundary.

What to ship today

Start one pay-proxy.mjs with a sk_test_ key, wrap one FunctionTool that calls it, and watch a paid call settle on Base Sepolia. Set a dashboard spend limit before you switch to a sk_live_ key. The CrewAI and AutoGen versions of this pattern are at how-to-add-payments-to-crewai-agent and how-to-add-payments-to-autogen-agent. Pricing is on the pricing page.

FAQ

Frequently asked questions.

Why a Node proxy instead of a Python package?

The x402 payment client ships for Node, and LlamaIndex agents are usually Python. Rather than invent a Python package that does not exist, you run one small Node process that holds the wallet and answers 402s, and your FunctionTool calls it over localhost. It is about thirty lines and one process per agent wallet. If you run LlamaIndex.TS, you can skip the proxy and wrap createX402Client directly.

Does this work with the LlamaIndex agent types?

Yes. FunctionAgent, ReActAgent, and AgentWorkflow all call tools the same way, so a FunctionTool that calls the proxy plugs into any of them unchanged. The payment lives in the tool, not in the agent loop, so your choice of agent type does not matter to it.

Can a paid tool feed a RAG pipeline?

Yes, and it is a common shape. A tool that calls a paid data API through the proxy returns text the agent can fold into its context the same as any retrieval result. You can also gate a custom retriever or query engine by routing its outbound HTTP through the proxy, so retrieval against a paid source settles per call.

Which networks and token does settlement use?

USDC, 6 decimals, on Base. A sk_test_ key settles on Base Sepolia (eip155:84532); a sk_live_ key settles on Base mainnet (eip155:8453). The SDK reads the network from the key prefix. The only payment scheme today is exact-usdc.

How do I bound what the agent spends?

Set the limit in the dashboard. The wallet enforces a per-transaction cap and a per-period allowance before settlement, so a call over either is refused before any USDC moves. Read the active limits with GET /v1/agents/:agentId/spend-permissions to confirm what is enforced.

Create your free agent wallet in 5 minutes.

First payment confirmed in under ten minutes. Free to start.