a obolium

Docs

How obolium works

Three primitives: x402 for the HTTP payment protocol, USDC on Base for settlement, and an immutable Solidity reputation contract for portable ratings.

Overview

obolium turns any HTTP endpoint into a paid product. The buyer pays in USDC, the seller's service runs, and the marketplace deducts a 3% fee on-chain via an immutable Solidity contract. Ratings are anchored to actual payments, so reputation is portable — anyone can read it without trusting the marketplace.

Marketplace facts

  • Network
    Base Sepolia
  • Settlement
    USDC
  • Marketplace fee
    3%
  • Signup
    None

Quick start

Three ways to buy: the browser UI, the CLI, or the MCP server (for AI agents).

  1. 1 Fund a wallet from the Base Sepolia faucet (ETH for gas + USDC for purchases).
  2. 2 Browse the directory, pick a product, hit Buy.
  3. 3 One USDC transfer settles on-chain. The endpoint runs and returns a result + receipt. Rate it from your orders when you're satisfied.

For buyers

Buyers connect a wallet (no signup), browse the marketplace, and click Buy. Each call is settled in USDC on Base. Three ways to hit the marketplace, depending on whether you're a person, a script, or an AI agent.

Browser

Connect any wallet (Coinbase Wallet, MetaMask, WalletConnect-compatible) at /browse. The wallet chip in the header shows your USDC and ETH balance — you need a little ETH for gas and enough USDC for the product. Spend caps and approvals are visible in your wallet popup before signing.

CLI

shell
# Configure once. Wallet must hold USDC on Base.
$ export OBOLIUM_PRIVATE_KEY=0x...
$ export OBOLIUM_DAILY_LIMIT=5.00

# Pay any capability in one line.
$ obolium-cli pay \
    --url https://api.chefbot.example/recipe-suggest \
    --body '{"ingredients": ["pasta", "garlic"]}'

200 OK
{ "recipe": "Garlic pasta in 12 minutes...",
  "receipt": { "payment_tx": "0xabc...", "seller_sig": "0x..." } }

MCP (for AI agents)

Add the obolium MCP server to Claude Desktop (or any MCP-compatible client). The agent gets live discovery, pre-flight wallet checks, and budget-capped payments — all routed through the marketplace API so backend errors trigger an automatic on-chain refund. The wallet you point at OBOLIUM_PRIVATE_KEY needs USDC for purchases and a little ETH for gas; nothing else needs to be reachable from the internet.

shell
# ~/Library/Application Support/Claude/claude_desktop_config.json
# (Linux: ~/.config/Claude/claude_desktop_config.json,
#  Windows: %APPDATA%\Claude\claude_desktop_config.json)
{
  "mcpServers": {
    "obolium": {
      "command": "/absolute/path/to/obolium-mcp",
      "env": {
        "OBOLIUM_PRIVATE_KEY": "0x...",
        "OBOLIUM_RPC": "https://sepolia.base.org",
        "OBOLIUM_MARKETPLACE_API": "https://api-staging-obolium.hubje.nl"
      }
    }
  }
}

# Tools the agent gets:
#   list_marketplace      — live discovery of all hosted shops + capabilities
#   wallet_status         — USDC + ETH balance, so the agent can self-check
#   pay_call              — marketplace-routed: pass seller_id + capability_id
#   fetch_manifest        — peer-to-peer fallback for self-hosted shops
#   get_agent_reputation  — read on-chain rating history before paying
#   rate_agent            — anchor a 0-5 rating to a payment tx

# Restart Claude Desktop, then ask:
#   "Discover obolium sellers, pick a writing shop, and paraphrase this
#    paragraph. Spend up to $0.10. Refund if it errors."

Build the binary from this repo with cargo build --release -p obolium-mcp — point Claude's command field at target/release/obolium-mcp. Every payment lands in /orders just like a browser buy, so you can audit what the agent spent.

What you receive

On a successful payment the seller's HTTP response is returned to you verbatim, plus an EIP-712 signed receipt:

  • ·JSON data — most capabilities return structured JSON. The browser shows it in the Buy card; the CLI prints it; agents parse it.
  • ·Downloads / images — sellers commonly return a short-lived URL ({"url": "https://...", "content_type": "image/png"}). The browser surfaces a Download / Open button; the CLI prints the URL.
  • ·Premium content — markdown / HTML / audio responses render natively in the Buy card.
  • ·Receipt — every response includes a signed receipt binding your wallet, the payment tx, the amount, and a hash of the response. Verifiable by anyone, anywhere.

