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 June 2, 2026

Create a Blockchain0x client with createClient, wrap createX402Client in a LangChain DynamicStructuredTool, and point it at a paid API. When the API answers HTTP 402, the x402 client builds the X-Payment header and settles in USDC on Base. Verify confirmations with webhooks.verify. Set spend limits in the dashboard so the wallet enforces them before any payment.

What you will build

A LangChain agent that pays for the services it calls, settled in USDC on Base. The agent's planner never sees the payment. It calls a normal tool, the tool fetches a paid API, and when that API answers 402 Payment Required the x402 client settles the bill and retries. You wire this once. After that, every paid call the agent makes flows through its Blockchain0x wallet, bounded by a spend limit you set in the dashboard.

This is the LangChain-specific version of the architecture on the LangChain integration page. If you already have an agent and just want it to pay, you are in the right place. The core is about fifteen lines.

There is no Blockchain0x LangChain package. You do not need one. The honest pattern is to wrap the real x402 fetch client in LangChain's own tool type, and that is exactly what the code below does.

Prerequisites

Have these ready before you start:

  • A working LangChain agent in TypeScript (any executor: AgentExecutor, createToolCallingAgent, LangGraph).
  • A Blockchain0x account with one agent created. The add-payments-to-agent guide walks through that in five minutes.
  • An API key. Use a sk_test_ key for this walkthrough and switch to sk_live_ when you ship.
  • Node 18 or newer. The SDK targets >=18.

Set the key where your runtime reads env:

BASH
export B0X_API_KEY=sk_test_...   # sk_test_ -> Base Sepolia, sk_live_ -> Base mainnet

Install the packages

Two real packages, plus LangChain core if you do not already have it.

BASH
npm install @blockchain0x/node @blockchain0x/x402 @langchain/core

@blockchain0x/node is the authenticated client. @blockchain0x/x402 is the payment layer: its ./client export gives you a drop-in fetch that answers 402s. That is the whole dependency list. If you went looking for a dedicated LangChain adapter package, there is not one, and you will not miss it.

Wrap a paid API in a LangChain tool

Build one client per process, then wrap the x402 fetch in a DynamicStructuredTool. The agent treats it like any other tool.

TYPESCRIPT
import { DynamicStructuredTool } from "@langchain/core/tools";
import { createClient } from "@blockchain0x/node";
import { createX402Client } from "@blockchain0x/x402/client";
import { z } from "zod";

// The sk_test_ prefix pins this client to Base Sepolia.
const sdk = createClient({ apiKey: process.env.B0X_API_KEY! });

// fetchWithPay behaves like fetch. On an HTTP 402 it parses the payment
// requirement, builds the `X-Payment: exact-usdc:<base64>` header, settles
// in USDC, and re-issues the request. You just await the final Response.
const fetchWithPay = createX402Client({ sdk });

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: async ({ ticker }) => {
    const res = await fetchWithPay(
      `https://quotes.example.com/v1/quote?ticker=${encodeURIComponent(ticker)}`,
    );
    if (!res.ok) {
      // 402 is handled for you; a non-2xx here means the upstream itself
      // failed or the payment was rejected. Surface it, do not throw blindly.
      return `Quote lookup failed with status ${res.status}.`;
    }
    return await res.text();
  },
});

That is the entire integration. The tool's schema, name, and description are unchanged from an unpaid tool, so the planner reasons about it exactly as before. The only new line is the fetchWithPay wrapper.

Run the agent

The payment-aware tool plugs into your existing agent with no other 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], 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 upstream returns 402, the wallet settles the price in USDC, and the retried request returns the quote. The planner sees a normal tool result. It does not know money changed hands, and it does not need to.

Confirm payments with a webhook

Webhooks matter when the paid call starts work that finishes later. For a synchronous lookup like the one above, skip this section. For anything async, verify every delivery with webhooks.verify from the SDK. Verify against the raw bytes, never the parsed JSON, because the HMAC is computed over exactly what arrived on the wire.

TYPESCRIPT
import express from "express";
import { webhooks } from "@blockchain0x/node";

const app = express();
app.use(express.raw({ type: "application/json" }));

app.post("/webhooks/payment", (req, res) => {
  const result = webhooks.verify({
    headers: req.headers,
    rawBody: req.body, // Buffer of raw bytes
    secret: process.env.B0X_WEBHOOK_SECRET!, // returned once when you create the webhook
  });

  if (!result.ok) {
    return res.status(400).json({ code: result.code });
  }

  const payload = JSON.parse(req.body.toString("utf8"));
  if (result.eventType === "payment.sent") {
    deliverAsyncResult(payload);
  }
  return res.status(200).end();
});

The verifier compares the HMAC in constant time and rejects any delivery whose timestamp is more than five minutes off, which kills replay attempts. The events you care about for an agent that spends are payment.sent (the agent paid) and payment.received (someone paid the agent).

Set spending limits

