Obol Docs

Developer documentation

Obol is a marketplace where any API, scraper, bot, model, or data process can charge AI agents per call in USDC — with no billing system, no subscriptions, and no user accounts.

New here? Skip the reading — build your first service with AI in 2 minutes ↓

Network
Arc testnet · chain 5042002
Payment
USDC via Circle Gateway (x402)
Fee
0% commission · free per call
Two roles, one marketplace
Provider (Seller)
You own something useful — an API, a scraper, a model. You wrap it with Obol middleware and get paid per call in USDC, settled to your Arc wallet.
Buyer (Agent)
Your AI agent discovers services in the Obol marketplace, deposits USDC into Circle Gateway once, then pays per call automatically — no manual signing per request.
✨ Build with AI · 2-minute setup

Don't write a line of code.
Let your AI build your service.

Obol is built for the agent economy — so building on Obol should use an agent too. Copy the Obol Skill below, paste it into Claude, ChatGPT, or Cursor, and it will scaffold a working paid service, wire in your wallet, and walk you through deploying it. Your Arc payout address is already baked in.

1
Copy the skill
One click above — your wallet is already in it.
2
Paste into your AI
Claude, ChatGPT, Cursor — any capable model.
3
Deploy & register
Your AI hands you the server + deploy steps.
▸ Preview the skill prompt
You are helping me publish a paid service on Obol — a marketplace where AI agents
discover services and pay per HTTP call in USDC on the Arc blockchain (no accounts,
no API keys for the buyer, no invoices). I want you to build, run, and help me deploy
a working seller server, then tell me exactly how to register it.

# CONTEXT YOU NEED

- Network: Arc testnet (EVM, chain ID 5042002).
- Payment rail: Circle Gateway via the x402 standard (HTTP 402 "Payment Required").
- The seller (me) runs a normal Express server. Each paid route is wrapped with one
  middleware call that sets a price. When an agent calls without payment, the
  middleware returns 402 + payment details; the agent's SDK pays off-chain (EIP-3009,
  gasless, ~200ms) and retries; the middleware verifies and runs my handler.
- My earnings settle to MY Arc wallet address: 0xYourArcAddress
- I keep 100% of each call price; Obol charges 0% commission per call (it monetizes via optional subscriptions, not a take rate).

# THE STACK (use these EXACT packages — do not substitute)

  npm install express @circle-fin/x402-batching

Server skeleton (ESM, Node 18+):

  import express from "express";
  import { createGatewayMiddleware } from "@circle-fin/x402-batching/server";

  const app = express();
  app.use(express.json());

  const SELLER = process.env.SELLER_ADDRESS;            // my Arc wallet
  const gateway = createGatewayMiddleware({
    sellerAddress: SELLER,
    networks: "eip155:5042002",                         // Arc testnet
    facilitatorUrl: "https://gateway-api-testnet.circle.com",
  });

  // Each paid route: gateway.require("$<price>") sets the USDC price per call.
  app.get("/price", gateway.require("$0.001"), async (req, res) => {
    // ... my logic ...
    res.json({ /* result */, paidBy: req.payment?.payer });
  });

  app.get("/health", (_req, res) => res.json({ ok: true })); // free, unmetered
  app.listen(process.env.PORT || 4021);

# THE SERVICE I WANT TO BUILD (default — change if I tell you otherwise)

A **Crypto Price API**. It wraps CoinGecko's FREE public endpoint (no API key needed):

  GET https://api.coingecko.com/api/v3/simple/price?ids=<coin>&vs_currencies=usd

Expose one paid route:
  GET /price?coin=bitcoin   → charge $0.001 USDC → return { coin, usd, ts }
Validate the coin param, handle CoinGecko errors gracefully, and always include
`paidBy: req.payment?.payer` in the response so I can see who called.

# WHAT TO DO, STEP BY STEP

1. Create the project: package.json (type: module), the server file, a .env with
   SELLER_ADDRESS=0xYourArcAddress and PORT=4021, and a .gitignore that excludes .env.
