Documentation

Build on theopay.xyz

Everything you need to wrap an API, sell per-call access, and let humans or agents pay. The rail follows the Coinbase x402 spec; settlement is USDC on Solana.

Overview

theopay.xyz is a hosted facilitator, proxy, and marketplace for x402 — the open standard for charging per HTTP request. Point us at your existing API and a price; we give you a gated proxy URL. When a buyer (human or agent) calls it, we issue an HTTP 402, verify their on-chain payment, and forward the request to your origin.

Base URL
theopay.xyz
Settlement
USDC · Solana
Margin
1% per call
Endpoint shapes below follow the x402 spec and are the planned theopay.xyz API surface. Always verify the exact handshake and headers against the current Coinbase x402 docs.

Quickstart

Call any gated endpoint with an x402-aware client. It intercepts the 402, signs the payment with your wallet, and retries — your code just sees a normal 200.

typescript · x402-fetch
import { wrapFetchWithPayment } from "x402-fetch";
import { createSolanaWallet } from "x402-fetch/solana";

const wallet = createSolanaWallet(process.env.AGENT_SOLANA_KEY!);
const fetchWithPay = wrapFetchWithPayment(fetch, wallet);

const res = await fetchWithPay("https://theopay.xyz/x/fetch-x-post?id=1789…");
const data = await res.json(); // → { author: "@levelsio", text: "…", … }

The x402 flow

  1. 1.A client (human or agent) requests a gated endpoint with no payment.
  2. 2.theopay.xyz responds 402 Payment Required + amount, asset, chain, and payTo.
  3. 3.The client signs a USDC payment on Solana and re-sends with the X-PAYMENT header.
  4. 4.theopay.xyz verifies the payment on-chain.
  5. 5.We forward to your origin and stream back the response.
the handshake
# 1) No payment → challenge
GET /x/fetch-x-post HTTP/1.1

HTTP/1.1 402 Payment Required
{
  "x402": {
    "amount": "2000",        // 0.002 USDC (6 decimals)
    "asset": "USDC",
    "chain": "solana",
    "payTo": "Theo…Treasury",
    "resource": "/x/fetch-x-post"
  }
}

# 2) With payment → success
GET /x/fetch-x-post HTTP/1.1
X-PAYMENT: <signed-solana-payment-authorization>

HTTP/1.1 200 OK
{ "author": "@levelsio", "text": "shipped a new feature 🚀", "likes": 4210 }

Core concepts

Listing
An API you've wrapped: an origin URL + a per-call price. Each listing gets a public slug and a gated proxy URL at /x/{slug}.
Gated proxy
The URL we host in front of your origin. It enforces payment, then forwards the request and streams back your origin's response.
Facilitator
The component that issues the 402 challenge and verifies the on-chain payment before releasing the response. theopay.xyz runs it for you.
Payment authorization
A signed Solana payment the client sends in the X-PAYMENT header. It both pays for and authorizes the request — no account needed.
Settlement
USDC moves on Solana per call to your treasury wallet, minus the flat 1% margin. Fast, cheap, deterministic finality.

Authentication

Two audiences, two models. Buyers and agents have no account — calls are authorized by a signed Solana payment in the X-PAYMENT header. Sellers manage listings with a bearer API key.

seller auth
curl https://theopay.xyz/api/v1/listings \
  -H "Authorization: Bearer tm_live_xxxxxxxxxxxx"

Gated proxy

Every listing is reachable at a gated proxy path. Call it like the underlying API — we handle payment, then forward your request (method, headers, body) to the origin and stream back the response.

GET/x/{slug}

Call a gated endpoint

Proxies to the seller's origin. Returns 402 until a valid payment header is present, then 200 with the origin's response.

Parameters

  • slugstringrequiredThe listing's public slug, e.g. fetch-x-post.
  • X-PAYMENTheaderoptionalSigned Solana payment authorization. Omit to receive the 402 challenge.
pay → 200
const res = await fetchWithPay("https://theopay.xyz/x/fetch-x-post");
// 402 → pay → retry happens automatically
const data = await res.json();

Listings

Programmatically manage the APIs you sell. All routes require a seller bearer token.

GET/api/v1/listings

List your listings

Returns all listings owned by the authenticated seller.

POST/api/v1/listings

Create a listing

Wrap an origin URL in x402 and get back a gated proxy URL.

