A self-hosted rental server for courts, rehearsal rooms, meeting rooms and equipment. Browsing the calendar is free. $0.001 buys a signed, time-limited quote for an exact window; $0.02 reserves it and returns the gate, door or locker code — plus the window, the pricing breakdown, the terms and a calendar invite — in the same HTTP response. Pay in USDC on Base or Solana — your client picks the rail.
| Route | Price | The artifact you get back |
|---|---|---|
GET /inventory | free | Rentable items plus calendars — rates, peak hours, min/max blocks, access type, terms, busy windows, free block starts |
GET /quote | $0.001 | Signed, time-limited price: per-block lines with peak flags, total + totalAtomicUSDC, availability, terms, expiresAt, HMAC signature |
POST /reserve | $0.02 | {rentalId, accessCode, window, pricing, terms, cancelToken, ics (base64 invite), signature} |
POST /cancel/:id | free | Signed cancellation — block released, access code revoked (auth by cancelToken) |
GET /rentals/:id | free | The rental including its access code (auth by cancelToken) |
GET /.well-known/x402 | free | Machine-readable payment manifest for agents and indexers |
Every paid route returns the thing you bought in the 200 body. No pay-now-deliver-later.
POST /reserve with no payment. Server replies 402 with an accepts[] holding both rails — amount, token address and recipient on Base and on Solana.
Base: sign an EIP-3009 USDC authorization. Solana: sign an SPL transferChecked. Retry with the X-PAYMENT header; that rail's facilitator verifies and settles on the chain you chose.
200 with the rental and its access code in the body and a settlement receipt in X-PAYMENT-RESPONSE, naming the rail. Settlement only runs on success.
import { wrapFetchWithPayment } from "x402-fetch";
import { privateKeyToAccount } from "viem/accounts";
const payFetch = wrapFetchWithPayment(fetch, privateKeyToAccount(PRIVATE_KEY));
// browsing is free — no wallet needed
const inv = await fetch("http://localhost:4024/inventory?days=7").then(r => r.json());
// $0.001: a signed price for the exact window
const quote = await payFetch(
"http://localhost:4024/quote?item=court-1&date=2026-08-08&start=18:00&blocks=2"
).then(r => r.json());
console.log(quote.total, quote.lines); // $0.06, two peak blocks
// $0.02: reserve it, echoing the quote so the price is pinned
const rental = await payFetch("http://localhost:4024/reserve", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ name: "Agent Ada", quote }),
}).then(r => r.json());
console.log(rental.accessCode, rental.window, rental.ics);
Booking-grid flow with the drop-in payment modal — pick a window, buy a signed quote, reserve with Phantom (Solana) or MetaMask (Base), and the gate code appears on screen.
public/index.html →skill.md + .well-known/x402 discovery, MCP tool wrapper for Claude, listing on x402scan / Bazaar.
agents.md →Every endpoint with params, prices, schemas, and error cases. OpenAPI 3.1 included.
api.md →