What the integration covers
Adding payments to the OpenAI Agents SDK is a pattern, not a package. You give each agent a wallet and have its tools pay through the x402 client, which adds four capabilities the SDK does not have by default: per-tool paid calls settled in USDC on Base, per-agent identity counterparties can verify, a wallet-enforced spend limit that survives prompt injection, and audit indexed by agent rather than by Runner invocation.
The design mirrors the SDK's own model: each agent is its own entity. When you build a graph of agents that hand off to each other, each has its own instructions and its own tools, and with a wallet each also has its own budget and audit trail. This is the integration-cluster reference; the canonical page is at /integrations/openai-agents-sdk, and the LangChain walkthrough at how-to-add-payments-to-langchain-agent translates almost line for line.
Compatibility matrix
Because you wrap a fetch (or call a proxy that does), anything in the SDK that calls a tool works.
| OpenAI Agents SDK surface | Supported? | Notes |
|---|---|---|
TypeScript SDK (@openai/agents) |
Yes | Wrap createX402Client inside the tool's execute |
Python SDK (from agents import ...) |
Via a Node proxy | The x402 client is Node-only; the function_tool calls a localhost proxy |
The Agent class |
Yes | Standard agent shape, unchanged |
Runner.run() / streamed runs |
Yes | Streaming and non-streaming both work |
| Handoffs between agents | Yes | The receiving agent pays from its own wallet |
| Multi-tool agents | Yes | Each tool pays independently |
| Built-in guardrails | Yes | Orthogonal to payment; both layers run |
| Built-in tracing | Yes | Log settlements alongside the SDK spans |
| Custom model backends | Yes | Anthropic, Mistral, local, via the SDK's model interface |
What is not in scope:
- Tools that route through the SDK's Computer Use or Browser tools without a
function_tool. Wire the payment API directly there. - Billing on partial results before a tool completes. Payment happens on the paid request, not per streamed chunk.
Surface area in one screen
TypeScript wraps the client directly in a tool:
import { Agent, run, tool } from "@openai/agents";
import { createClient } from "@blockchain0x/node";
import { createX402Client } from "@blockchain0x/x402/client";
import { z } from "zod";
const sdk = createClient({ apiKey: process.env.B0X_API_KEY! });
const fetchWithPay = createX402Client({ sdk });
const getQuote = tool({
name: "get_quote_realtime",
description: "Fetch a real-time quote for a stock ticker.",
parameters: z.object({ ticker: z.string() }),
execute: async ({ ticker }) => {
const res = await fetchWithPay(`https://quotes.example.com/v1/quote?ticker=${ticker}`);
return res.ok ? await res.text() : `Lookup failed: ${res.status}`;
},
});
const researcher = new Agent({ name: "Researcher", instructions: "Equity research analyst.", tools: [getQuote] });
const result = await run(researcher, "What is the live quote on TSLA?");Python calls a small local proxy from a function_tool, because the x402 client is Node-only today:
from agents import Agent, function_tool, Runner
import requests
@function_tool
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}"
researcher = Agent(name="Researcher", instructions="Equity research analyst.", tools=[get_quote_realtime])The proxy is the same thirty-line Node service used in the CrewAI walkthrough. The other half of the integration is the spend limit, which you set in the dashboard and read back over the API:
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(); // allowance_wei, per_tx_wei, period_seconds, ...No new Agent class, no custom Runner, no replacement for function_tool, just a tool that pays and a limit you set once. Which path you take is decided by your runtime, not by preference: a TypeScript agent wraps the client inline with no extra process, while a Python agent runs the proxy alongside it. If you are starting fresh and language is open, the TypeScript path has one fewer moving part because there is no proxy to deploy or supervise.
Handoffs and per-agent wallets
Handoffs are one of the SDK's strongest primitives. An agent hands control to another mid-run; the receiver inherits context but runs with its own instructions and tools. Give each agent its own wallet and the model lines up cleanly: each has its own budget and its own audit trail.
Three benefits in handoff-heavy designs:
Per-role budgets. A triage agent that only routes needs almost no budget. A researcher calling premium APIs needs a real allowance. A writer calling cheap LLMs needs a small one. Per-agent wallets let you tune each role rather than budgeting for the worst case across the whole graph.
Clean attribution. When the dashboard shows most spend on the researcher and little on the writer, you see exactly where cost lives. A shared wallet erases that signal.
Isolated blast radius. A prompt-injected receiver after a handoff spends only its own allowance. The agents above it keep their budgets intact. The general shape is documented at the agent-to-agent payment glossary entry, and the LangChain parallel is langchain-payment-integration.
What the integration does not touch
The pattern stays narrow. These parts of your SDK stack are untouched:
- The LLM. Whatever model each agent uses passes through.
- The instructions. Agent behavior and reasoning are unchanged.
- The Runner. Streaming and non-streaming runs both work.
- Handoff routing. The SDK decides who handles what; the tool pays only when the receiver calls it.
- Guardrails. Input and output validation keep running.
- Tracing. Spans for handoffs and tool calls appear as before.
- Free tools. Tools that do not call the paid path return normally with no involvement.
When this is the right integration
Two situations where this pattern is the right pick.
Your agents call paid third-party services. Premium data, paid models, paid MCP servers, all surface as 402-returning endpoints the client handles. The alternative, baking a credential into each tool or proxying everything through your backend, is more code and gives no unified limit.
Your system has several agents with different cost profiles. Per-agent wallets give per-role budgets and per-role audit. A shared wallet across many agents works but loses the attribution that makes a hierarchy easier to run.
Where it is not the right pick: a single-agent app with one trusted provider and a shared key (it adds nothing), a workload where humans drive every payment via Stripe (use that migration path), or a tool that bypasses function_tool entirely (wire the payment API directly).
Pricing and tier choices
The pattern is free; you write code against open packages. What you pay is the wallet platform fee, set per agent on the pricing page: Free is $0 per agent per month at a 5% transaction fee, Pro is $9 per agent per month at 2%, and Business is $29 per agent per month at 1%. Per-agent pricing means you pay for the agents that actually transact.
In handoff-heavy designs, the busiest agents are usually the specialists at the bottom of the graph, the researchers and data-fetchers. Upgrade those to Pro first when their volume justifies it, and leave the triage and routing agents at the top on Free until their own traffic earns the change. Tiers are per agent, so the mix evolves with your traffic. Run a week on Free, read the numbers, then decide.