This is the part people get wrong, so read it twice. You do not set spend limits from the SDK, and you never put them in the prompt. They live in the dashboard, enforced by the wallet API before settlement, which is the one place prompt injection cannot reach them.

You can read back what is enforced to confirm it:

TYPESCRIPT
const agentId = "agt_...";
const res = await fetch(
  `https://api.blockchain0x.com/v1/agents/${agentId}/spend-permissions`,
  { headers: { Authorization: `Bearer ${process.env.B0X_API_KEY!}` } },
);
const permissions = await res.json();
// Each permission exposes allowance_wei, per_tx_wei, and period_seconds
// (86400 daily, 604800 weekly, or 2592000 monthly), plus start_at / end_at.

The wallet checks these on every payment intent. A call that would break per_tx_wei or blow through the period allowance_wei is refused before any USDC moves. Set conservative numbers in the dashboard first, watch real usage for a week, then loosen. The agent-spend-controls guide covers the dashboard side.

Test on Base Sepolia

Run the whole flow on testnet before you touch a sk_live_ key. A sk_test_ key settles on Base Sepolia (eip155:84532) with the same request and response shapes as mainnet.

Fund the agent first. Copy the agent's wallet address from the dashboard (or its public page at https://wallet.blockchain0x.com/a/{slug}) and send it test USDC from a public Base Sepolia USDC faucet. Then run the agent and watch the paid tool settle.

One honest caveat: outbound settlement is in active rollout. On some networks the settle path can return a 503 until the chain adapter is live there, so write your tool to handle a non-2xx response cleanly rather than assume every paid call succeeds. The test-agent-payments guide documents the sandbox flow in more depth. Production costs are on the pricing page: the Free tier covers this walkthrough, and paid tiers drop the transaction fee.

Common pitfalls

Four mistakes that cost teams an afternoon each in their first week.

Verifying the parsed body instead of the raw bytes. The webhook HMAC is computed over the exact bytes on the wire. If a framework middleware parses the JSON before you read it, you re-serialize a slightly different string and the signature never matches. Mount express.raw on the webhook route and pass the Buffer straight into webhooks.verify.

Mixing test and live keys. A LangChain agent that boots with sk_test_ but points at production URLs is the most common config bug in week one. The server stamps the network from the key prefix and rejects a mismatched caller with apikey.network_mismatch, but you want to catch it earlier. Fail the boot:

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

Putting the budget in the prompt. "You may spend up to five dollars per task" in a system prompt is not a control, it is a suggestion, and a crafted input will talk the model past it. The spend permission in the dashboard is the real boundary. The prompt should describe behavior; the wallet enforces money.

Assuming the agent retries 402 itself. It does not. The x402 client handles the 402 and retry inside fetchWithPay. Your tool sees only the final response. Do not write your own 402 branch on top of it, or you will pay twice for one call.

What to ship today

Take one thing from this guide: adding payments to a LangChain agent is a single fetchWithPay wrapper around a tool's fetch. Everything else, the webhook and the spend limits, is hardening you layer in as the agent earns trust.

Ship the wrapper on Base Sepolia today, watch one real paid call settle, then set a dashboard spend limit before you go near a sk_live_ key. If your agent will also sell a service, the receive side is the monetize-mcp-server guide. If it only consumes paid APIs, the spend limit is the highest-value thing you can do this week.

FAQ

Frequently asked questions.

Does this work with LangGraph?

Yes. LangGraph is the orchestration layer above LangChain, and every node still calls plain Tools. Register the same payment-aware tool with the node that needs it. Nothing about the x402 client changes; you are wrapping a fetch, and a fetch works the same inside a single agent or a multi-node graph.

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, so you switch chains by switching keys. The only payment scheme today is exact-usdc.

What happens when a payment would exceed the agent's spend limit?

The wallet checks the agent's spend permissions before it settles anything. A payment that breaks the per-transaction or period allowance is rejected before any USDC moves, so the paid request never completes and your tool gets a non-2xx response. Surface that to the planner and tell it not to retry the same call blindly.

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

An API key authorizes the agent against one provider. A Blockchain0x wallet lets the agent pay any endpoint that speaks x402 and accepts USDC: paid APIs, paid MCP tools, other agents. The wallet is a primitive you reuse across every merchant, not a per-vendor integration you rebuild each time.

Can I charge other agents to use one of my own tools?

Yes, that is the receive side. Put createX402Plugin in front of your endpoint (it ships for Fastify at @blockchain0x/x402/server/fastify and Express at @blockchain0x/x402/server/express). It returns a 402 with your price and verifies the X-Payment header on the retry. The mcp-server-monetization guide is the canonical version of that flow.

Is the webhook required?

Only for asynchronous work. If your tool returns its result the moment the paid request succeeds, you can skip webhooks. They matter when the paid call kicks off something that finishes later, where you want to act on the payment.received or payment.sent event rather than block the tool.

Create your free agent wallet in 5 minutes.

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