Parameters

  • namestringrequiredDisplay name shown in the marketplace.
  • origin_urlstringrequiredYour real API endpoint to proxy to.
  • price_usdcnumberrequiredPrice charged to the buyer per call, in USDC.
  • categorystringoptionalMarketplace category, e.g. data, ai, finance.
create listing
curl -X POST https://theopay.xyz/api/v1/listings \
  -H "Authorization: Bearer tm_live_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Fetch X Post",
    "origin_url": "https://api.yoursite.com/v1/x-post",
    "price_usdc": 0.002,
    "category": "data"
  }'

# → { "id": "lst_123", "slug": "fetch-x-post",
#     "proxy_url": "https://theopay.xyz/x/fetch-x-post" }
PATCH/api/v1/listings/{id}

Update a listing

Change the price, origin, name, or category of a listing.

Parameters

  • idstringrequiredThe listing ID.
DELETE/api/v1/listings/{id}

Delete a listing

Permanently removes a listing and disables its proxy URL.

Parameters

  • idstringrequiredThe listing ID.

Transactions

Read the per-call payment record for your listings — for earnings, analytics, and reconciliation.

GET/api/v1/transactions

List transactions

Paginated payment records across your listings, newest first.

Parameters

  • listing_idstringoptionalFilter to a single listing.
  • limitnumberoptionalPage size (default 50, max 200).
  • cursorstringoptionalPagination cursor from a previous response.
transaction object
{
  "id": "txn_abc123",
  "listing_id": "lst_123",
  "amount_usdc": 0.002,
  "fee_usdc": 0.00002,
  "net_usdc": 0.00198,
  "chain": "solana",
  "signature": "5f…onchainSig",
  "status": "settled",
  "created_at": "2026-06-15T10:00:00Z"
}

Errors

theopay.xyz uses conventional HTTP status codes. The body is always JSON with an error object.

400Bad request — a parameter is missing or malformed.
401Missing or invalid seller API key.
402Payment required — pay and retry with X-PAYMENT.
404Listing or resource not found.
429Rate limited — slow down and retry.
502The seller's origin returned an error or timed out.

Pagination

List endpoints are cursor-paginated. Pass limit (max 200) and the next_cursor from the previous response as cursor to fetch the next page. When next_cursoris null, you've reached the end.

paginated response
GET /api/v1/transactions?limit=50

{
  "data": [ /* … */ ],
  "next_cursor": "txn_abc123",   // pass as ?cursor= for the next page
  "has_more": true
}

Rate limits

The management API is limited per API key. Paid proxy calls aren't rate-limited by us beyond your origin's own limits. Every response includes the headers below; on 429, back off and retry after Retry-After seconds.

X-RateLimit-LimitRequests allowed per window.
X-RateLimit-RemainingRequests left in the current window.
X-RateLimit-ResetUnix time when the window resets.

Webhooks

Subscribe to transaction.settled to get a signed POST to your endpoint on every paid call — useful for ledgers, alerts, and provisioning. Verify the X-Theo-Signature header against your webhook secret.

webhook payload
POST https://your-app.com/webhooks/theomarket
X-Theo-Signature: t=1718446800,v1=5f2c…

{
  "event": "transaction.settled",
  "data": {
    "id": "txn_abc123",
    "listing_id": "lst_123",
    "net_usdc": 0.00198,
    "signature": "5f…onchainSig"
  }
}

SDKs & tools

x402-fetch (TypeScript)

Drop-in fetch wrapper that auto-resolves 402s. The fastest path for JS/TS agents.

REST API

Language-agnostic. Manage listings and read transactions over plain HTTP with a bearer key.

Solana wallet adapters

Phantom, Solflare, Backpack, and embedded wallets all work for signing payments.

Webhooks

Push transaction events to your own infrastructure for ledgers and provisioning.

Testing

Use a Solana devnet wallet and a devnet USDC mint to exercise the full 402 → pay → 200 loop without spending real funds. Point your client at the devnet RPC and fund the wallet from a faucet.

devnet config
// point your client at Solana devnet
const wallet = createSolanaWallet(DEVNET_KEY, {
  rpcUrl: "https://api.devnet.solana.com",
});
// fund it: solana airdrop 1 <address> --url devnet
const res = await fetchWithPay("https://theopay.xyz/x/fetch-x-post");
Ready to integrate for real? Start at the agent quickstart or list an API.