2. Write the full server. Production-quality: input validation, try/catch around the
   upstream fetch, clear JSON errors, a brief comment on each route's price.
3. Give me the exact commands to install deps and run it locally.
4. Tell me how to expose it publicly for testing in ONE command:
     npx localtunnel --port 4021     (gives a https://<name>.loca.lt URL)
   …and how to deploy permanently to Railway or Render (free tier): push to GitHub,
   create the project, set env var SELLER_ADDRESS=0xYourArcAddress, get the public URL.
5. Tell me precisely what to enter when I register it at obol-arc.web.app/dashboard
   → Provide services → + New service:
     - Service name, Category, Description
     - Price per call (USDC), Payout address (0xYourArcAddress), Hosted URL (my public URL)
     - Input params (e.g. "coin: string")
6. Finally, give me a one-line curl I can run to confirm the route returns 402 before
   payment (proof the metering works):  curl -i <my-url>/price?coin=bitcoin

Build everything now. Output complete files I can copy verbatim — no placeholders
except where I must paste my deployed URL. Be concise but complete.
Prefer to do it by hand? The full manual walkthrough is right below — install the SDK, wrap your endpoint, deploy, and register. The AI skill just does all of it for you.

Quick start

Prefer the manual route? Here's every step by hand.

Get from zero to a live paid API endpoint in under 10 minutes.

1
Create your wallet
Go to Dashboard → Use services → click "Create my wallet". Set a PIN — Obol never holds your keys. You'll get an Arc testnet EOA address. Copy it.
2
Get testnet USDC
Visit faucet.circle.com and request USDC on Arc testnet to your new wallet address. You'll need this to test both sending and receiving payments.
3
For sellers: wrap an endpoint
Install the SDK, add one middleware call to your Express route, run the server. See Providers section for the full code.
4
For buyers: deposit & call
Deposit USDC into Gateway once via your dashboard. After that, every API call is automatically paid — no confirmation per request.
Testnet only. Obol currently runs on Arc testnet (chain ID 5042002). All USDC is testnet USDC — no real money. Get free testnet USDC at faucet.circle.com.

Providers (Sellers)

A provider runs a server that does something useful and charges agents per HTTP call. You decide what runs behind the endpoint — Obol only sees the request and response.

How it works

You add Obol middleware to any Express route. When an agent calls that route without payment, your server returns HTTP 402 (Payment Required) with Circle Gateway payment details. The agent's SDK automatically pays and retries. Your server processes the request and the earnings land in your Arc wallet.

Agent calls your URL
  → No payment header → your server returns 402 + payment details
  → Agent's SDK pays Circle Gateway (~200ms, off-chain)
  → Agent retries with payment proof
  → Your middleware verifies payment
  → Your handler runs, returns data
  → Earnings settle to your Arc address

Wrap your API

Install the SDK and add middleware to any Express route.

# In your server project
npm install @circle-fin/x402-batching express

Minimal example — single endpoint

import express from "express";
import { createGatewayMiddleware } from "@circle-fin/x402-batching/server";

const app = express();

// Replace with your UCW wallet address from the Obol dashboard
const SELLER = process.env.SELLER_ADDRESS;

const gateway = createGatewayMiddleware({
  sellerAddress: SELLER,
  networks: "eip155:5042002",                          // Arc testnet
  facilitatorUrl: "https://gateway-api-testnet.circle.com",
});

// $0.002 USDC per call to this route
app.get("/enrich", gateway.require("$0.002"), (req, res) => {
  const domain = req.query.domain || "example.com";
  res.json({
    domain,
    company: "Acme Inc.",
    // req.payment is populated after a successful payment
    paidBy: req.payment?.payer,
    txHash: req.payment?.transaction,
  });
});

app.listen(4021);
req.payment is injected by the middleware after a verified payment. It contains payer (the buyer's Arc address) and transaction (the settlement tx hash). Use these for receipts, usage logging, or per-user rate limiting.

Per-endpoint pricing

Different routes can have different prices. Call gateway.require() independently on each route.

const gateway = createGatewayMiddleware({
  sellerAddress: SELLER,
  networks: "eip155:5042002",
  facilitatorUrl: "https://gateway-api-testnet.circle.com",
});

// Cheap: basic lookup
app.get("/company/basic", gateway.require("$0.001"), (req, res) => {
  res.json({ name: "Acme Inc.", country: "US" });
});

// Medium: full profile
app.get("/company/full", gateway.require("$0.005"), (req, res) => {
  res.json({ name: "Acme Inc.", headcount: 420, revenue: "$12M", ... });
});

// Expensive: bulk batch (up to 50 domains per call)
app.post("/company/bulk", gateway.require("$0.050"), async (req, res) => {
  const { domains } = req.body;
  const results = await enrichAll(domains);   // your own logic
  res.json({ results, count: results.length });
});

// Free: health check (no middleware = no payment required)
app.get("/health", (_req, res) => res.json({ ok: true }));
Register each endpoint path + its price separately in the Obol dashboard under Per-endpoint pricing. This lets agents discover which paths exist and what each costs before calling. You can also leave a route unlisted if you only want direct callers.

API keys & secrets

When you wrap a paid third-party API, your API key stays on your server. Buyers never see it. They call your URL and pay — your server uses its key to call the upstream service on their behalf.

# Your server's environment — buyers never see any of this
SELLER_ADDRESS=0xYourArcWallet
OPENAI_API_KEY=sk-...
SOME_DATA_API_KEY=abc123
SCRAPER_PROXY_PASSWORD=xyz789
The economics: You pay your upstream API $0.01/call. You charge agents $0.015/call through Obol. You keep $0.005 per call. The agent doesn't need an API key, a credit card, or an account anywhere — they just have USDC.

Real examples

Example 1 — Wrap OpenAI completions

import OpenAI from "openai";

const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });

// You pay OpenAI ~$0.002/call (GPT-4o-mini).
// You charge agents $0.004/call → $0.002 margin per call.
app.post("/complete", gateway.require("$0.004"), async (req, res) => {
  const { prompt } = req.body;
  const chat = await openai.chat.completions.create({
    model: "gpt-4o-mini",
    messages: [{ role: "user", content: prompt }],
  });
  res.json({
    result: chat.choices[0].message.content,
    paidBy: req.payment?.payer,
  });
});

Example 2 — Wrap a Puppeteer scraper

import puppeteer from "puppeteer";

// Agents pay $0.01 per page scrape. You pay server costs (~$0.001).
app.get("/scrape", gateway.require("$0.010"), async (req, res) => {
  const { url } = req.query;
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto(url, { waitUntil: "networkidle2" });
  const text = await page.evaluate(() => document.body.innerText);
  await browser.close();
  res.json({ url, text, charCount: text.length, paidBy: req.payment?.payer });
});

Example 3 — Wrap a premium weather API (you hold the key)

// Agents call your endpoint and pay $0.001.
// Your server calls the premium API with your key.
// Agents never see your key.
app.get("/weather", gateway.require("$0.001"), async (req, res) => {
  const { city } = req.query;
  const r = await fetch(
    `https://api.weatherapi.com/v1/current.json?key=${process.env.WEATHER_KEY}&q=${city}`
  );
  const data = await r.json();
  res.json({
    city: data.location.name,
    temp_c: data.current.temp_c,
    condition: data.current.condition.text,
    paidBy: req.payment?.payer,
  });
});

Deploying your server

Your server needs a permanent public HTTPS URL. Any Node.js host works. For testing you can use localtunnel (no install needed). For production deploy to Railway, Fly.io, or Google Cloud Run.

OptionCostSetup timeBest for
localtunnel (npx)Free10 secondsLocal testing only
RailwayFree tier5 minutesHackathons, demos
Fly.ioFree tier10 minutesPersistent low-traffic
Google Cloud RunFree tier15 minutesProduction
RenderFree tier5 minutesSimple deploys

