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

How to add payments to a LangChain agent

8 min read·Last updated May 15, 2026

Install the Blockchain0x SDK, register a paid tool that wraps any LangChain Tool with a price and a reason, and let the agent call it. The runtime returns a 402 with a hosted URL on first call; settlement happens in USDC on Base; the tool runs once the wallet pays. Webhook confirms; spend policy bounds risk.

What you will build

A LangChain agent that pays for the tools it uses, settled in USDC on Base. The agent's planner does not know anything about payments - it sees a normal LangChain Tool, calls it, and gets results. Underneath, every call settles through the agent's Blockchain0x wallet using the x402 protocol. You set a spend policy once; the wallet enforces it on every payment intent before settlement.

This guide is the LangChain-specific version of the same architecture documented in the LangChain integration page. If you have already built a LangChain agent and want to wire payments without rewriting it, you are in the right place. The total integration is roughly 30 lines of code.

Prerequisites

Before you start, have these ready:

  • A working LangChain agent in TypeScript or Python (any executor: AgentExecutor, create_tool_calling_agent, LangGraph, etc.).
  • A Blockchain0x account with one agent profile created. The add-payments-to-agent guide covers this in five minutes.
  • An API key (use sk_test_ for this walkthrough; switch to sk_live_ when you ship).
  • Node 20+ or Python 3.11+, matching your LangChain runtime.
  • A clear sense of which tool you want the agent to pay for. Common choices: premium data APIs, paid MCP tools, third-party LLM endpoints with their own paywalls.

Install the SDK

Two packages. The first is the core SDK; the second is the LangChain adapter that gives you the requirePayment Tool wrapper.

BASH
# Node / TypeScript
npm install @blockchain0x/sdk @blockchain0x/langchain

# Python
pip install blockchain0x blockchain0x-langchain

Set two environment variables anywhere your LangChain runtime reads env from:

BASH
BLOCKCHAIN0X_API_KEY=sk_test_01J9...
BLOCKCHAIN0X_AGENT_ID=agt_01J9...

Wrap a tool with x402

The pattern is to take an existing LangChain Tool definition and wrap its handler with requirePayment. Everything else - the schema, the description, the way the agent's planner reasons about the tool - stays unchanged.

TypeScript:

TYPESCRIPT
import { DynamicStructuredTool } from "@langchain/core/tools";
import { requirePayment } from "@blockchain0x/langchain";
import { z } from "zod";

const realtimeQuote = new DynamicStructuredTool({
  name: "get_quote_realtime",
  description: "Fetch a real-time quote for a stock ticker.",
  schema: z.object({ ticker: z.string() }),
  func: requirePayment(
    {
      agentId: process.env.BLOCKCHAIN0X_AGENT_ID!,
      apiKey: process.env.BLOCKCHAIN0X_API_KEY!,
      priceUsdc: "0.005",
      reason: "Real-time quote",
    },
    async ({ ticker }, { receipt }) => {
      const quote = await fetchLiveQuote(ticker);
      return JSON.stringify(quote);
    },
  ),
});

Python:

PYTHON
from langchain.tools import StructuredTool
from blockchain0x_langchain import require_payment
from pydantic import BaseModel

class QuoteArgs(BaseModel):
    ticker: str

@require_payment(
    agent_id=os.environ["BLOCKCHAIN0X_AGENT_ID"],
    api_key=os.environ["BLOCKCHAIN0X_API_KEY"],
    price_usdc="0.005",
    reason="Real-time quote",
)
async def get_quote_realtime(ticker: str, receipt):
    quote = await fetch_live_quote(ticker)
    return json.dumps(quote)

realtime_quote = StructuredTool.from_function(
    name="get_quote_realtime",
    description="Fetch a real-time quote for a stock ticker.",
    args_schema=QuoteArgs,
    coroutine=get_quote_realtime,
)

The wrapper does three things on every call: it asks Blockchain0x whether the agent has already paid for this tool in the current receipt window, returns a 402-shaped error to the agent if not (which the wallet runtime handles by settling), and invokes the underlying function with the receipt attached once payment lands.

Connect the tool to your LangChain agent

The wrapped tool plugs into your existing LangChain agent the same way an unpaid tool would. Nothing in the agent code changes.

TYPESCRIPT
import { createToolCallingAgent, AgentExecutor } from "langchain/agents";
import { ChatOpenAI } from "@langchain/openai";

