Tutorial: give your AI agent a wallet and let it buy social data

An AI agent that can pay for its own API calls is a fundamentally more capable machine than one that cannot. It can decide, mid-task, that it needs a piece of data, buy exactly that data for a cent, and move on. No human provisioning keys, no vendor onboarding, no monthly plan. This tutorial takes you from nothing to a Claude agent that checks Instagram, TikTok, and X stats and pays for every lookup itself. Budget about fifteen minutes and five dollars.

Step 1: create the agent's wallet

The wallet is just a keypair. Generate one locally with viem:

// generate-wallet.mjs
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";

const pk = generatePrivateKey();
const account = privateKeyToAccount(pk);

console.log("Address:    ", account.address);
console.log("Private key:", pk); // store securely, never commit

Treat the private key like the cash it controls: environment variable or secrets manager, never source control. The nice property of agent wallets is that the blast radius is capped by the balance. A wallet holding five dollars is a five dollar problem if it leaks, which is a very different risk profile from a leaked API key on a card-backed account.

Step 2: fund it with USDC on Base (skip the ETH)

Send USDC on the Base network to the address you just generated. From Coinbase, choose USDC, withdraw, select Base as the network. From any exchange or wallet, same idea: asset USDC, network Base. Five dollars funds 500 API calls.

Here is the part that surprises people: the wallet needs zero ETH. x402 payments are EIP-3009 transfer authorizations. Your agent signs a message authorizing the transfer, and the facilitator submits it on chain and pays the gas. You will never top up gas, never see a "insufficient funds for gas" error, never think about it again. The USDC contract on Base is 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 if you want to verify what you are sending.

Step 3: wrap fetch so payment is automatic

npm install @x402/fetch @x402/evm viem
// paid-fetch.mjs
import { wrapFetchWithPaymentFromConfig } from "@x402/fetch";
import { ExactEvmScheme } from "@x402/evm";
import { privateKeyToAccount } from "viem/accounts";

const account = privateKeyToAccount(process.env.AGENT_PRIVATE_KEY);

export const payFetch = wrapFetchWithPaymentFromConfig(fetch, {
  schemes: [{ network: "eip155:8453", client: new ExactEvmScheme(account) }],
});

That wrapper is the whole trick. When a server responds 402, it reads the payment terms from the accepts array, signs a USDC authorization for the exact amount, retries with the payment attached, and returns the paid response. Test it against a live endpoint:

import { payFetch } from "./paid-fetch.mjs";

const res = await payFetch(
  "https://x402.findclout.com/api/v1/post?url=" +
    encodeURIComponent("https://www.instagram.com/reel/DLmR4kXtQ2a/")
);
console.log(await res.json());
console.log("Receipt:", res.headers.get("PAYMENT-RESPONSE"));

If you see JSON with view counts and a settlement receipt in the header, your agent has money and knows how to spend it. Every request costs $0.01, and 4xx responses are never charged, so a malformed URL costs nothing.

Step 4: expose it to Claude as a tool

Now hand the capability to an LLM. With the Anthropic SDK, define a tool whose implementation is just the paid fetch, and run the standard tool-use loop:

// claude-agent.mjs
import Anthropic from "@anthropic-ai/sdk";
import { payFetch } from "./paid-fetch.mjs";

const anthropic = new Anthropic();

const tools = [{
  name: "get_social_post_stats",
  description:
    "Get live stats for a public social media post. Costs $0.01 in USDC, paid " +
    "automatically from your wallet. Call this whenever you need current views, " +
    "likes, comments, shares, or follower counts for an Instagram, TikTok, or X post URL.",
  input_schema: {
    type: "object",
    properties: {
      url: { type: "string", description: "Full post URL on instagram.com, tiktok.com, or x.com" },
    },
    required: ["url"],
  },
}];

async function getSocialPostStats({ url }) {
  const res = await payFetch(
    "https://x402.findclout.com/api/v1/post?url=" + encodeURIComponent(url)
  );
  return JSON.stringify(await res.json());
}

let messages = [{
  role: "user",
  content: "Which of these posts performed best? " +
    "https://www.instagram.com/reel/DLmR4kXtQ2a/ and " +
    "https://www.tiktok.com/@nflstreetmoments/video/7401882236711",
}];

while (true) {
  const response = await anthropic.messages.create({
    model: "claude-opus-4-8",
    max_tokens: 16000,
    tools,
    messages,
  });

  if (response.stop_reason !== "tool_use") {
    console.log(response.content.find((b) => b.type === "text")?.text);
    break;
  }

  messages.push({ role: "assistant", content: response.content });
  const results = [];
  for (const block of response.content) {
    if (block.type === "tool_use") {
      results.push({
        type: "tool_result",
        tool_use_id: block.id,
        content: await getSocialPostStats(block.input),
      });
    }
  }
  messages.push({ role: "user", content: results });
}

Note what is absent: no API key for the stats service anywhere in this file. The tool description tells Claude the call costs a cent, so the model can weigh whether a lookup is worth it, which turns out to be a genuinely useful economic constraint on tool use.

Step 5 (alternative): LangChain

The same capability as a LangChain tool, usable in any agent executor:

import { tool } from "@langchain/core/tools";
import { z } from "zod";
import { payFetch } from "./paid-fetch.mjs";

export const socialStatsTool = tool(
  async ({ url }) => {
    const res = await payFetch(
      "https://x402.findclout.com/api/v1/post?url=" + encodeURIComponent(url)
    );
    return JSON.stringify(await res.json());
  },
  {
    name: "get_social_post_stats",
    description:
      "Get live views, likes, comments, shares, and follower counts for a public " +
      "Instagram, TikTok, or X post by URL. Costs $0.01 per call, paid automatically.",
    schema: z.object({ url: z.string().describe("Full post URL") }),
  }
);

Step 6: put guardrails on the money

An agent with a wallet needs a budget, and the wallet itself is the cleanest one: it cannot spend more than it holds. Layer on two cheap application-level controls:

// Simple spend tracking around payFetch
let spentCents = 0;
const BUDGET_CENTS = 200; // $2.00 per task

export async function payFetchBudgeted(url) {
  if (spentCents >= BUDGET_CENTS) {
    throw new Error("Task budget exhausted: " + spentCents + " cents spent");
  }
  const res = await payFetch(url);
  if (res.headers.get("PAYMENT-RESPONSE")) spentCents += 1;
  return res;
}

And keep the wallet topped up small. A pattern we like: a treasury wallet holds the real funds and drips $5 at a time into the agent wallet. The agent gets autonomy, you keep custody of the meaningful money.

Where to point your newly moneyed agent

The universal /api/v1/post endpoint used above auto-detects Instagram, TikTok, and X from the URL, which makes it the right single tool for a general agent. For deeper work, add the specific endpoints as separate tools: Instagram post and profile stats, TikTok stats with follower counts, and X post stats, each documented on the endpoint reference. Machine-readable descriptions of everything live at openapi.json and llms.txt, so agents can even discover the API on their own.

For a complete real-world workflow built on this foundation, read how agents verify influencer campaign results automatically. And if you are wondering why the pay-per-request model beats API keys for this entire class of problem, that argument is laid out in x402 vs API keys.

Want the views, not just the numbers?

FindClout runs the biggest independently owned American meme page network, with sports, finance, entrepreneurship, movie, TV, and music pages reaching real American audiences. We place brands natively inside viral clips people already love: not ads next to content, your product inside it.

Book a call at findclout.com