Every purchase is persisted to /orders — your private order history with the full response body and a re-link to the receipt + basescan tx. Refunded calls show up there too, with a Refunded badge and a link to the on-chain refund tx (see Refunds).

Sellers — hosted shop

The easiest path. obolium runs the seller-svc for you; all you need to provide is the backend HTTP service that does the actual work, and an EOA wallet that receives the payments. The seven demo shops you can browse on this site all use this path.

What your backend must look like

A regular HTTP service with two requirements: a GET /health that returns 2xx (used as a pre-flight check before quoting buyers), and one route per capability that takes POST with a JSON body and returns JSON. That's it — no auth, no x402 plumbing, no signing. obolium does that part.

python
# pip install flask
from flask import Flask, request
app = Flask(__name__)

@app.get("/health")
def health():
    return "ok", 200

@app.post("/my-shop/summarize")
def summarize():
    body = request.get_json()
    text = body.get("text", "")
    # Your real work goes here — call an LLM, query a DB, whatever.
    return {
        "summary": text[:140] + ("…" if len(text) > 140 else ""),
        "word_count": len(text.split()),
    }

# Run on any port reachable from obolium's seller-svc.
# obolium calls POST <your-host>/my-shop/summarize with the buyer's JSON.

Same shape in any stack — here it is in Node:

js
// npm i express
import express from "express";
const app = express();
app.use(express.json());

app.get("/health", (_req, res) => res.send("ok"));

app.post("/my-shop/summarize", (req, res) => {
  const { text = "" } = req.body;
  res.json({
    summary: text.slice(0, 140),
    word_count: text.split(/\s+/).length,
  });
});

app.listen(8000);

Onboarding checklist

  1. 1 Have an EOA wallet on Base. This is your operator wallet — every successful payment lands in it (minus the on-chain marketplace fee). Keep enough ETH in it for occasional refund transactions; see Refunds.
  2. 2 Deploy your backend somewhere obolium can reach. A publicly-routable URL works; if you're running on the same cluster as obolium, the cluster-internal DNS name is enough.
  3. 3 Sign in at /sell with your operator wallet, then add capabilities — each one names a route on your backend and the price per call.
  4. 4 Your shop appears on /browse. Buyers pay; USDC arrives in your wallet; receipts are signed automatically.

Long-running capabilities

If your backend takes more than a couple of seconds — image generation, slow LLM calls, batch processing, transcription — flip Async on the capability in /sell. The flow then becomes:

  1. 1 Buyer pays as usual. seller-svc verifies the on-chain payment, persists a jobs row, and returns 202 Accepted with a job_id immediately — your backend hasn't been called yet.
  2. 2 seller-svc runs the request against your backend in a background task. Your backend stays synchronous — it still does its work and returns JSON when done. No protocol change on your side.
  3. 3 The buyer's browser (or MCP agent) polls /api/jobs/{job_id} until the upstream completes. On error, the existing auto-refund path runs and the job row is marked failed with the on-chain refund tx.

Set Estimated response (ms) alongside Async — the buyer card shows the ETA in the Processing badge, and the marketplace's poll deadline scales off it (6× the ETA, clamped to 1–10 minutes).

Webhook delivery (optional). Buyers can pass callback_url on POST /api/pay/complete (MCP agents pass it on pay_call). When the async job finishes — success or failure — seller-svc POSTs the final payload to that URL. Body mirrors the polling shape: { job_id, status, payment_tx, capability_id, result?, receipt?, error?, refund_tx_hash? }. Delivery is best-effort with a 10s timeout and no retries; polling /api/jobs/{job_id} stays authoritative. Must be http(s), max 2048 chars.

Hosted shops trade some sovereignty for convenience: obolium holds the signing keys for x402 receipts, and your backend ultimately needs to be reachable from the obolium cluster. If that's a dealbreaker, see self-hosted below.

Sellers — self-hosted

Full sovereignty. You run your own obolium-seller binary on your own infrastructure. It holds your operator key, talks to Base RPC directly, signs its own receipts, and serves its own /.well-known/agent.json manifest. obolium just discovers and lists you.

shell
# 1. Run seller-svc with your operator wallet's private key.
$ export OBOLIUM_PK=0x...
$ export OBOLIUM_TOKEN=0x036CbD53842c5426634e7929541eC2318f3dCF7e
$ export OBOLIUM_MARKETPLACE_SPLITTER=0xFc9C083b71fca6aBcd70dbA95887f48401B8691A
$ export OBOLIUM_BIND=0.0.0.0:7402
$ obolium-seller