Local testing with localtunnel

# Terminal 1 — run your server
SELLER_ADDRESS=0xYourArcAddress node server.mjs

# Terminal 2 — expose it publicly (no install needed)
npx localtunnel --port 4021
# → your url is: https://happy-dogs-fly.loca.lt

Deploy to Railway (permanent URL)

# 1. Push your server code to a GitHub repo

# 2. Go to railway.app → New Project → Deploy from GitHub

# 3. Set environment variables in Railway dashboard:
#    SELLER_ADDRESS = 0xYourArcAddress
#    PORT           = 4021
#    (any API keys your server needs)

# 4. Railway gives you a URL like:
#    https://your-project.railway.app
# Use that URL when registering in the Obol dashboard.

Register in the dashboard

Go to Dashboard → Provide services → + New service and fill in each field:

FieldWhat to enterExample
Service nameShort name agents see in searchCompany Enrichment API
CategoryPick the closest matchData
Price per callDefault USDC price for one call0.002
Payout addressYour Arc wallet — auto-filled if wallet created0xYourArcAddress
Hosted URLYour server's public HTTPS URLhttps://your-app.railway.app
DescriptionWhat your API does, what it returnsReturns company name, size, industry for any domain
Input paramsParam names agents use to call itdomain: string
API docs URLLink to your docs (optional)https://your-docs.example.com

Per-endpoint pricing rows (optional)

If your server has multiple routes at different prices, add one row per route. Leave empty to use the single price above for all routes.

PathPrice per callDescription
/company/basic0.001Name and country only
/company/full0.005Full profile with headcount and revenue
/company/bulk0.050Batch of up to 50 domains
Once registered, your service appears in the Marketplace where agents can discover it. Agents call your hosted URL directly — Obol doesn't proxy the traffic. Payment happens between agent and your server via Circle Gateway.

Buyers (Agents)

A buyer is any AI agent or script that discovers services on Obol and pays per call automatically using Circle Gateway.

How it works

1. Agent deposits USDC into Circle Gateway (one time, any amount)
2. Agent calls a paid API endpoint
3. Server returns 402 + payment details (seller address, amount, network)
4. Agent's SDK signs an EIP-3009 off-chain authorization (~200ms, no gas)
5. Circle Gateway verifies and records the payment
6. Agent retries the request with the payment header
7. Server verifies → processes → returns data
8. Gateway settles to seller on Arc (batched, gasless)
No gas. No wallet popup. No signing per call. The agent signs once per payment using EIP-3009 (off-chain). Circle Gateway handles verification and batch settlement. Once the Gateway balance is funded, calls are automatic.

Fund your account

Buying is keyless. All you need is an Obol account and API key — no private key, no wallet to manage. Obol's relayer pays sellers on your behalf and deducts from your funded balance.

# 1. Create an account and copy your API key from Settings on obol-arc.web.app
#    (looks like obl_sk_live_…)

# 2. Deposit USDC into your Obol spending balance (Dashboard → Deposit,
#    or the MCP "deposit" tool). Fund from any chain via Circle Gateway.

# 3. That's it — set your API key and start paying:
export OBOL_API_KEY=obl_sk_live_your_key_here
No private key required. Your API key authorizes payments through Obol's hosted relayer + Circle Gateway. Keep the API key secret (env var or secrets manager) — it can spend your balance, so treat it like a password.

MCP configuration

Add Obol to any MCP-compatible AI agent (Claude, Cursor, etc.) so it can find and pay for services automatically — with just your API key.

// Add to your claude_desktop_config.json or mcp settings:
{
  "mcpServers": {
    "obol": {
      "command": "npx",
      "args": ["-y", "@superbigroach/obol-mcp"],
      "env": {
        "OBOL_API_KEY": "obl_sk_live_…"
      }
    }
  }
}

Advanced: self-custody (optional)

Prefer to hold your own funds and sign payments locally instead of using the hosted relayer? Set OBOL_AGENT_KEY to a funded EOA private key and the MCP/SDK will sign directly. Most buyers do not need this.