const llm = new ChatOpenAI({ model: "gpt-4o" });
const agent = await createToolCallingAgent({
  llm,
  tools: [realtimeQuote, /* other tools */],
  prompt: yourPrompt,
});

const executor = new AgentExecutor({ agent, tools: [realtimeQuote] });
await executor.invoke({ input: "What is the live quote on TSLA?" });

The first time the agent calls get_quote_realtime, the wallet pays $0.005 and the Tool returns the quote. Subsequent calls within the receipt-cache window return immediately without re-settling. The agent's planner never has to know.

Handle the confirmation webhook

Webhooks are only needed if your paid tool produces work asynchronously (a slow API, a streaming response, a background job). For the synchronous case above, you can skip this section.

If you do need async, point your webhook endpoint at the Blockchain0x dashboard and verify the signature on every event. The full pattern is documented in the handle-agent-payments-with-webhooks guide; the LangChain-specific concern is to make sure the webhook handler can map the payment_request_id in the event payload back to whatever in-progress work it triggered.

A reasonable shape:

TYPESCRIPT
import crypto from "node:crypto";
import express from "express";

const SIGNING_SECRET = process.env.BLOCKCHAIN0X_SIGNING_SECRET!;

app.post(
  "/webhooks/payment",
  express.raw({ type: "application/json" }),
  (req, res) => {
    const sig = req.header("X-Blockchain0x-Signature") ?? "";
    const expected = crypto.createHmac("sha256", SIGNING_SECRET).update(req.body).digest("hex");
    if (!crypto.timingSafeEqual(Buffer.from(sig, "hex"), Buffer.from(expected, "hex"))) {
      return res.status(401).send("Invalid signature");
    }
    const event = JSON.parse(req.body.toString());
    if (event.type === "payment.confirmed") {
      void deliverAsyncResult(event.data.payment_request_id);
    }
    res.status(200).send("ok");
  },
);

Add a spend policy

Once your LangChain agent can pay, give it bounds. The policy lives in the wallet's API layer, not the agent's prompt, which is the only place it survives prompt injection.

TYPESCRIPT
import { Blockchain0x } from "@blockchain0x/sdk";

const client = new Blockchain0x({ apiKey: process.env.BLOCKCHAIN0X_API_KEY! });

await client.agents.updateSpendPolicy(process.env.BLOCKCHAIN0X_AGENT_ID!, {
  daily_cap_usdc: "20.00",
  per_payment_cap_usdc: "0.50",
  // Optional, if your agent only pays a known set of merchants:
  allowed_counterparties: [
    "0xPaidMcpServerA...",
    "0xPaidDataApiB...",
  ],
});

The wallet enforces this on every payment intent before settlement. A LangChain tool call that would exceed the daily cap fails with a policy_violation error before any money moves. Tune the numbers based on actual usage data; the agent-spend-controls guide covers the configuration in more depth.

Test on Base Sepolia

Before you flip to sk_live_ keys, run the whole flow against the sandbox. Test keys mint test USDC, hit Base Sepolia for settlement, and have the same response shapes as live keys.

BASH
# Fund the agent's test wallet with $100 of test USDC.
curl -X POST https://api.blockchain0x.com/v1/sandbox/fund-agent \
  -H "Authorization: Bearer sk_test_01J9..." \
  -H "Content-Type: application/json" \
  -d '{"agent_id":"agt_01J9...","amount_usdc":"100.00"}'

Three scenarios to exercise: a happy-path tool call that settles and returns, a call that exceeds the spend policy and rejects, and a webhook retry (force a 500 from your handler the first time and confirm idempotency on the second). When all three pass on test keys, swap the key and ship.

The test-agent-payments-without-real-money guide documents the full sandbox workflow if you need more depth. Pricing on production is documented at /pricing/ - the Free tier covers everything in this walkthrough; the Pro tier unlocks per-agent spend policies, custom branding on the public agent page, and 2% transaction fees instead of 5%.

Common pitfalls

Five mistakes that bite teams in their first week of LangChain-with-payments. Each one has cost at least one team an afternoon of debugging.

Wrapping the agent instead of the tool. It is tempting to wrap the AgentExecutor with requirePayment to charge once per agent invocation. Do not. The agent's planner may decide to make many tool calls per invocation, and you lose granularity. Wrap the tool's func so the price tracks the underlying cost, and let the planner's spend decisions be implicit.

