A CrewAI agent that buys the data it needs.
A CrewAI tool that calls a paid endpoint on gateway.apiosk.com. The 402 is answered inside the tool body, so the agent asks a question and gets JSON back. No API key, no account.
pip install crewai "x402[requests,evm]"What you are about to do
The whole integration is one tool definition and one wallet key. Everything specific to CrewAI is below; everything specific to payment happens inside the client.
Install crewai and the x402 requests client
pip install crewai "x402[requests,evm]". Custom tools ship inside crewai itself, so you do not need the [tools] extra — that one only pulls the prebuilt crewai_tools catalog. The evm extra brings eth-account and web3 with it. CrewAI needs Python 3.10 or newer.
Define the tool with @tool from crewai.tools
Build one paying requests.Session at module level, then decorate a plain function with @tool. CrewAI turns the type annotations and the docstring into the schema the model reads, so both are required — it raises ValueError without them. Reach for BaseTool with args_schema when you want to write the argument descriptions yourself.
Hand it to the Agent and kick off the Crew
Pass the decorated function into Agent(tools=[...]), give the Task an expected_output, then call Crew(agents=[...], tasks=[...]).kickoff(). The Agent's own llm defaults to gpt-4.1-mini, so set OPENAI_API_KEY or pass llm=. kickoff returns a CrewOutput; result.raw is the answer.
CrewAI, end to end
Copy these in order. The endpoints are placeholders — swap in any endpoint from the catalog.
Three things to know
The key stays out of the crew
WALLET_PRIVATE_KEY is read once when the tool module imports, and the session is closed over by the function body. It never enters an Agent, a Task description or a tool argument, so it cannot reach the model's context or the crew log.
Sync tools, sync client
CrewAI executes a tool body synchronously, so pair x402ClientSync with x402_requests. The async pair — x402Client with httpx — raises TypeError here. x402_requests hands back an ordinary requests.Session, so params=, raise_for_status() and `with` all behave as usual.
The agent sees one tool call
The 402, the signature and the retry all happen inside session.get. The tool returns the JSON body and nothing else, so with verbose=True the crew log shows a single tool call rather than two requests. The settled call leaves an on-chain receipt on Base.
Frequently asked questions
Where does BaseTool live now — crewai.tools or crewai_tools?
crewai.tools. Both `from crewai.tools import tool` and `from crewai.tools import BaseTool` are current and ship in the crewai package itself. The older `from crewai_tools import BaseTool` no longer resolves: crewai_tools is now only a catalog of prebuilt tools, and the `crewai[tools]` extra installs it. Writing your own tool needs nothing beyond crewai.
Do I use x402Client or x402ClientSync in a CrewAI tool?
x402ClientSync, paired with `x402_requests`. A CrewAI tool body runs synchronously — `_run` and the function under @tool are both sync — so the requests-based surface is the match. x402Client is the async half and pairs with `x402HttpxClient` from x402[httpx]. Mixing the two raises TypeError by design. There is no x402-httpx package on PyPI; httpx and requests are extras of the single `x402` package.
Does the tool need an API key for the endpoint?
No. gateway.apiosk.com replies 402 Payment Required with the price for that request, the session signs a USDC payment on Base, and the call is retried. There is no key, no account and no invoice for the endpoint. The agent's own model is separate: CrewAI's Agent defaults to gpt-4.1-mini, so set OPENAI_API_KEY or pass `llm=` if you use another provider.
Every listed API, on the same tool interface.
Agents call the comparison. Providers get into it.