# Generate an EOA key, fund it at faucet.circle.com (Arc testnet), then:
export OBOL_AGENT_KEY=0xYourPrivateKey   # replaces the keyless path
import { GatewayClient } from "@circle-fin/x402-batching/client";

const buyer = new GatewayClient({ chain: "arcTestnet", privateKey: process.env.OBOL_AGENT_KEY });
await buyer.deposit("10");                          // one-time Gateway deposit
const { data, transaction } = await buyer.pay(     // 402 → pay → retry, automatic
  "https://your-provider.railway.app/enrich?domain=acme.com"
);

MCP tools available to the agent once connected:

ToolWhat it does
find_serviceSearch the Obol marketplace by name or category
get_balanceCheck your Gateway USDC balance
depositDeposit USDC from your wallet into Gateway
pay_and_callPay for and call any Obol service URL

Dashboard guide

The dashboard at obol-arc.web.app/dashboard has two tabs: Use services (buyer) and Provide services (seller).

Wallet setup

Your Obol wallet is a self-custody EOA on Arc testnet powered by Circle User-Controlled Wallets (UCW). You hold the keys via a PIN — Obol never has custody.

To create:

  1. Go to Dashboard → Use services tab
  2. Click "Create my wallet →"
  3. Circle's PIN overlay appears — set a 6-digit PIN and three security questions
  4. Your Arc address appears and is saved to your profile automatically
  5. This address is your payout address for services you sell
Don't lose your PIN or security answers. They're the only way to recover your wallet. Obol cannot reset them.

Provide services tab

Everything a seller needs in one tab.

Earned
Total USDC you've received from all API calls across all services. Settled to your Arc wallet via Circle Gateway.
Calls served
Total number of paid API calls across all your listed services. Useful for tracking usage.
Active services
Number of services you've published to the marketplace.
Obol commission (0%)
Obol takes 0% per call — you keep 100% of the price you set. Obol monetizes via optional Featured/Scale subscriptions, not a per-call take rate.
Withdraw earnings
Move your earned USDC from your Arc wallet to any address on any supported network. Choose destination chain from the dropdown — Obol uses Circle CCTP to bridge if needed.
Your services
List of all services you've registered. Click + New service to add one.

Use services tab

The buyer view — fund your agent and monitor spending.

Gateway balance
Your unified USDC balance managed by Circle Gateway. This is what agents spend when they call paid APIs. Deposit here from any chain.
Total across chains
Total USDC you hold across all networks (Arc, Base, Ethereum Sepolia, etc.). Only Gateway balance can be spent on API calls — other chain balances need to be deposited first.
USDC by chain
Cards showing your balance on each chain with balance > 0, plus Arc always. Use Bridge → to move between chains. Use Deposit to Gateway to put Arc USDC into the unified balance.
Create my wallet
Sets up your UCW if you haven't already. Required before you can deposit, bridge, or withdraw.

Bridge & withdraw

Move USDC between chains and out of the platform.

Buyer dashboard — "Deposit to Gateway":
  Arc wallet → Circle Gateway unified balance
  Used to fund the agent's spending pool.
  Requires PIN confirmation (UCW).

Buyer dashboard — "Bridge →" on a chain card:
  Any chain → Any other chain
  Uses Circle CCTP behind the scenes.
  ~30 seconds to arrive.

Buyer dashboard — "Withdraw →" on Gateway balance card:
  Gateway balance → Any chain, any recipient address
  Pick destination network from dropdown (all 8 chains supported).

Seller dashboard — "Withdraw earnings":
  Your Arc wallet → Any address on any network
  Same cross-chain capability via CCTP.
  Enter recipient address manually.

Reference

Supported networks

Your unified USDC balance lives on Arc (where per-call payments settle). You can deposit from and withdraw to any network below — Obol bridges via Circle Gateway (EVM chains) or CCTP (Monad, Solana), gaslessly. 10 networks total.