# 2. Sign in at https://obolium.example/sell with the same wallet, then
#    register your shop by base URL. obolium fetches your manifest,
#    confirms the operator_wallet field matches your signed-in wallet,
#    and indexes your capabilities.

Your backend requirements are the same as the hosted case (JSON in, JSON out, /health). The difference is that the seller-svc binary lives on your side of the wire, so your private key never leaves your machine. If you'd prefer to write the seller side from scratch (different language, different architecture), the only contract that matters is the x402 handshake — see Manifest format and Payment & receipts.

Manifest format

Every seller-svc serves /.well-known/agent.json describing the shop and its products. Marketplaces (this one and others) read it on each refresh tick.

json
{
  "name": "ChefBot Kitchen",
  "version": "0.3.0",
  "operator_wallet": "0x44209a...d8890e",
  "capabilities": [
    {
      "id": "recipe-suggest",
      "description": "Suggest a recipe from ingredients",
      "category": "Food",
      "endpoint": "/recipe-suggest",
      "input_schema": { "type": "object", ... },
      "output_schema": { "type": "object", ... },
      "pricing": {
        "currency": "USDC",
        "chain": "base-sepolia",
        "amount_base_units": "10000"
      },
      "image_url": "https://...",
      "flags": ["uses_llm", "processes_user_text"]
    }
  ]
}
  • ·operator_wallet — must match the wallet that signs in to claim the shop.
  • ·pricing.amount_base_units — USDC base units (6 decimals). "10000" = $0.01.
  • ·flags — non-binding hints. Recognized: uses_llm, accepts_urls, processes_user_text, stateful, deterministic.
  • ·image_url — optional, surfaced on the product card.

Payment & receipts

The wire format is plain x402: HTTP 402 with a quote, then a header carrying the on-chain payment proof.

shell
1. Buyer GETs /well-known/agent.json and discovers /recipe-suggest @ $0.01
2. Buyer POSTs to /recipe-suggest with body — server returns 402 + quote.
3. Buyer signs a USDC pay() through the marketplace splitter on Base.
4. Buyer re-POSTs with X-PAYMENT: <base64 receipt> header.
5. Seller verifies the on-chain transfer, runs the work, signs an EIP-712
   receipt, returns 200 + result.

The receipt is an EIP-712 message signed by the seller wallet, binding the buyer, the capability, the amount, and a hash of the response. Aggregators don't need to trust the marketplace to verify it.

Refunds

A buyer pays before the work runs. If the seller's backend errors mid-call, obolium auto-refunds the buyer with a USDC transfer from the seller's wallet — no manual claim, no support ticket. Two layers protect the buyer:

  1. 1 Pre-flight health probe. Before quoting, obolium hits the seller's /health. If it doesn't return 2xx within 2 seconds, the quote is refused and the buyer doesn't pay at all.
  2. 2 Auto-refund on failure. If the backend returns an error after payment, the seller-svc broadcasts a USDC transfer back to the buyer for the seller's share (97% — the 3% marketplace fee stays in the treasury and is non-refundable in v1). The buyer sees an amber "Refunded" card in the Buy flow and a Refunded badge in /orders with the on-chain refund tx.

If the refund itself fails — typically because the seller's wallet is out of ETH for gas — the order is marked "Refund failed" in /orders with the failure reason. The buyer can quote the payment tx hash to contact the seller for a manual claim. Sellers running a hosted shop should keep a small ETH balance in their operator wallet to cover refund gas; the cost is < $0.001 per refund on Base.

On-chain reputation

A rating is a single transaction calling rate(agent, paymentTx, stars, commentHash) on the Reputation contract. The contract emits a Rating event; any indexer can aggregate it.

  • ·Anchored. The paymentTx ties the rating to an actual on-chain payment — fakes don't verify.
  • ·Portable. Any marketplace can read the same events.
  • ·Commit-only. Comment text is hashed on-chain; plaintext lives off-chain so it can be retracted, while the rating itself is immutable.

Contracts

Deployed on Base Sepolia (chain id 84532). All addresses verifiable on Basescan.

MarketplaceSplitter

Routes payments; enforces the 3% fee on-chain.

0xFc9C083b71fca6aBcd70dbA95887f48401B8691A

Reputation

Stores Rating events anchored to payment tx hashes.

0xe030006bFa036a0160FAe80601c962321518805e

Treasury

Marketplace owner wallet — receives the fee.

0x7ad1882e926a4C26F66247e2dE029A74307dd9de

USDC (Base Sepolia)

Official Circle testnet USDC.

0x036CbD53842c5426634e7929541eC2318f3dCF7e

Source: gitea.hubje.nl/brian/obolium