Skip to content

A Vercel AI SDK agent that pays per call.

A working Vercel AI SDK tool that calls a live Apiosk endpoint. The model picks the tool and reads the result; the x402 client underneath answers the 402 and signs a USDC payment on Base per call. No API key, no account.

npm install ai @ai-sdk/anthropic zod @x402/axios @x402/evm axios viem

What you are about to do

The whole integration is one tool definition and one wallet key. Everything specific to Vercel AI SDK is below; everything specific to payment happens inside the client.

Install the SDK and a paying HTTP client

01

npm install ai @ai-sdk/anthropic zod @x402/axios @x402/evm axios viem. Put a funded Base wallet key in WALLET_PRIVATE_KEY. Nothing to sign up for, so there is no API key to add.

Define the tool with inputSchema

02

Wrap the endpoint in tool() from the ai package. Describe the arguments with zod under inputSchema, and let execute call the gateway through the wrapped axios instance. The x402 interceptor handles the 402 and the retry, so execute reads like an ordinary request.

Hand the tool to generateText

03

Pass it in the tools map on generateText or streamText and bound the loop with stopWhen: isStepCount(n). The model decides when the job needs the tool, calls it with its own arguments, and reads the returned JSON on the next step.

Vercel AI SDK, end to end

Copy these in order. The endpoints are placeholders. Swap in any endpoint from the catalog.

tools/apiosk.tsTypeScript
// tools/apiosk.ts
// The paying client plus the first tool. Typechecks against ai 7,
// @x402/axios 2, @x402/evm 2, viem 2, zod 4.

import axios from "axios";
import { wrapAxiosWithPaymentFromConfig } from "@x402/axios";
import { ExactEvmScheme } from "@x402/evm";
import { privateKeyToAccount } from "viem/accounts";
import { tool } from "ai";
import { z } from "zod";

const account = privateKeyToAccount(process.env.WALLET_PRIVATE_KEY as `0x${string}`);

// One client for every endpoint on the gateway. Base mainnet is the CAIP-2 id
// "eip155:8453". The interceptor answers the 402, signs the USDC payment and
// retries the request, so execute() below only ever sees the data.
export const apiosk = wrapAxiosWithPaymentFromConfig(
  axios.create({ baseURL: "https://gateway.apiosk.com" }),
  { schemes: [{ network: "eip155:8453", client: new ExactEvmScheme(account) }] },
);

// inputSchema, not parameters. The field was renamed in AI SDK v5 and is
// required in v7, so there is no tool() overload that matches `parameters`:
// tsc rejects the call outright rather than building a tool with no schema.
export const convertCurrency = tool({
  description: "Convert an amount between two currencies using live FX rates.",
  inputSchema: z.object({
    from: z.string().describe("ISO currency code to convert from, e.g. EUR"),
    to: z.string().describe("ISO currency code to convert to, e.g. USD"),
    amount: z.number().positive(),
  }),
  execute: async ({ from, to, amount }) => {
    const { data } = await apiosk.get("/v1/fx/convert", {
      params: { from, to, amount },
    });
    return data;
  },
});
tools/verify-email.tsTypeScript
// tools/verify-email.ts
// A second job on the same client. Nothing about the payment path changes.

import { tool } from "ai";
import { z } from "zod";
import { apiosk } from "./apiosk";

export const verifyEmail = tool({
  description: "Check whether an email address is deliverable.",
  inputSchema: z.object({
    email: z.string().describe("The address to check, e.g. ada@example.com"),
  }),
  execute: async ({ email }) => {
    const { data } = await apiosk.get("/v1/email/verify", { params: { email } });
    return data;
  },
});
agent.tsTypeScript
// agent.ts
// Run with: npx tsx agent.ts

import { anthropic } from "@ai-sdk/anthropic";
import { generateText, isStepCount } from "ai";
import { convertCurrency } from "./tools/apiosk";
import { verifyEmail } from "./tools/verify-email";

const result = await generateText({
  model: anthropic("claude-opus-5"),
  tools: { convertCurrency, verifyEmail },
  // stopWhen replaces maxSteps. isStepCount is the v7 name; stepCountIs is
  // still exported as an alias. Five steps is five tool round trips at most.
  stopWhen: isStepCount(5),
  prompt: "What is 250 EUR in USD right now?",
});

console.log(result.text);

// Each paid call is in the step record:
// result.steps.flatMap((step) => step.toolResults);

Three things to know

The key lives in the client, not the tool

WALLET_PRIVATE_KEY is read once, where the axios instance is built. Tools import that instance. The model sees the description and the inputSchema and nothing else: not the wallet, not the price, not the payment header. Keep the client in its own module so a second tool cannot reconstruct it with different settings.

execute is async because the call is two round trips

A paid request is a 402 with a price, then a signed retry. Both happen inside execute, so the promise resolves later than an unpaid fetch would. Return the parsed JSON, not the axios response: whatever you return is what the model reads on the next step, and a response object serialises into noise.

stopWhen is the ceiling on a run

maxSteps is gone. stopWhen: isStepCount(n) bounds how many tool round trips one generateText or streamText can make, which is the upper bound on paid calls per run. Leave it out and a loop that keeps calling the tool keeps paying. stepCountIs still resolves as an alias if you have it in older code.

Good questions.

A few things to know before you start.

How pricing works
What is Apiosk?

Apiosk helps people and AI agents get data from paid APIs. Describe what you need, review the proposed service or research plan and its price, then approve the work. Apiosk handles the calls and returns the available results with their sources.

What is the difference between Answer and Research?

Answer helps with a direct data request, such as a company profile or filed accounts. Research creates a plan for requests that need several steps. It can resolve a company first and use that identity to retrieve its records. The plan shows what it can cover before you approve.

What if my question is unclear or data is missing?

Apiosk asks for context when it needs a company, location, period or other detail. If a provider does not have the requested data, the result should say what is missing. Data availability depends on the source; an API listing does not guarantee that every record exists.

How much does it cost?

The price depends on the services your request needs. Apiosk shows the total, including its service fee, before you approve. You pay per use from your balance, with no subscription required.

See pricing
Do I need to know how APIs work?

No. In the Apiosk app, you ask in ordinary language and approve the price. You do not need a separate API key or account for each provider. Developers can also connect through MCP or API.

Can I use Apiosk inside ChatGPT or Claude?

Yes. Apiosk is available as a connector for ChatGPT and Claude, and through MCP for other agents and tools. Connect once, sign in to Apiosk, and ask your question from there. The price is shown before anything runs and is paid from your Apiosk balance.

Connect an agent
Can my AI agent use Apiosk?

Yes. Connect a compatible agent through MCP or API and authorize its access to your Apiosk account. Spending limits and approval rules control what it can buy.

Connect an agent