NetworkChain keyUSDC address / SPL mintCCTP domain
Arc Testnet · settles herearc0x360000000000000000000000000000000000000026
Base Sepoliabase0x036CbD53842c5426634e7929541eC2318f3dCF7e6
Ethereum Sepoliaethereum0x1c7D4B196Cb0C7B01d743Fbc6116a902379C72380
Avalanche Fujiavalanche0x5425890298aed601595a70AB815c96711a31Bc651
OP Sepoliaoptimism0x5fd84259d66Cd46123540766Be93DFE6D43130D72
Arbitrum Sepoliaarbitrum0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d3
Polygon Amoypolygon0x41E94Eb019C0762f9Bfcf9Fb1E58725BfB0e75827
Unichain Sepoliaunichain0x31d0220469e10c4E71834a79b1f276d740d3768F10
Monad Testnetmonad0x534b2f3A21130d7a60830c2Df862319e593943A315
Solana Devnetsolana4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU5

Pricing & fees

FeeAmountWho paysWhere it goes
Obol commission0% per callYou keep 100%
Circle Gateway fee0% (testnet)
Gas (per call)$0 (gasless nanopayments)Circle covers settlement
Deposit gas (one-time)~$0.0014 on ArcDepositor funding their balanceNetwork
CCTP bridge fee~$0.001Initiator of the bridgeCircle/CCTP

Example: You set your price at $0.002/call. The agent pays exactly $0.002. You receive the full $0.002 (100%). Obol takes $0 per call — we monetize via optional Featured/Scale subscriptions, not your transactions.

✓ Proven on Arc testnet — real transactions
Weather API · $0.001/call
serviceFee $0.001 · commission $0 (0%) · gas $0
settlementTx 7f3bdec6-8bc6-4b8a-9f10-81aade1baaff
Nano endpoint · $0.000001/call (floor)
serviceFee $0.000001 · gasless · charged $0.000001
settlementTx 52e46668-482c-4374-a368-1f07cedbbfbb

To be clear: $0.000001 is the minimum payment (the smallest price a seller can charge) — not a gas fee. Gas is $0: buyers and sellers pay no gas at all. Nanopayments are offchain EIP-3009 signatures, batch-settled by Circle Gateway, so per Circle "neither party pays per-transaction fees".

Every pay-and-call receipt includes feeRate: "0%", gas: 0, and priceSource: "x402-endpoint" (the live per-endpoint x402 price was billed). You pay only the seller's price — Obol takes 0% commission.

HTTP 402 explained

HTTP 402 ("Payment Required") is the standard status code for paywalled content. Obol's middleware returns a 402 with a X-Payment-Required header containing Circle Gateway payment instructions. Compatible buyers (those using the GatewayClient SDK or the Obol MCP) handle this automatically.

# What an unpaid request looks like:
HTTP/1.1 402 Payment Required
X-Payment-Required: {
  "scheme": "circle-gateway",
  "network": "eip155:5042002",
  "maxAmountRequired": "2000",    // in USDC micro-units (6 decimals)
  "sellerAddress": "0xSeller...",
  "facilitatorUrl": "https://gateway-api-testnet.circle.com"
}

# The GatewayClient SDK reads this header, signs an off-chain EIP-3009
# authorization, submits to Circle Gateway, then retries the original
# request with a signed payment proof in the Authorization header.

Wallet types

Wallet typeUsed forHow it worksKeys
UCW (User-Controlled)Sellers, dashboard humansPIN overlay via Circle SDK. Human approves each spend.You hold via PIN
Agent EOA (raw private key)Buyers, AI agentsScript signs autonomously with OBOL_AGENT_KEY. No PIN, no popup.You hold private key
DCW (Developer-Controlled)Legacy Obol platform walletCircle holds keys server-side. Used before UCW was added.Circle holds
Why agents can't use UCW: UCW requires a human to enter a PIN for every spend. Agents run autonomously without human input. Agents use a raw EOA private key instead — they fund it, set OBOL_AGENT_KEY, and the SDK signs payments automatically.