Using the same receipt window for fast and slow tools. The default receipt cache TTL of one hour is a reasonable compromise for most tools, but it is wrong for both ends of the spectrum. A real-time quote tool should have a 60-second TTL so callers do not get stale data for free. A reference-lookup tool that changes daily can run a 24-hour TTL to avoid charging the same caller for the same answer multiple times. Match the TTL to the data's freshness, not the default.

Forgetting to handle the policy_violation error. When the spend policy rejects a payment, your wrapped tool's func is not invoked - instead, the wrapper throws (in TypeScript) or raises (in Python) a PolicyViolationError. LangChain's tool executor will pass that up to the agent's planner. If your prompt does not tell the planner what to do with the error, the agent may loop trying the same tool with the same args, hitting the policy each time. Add a system-prompt clause along the lines of "if a tool returns a policy_violation error, do not retry it without different arguments".

Mixing test and live keys in dev. A LangChain agent that boots with sk_test_ against your local environment but hits production webhook URLs is the most common configuration bug in the first week. Always check the key prefix matches the environment at boot, and refuse to start if they disagree.

TYPESCRIPT
const apiKey = process.env.BLOCKCHAIN0X_API_KEY!;
const env = process.env.NODE_ENV;
if (env === "production" && apiKey.startsWith("sk_test_")) {
  throw new Error("Test key in production - aborting boot.");
}
if (env !== "production" && apiKey.startsWith("sk_live_")) {
  throw new Error("Live key in non-production - aborting boot.");
}

Skipping the verification badges on the agent's profile. The wallet works without them, but the agent's public profile page (where counterparties decide whether to accept payments from your agent) is much less credible without GitHub + domain verification. The badges take five minutes each via the verify-agent-identity guide and dramatically improve how merchants treat your agent on first contact.

What to ship today

If you take one thing from this guide, take this: the integration cost of adding payments to a LangChain agent is one wrapper around your tool's func. Everything else is configuration. The 30-line version above is the entire integration; everything after is hardening (webhooks, policy tuning, identity verification) that you can layer in as your agent grows.

The next step depends on what your agent does. If your LangChain agent is a paid tool itself (it earns revenue for solving problems for others), wire monetization with the monetize-mcp-server playbook. If it just consumes paid services, the spend policy in the section above is the highest-leverage thing you can do this week.

FAQ

Frequently asked questions.

Does this work with LangGraph?

Yes. LangGraph is the multi-agent layer above LangChain; the same paid-tool pattern works because each node in a LangGraph still calls Tools. Register the wrapped tool with the LangGraph node that should use it, set the spend policy on the workspace, and the rest of the flow is identical.

Do I need to hold ETH for gas?

No. Blockchain0x wallets on Base use sponsored gas - the wallet provider pays the chain fee in ETH and either eats the cost or settles a small USDC equivalent against your balance. Your LangChain agent only ever holds and pays in USDC.

What happens if the agent's daily cap is exceeded mid-call?

The 402 response is settled by the wallet API, which enforces the spend policy before settling. If the call would exceed the cap, the wallet returns a policy_violation error rather than paying. The Tool wrapper bubbles the error up; the agent's planner sees it and can either skip or escalate, depending on how you instructed it.

How is this different from giving the agent an OpenAI API key?

An OpenAI key authorizes the agent against one provider. A Blockchain0x wallet authorizes the agent to pay any merchant that accepts USDC - paid MCP tools, other agents, third-party APIs that return 402. The wallet is a primitive; the API key is a single integration. For multi-merchant agent workloads, the wallet is dramatically more powerful.

Can I gate one of my own LangChain tools and charge other agents to use it?

Yes - that is the reverse direction of this guide. Use the same `requirePayment` helper to wrap your tool handler, give it a price, and any external agent (LangChain or otherwise) that hits your endpoint will get a 402. See the monetize-mcp-server guide for the canonical version of that flow; the same wrapper works for any HTTP handler, not just MCP.

Is the webhook required?

Only for asynchronous fulfillment. If your Tool returns its result synchronously when the wallet's settle call succeeds, you can ignore webhooks entirely. Webhooks become important when the tool kicks off work that finishes seconds or minutes later (e.g. a long-running data pull), where you want to deliver the result after confirmation rather than block the call.

Create your free agent wallet in 5 minutes.

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