Examples

A paid API, a paid MCP tool, and an agent paying for both.

A paid JSON API (Node)

import express from "express";
import { createX402Xrpl, sqliteStore } from "@openwallet/x402-xrpl";

const x402 = createX402Xrpl({
  network: "xrpl:1",                               // Testnet while you build
  payTo: "rYourTestnetAddress…",
  rpc: "https://s.altnet.rippletest.net:51234",
  store: sqliteStore("./x402.db"),
});

const app = express();
app.get("/v1/quote",
  x402.http({ price: { asset: "XRP", drops: "10000" }, description: "One quote" }),
  (req, res) => res.json({ quote: "Plain words beat clever ones." }));
app.listen(8080);

The same on Cloudflare Workers

import { createX402Xrpl } from "@openwallet/x402-xrpl";

export default {
  async fetch(request, env) {
    const x402 = createX402Xrpl({
      network: "xrpl:1",
      payTo: env.PAY_TO,
      rpc: "https://s.altnet.rippletest.net:51234",
      store: env.STORE,                            // a store with an atomic claim
    });
    const r = await x402.handle(request, {
      price: { asset: "RLUSD", value: "0.01" },
      description: "One quote",
    });
    if (!r.paid) return r.response;                // the 402 challenge, or a failure
    return r.finish(Response.json({ quote: "Plain words beat clever ones." }));
  },
};

A paid MCP tool

import { McpServer } from "@modelcontextprotocol/server";
import { createX402Xrpl, memoryStore } from "@openwallet/x402-xrpl";

const server = new McpServer({ name: "summaries", version: "1.0.0" });
const x402 = createX402Xrpl({
  network: "xrpl:1",
  payTo: "rYourTestnetAddress…",
  rpc: "https://s.altnet.rippletest.net:51234",
  store: memoryStore(),                            // one process only; use sqlite or redis in production
});

x402.mcpPaidTool(server, "summarise", {
  price: { asset: "XRP", drops: "20000" },
  description: "Summarise a text in three sentences",
  inputSchema: { type: "object", properties: { text: { type: "string" } }, required: ["text"] },
}, async ({ text }) => ({ content: [{ type: "text", text: summarise(text) }] }));

An agent paying for both

With an AI app connected to OpenWallet, the model makes these calls. It never gives a destination or signs anything itself. On the remote server, the user approves each payment in the extension; with the desktop agent, small payments to approved merchants go through without a prompt.

// The HTTP API
// tools/call openwallet_pay_x402
{ "url": "https://api.example.com/v1/quote",
  "reason": "The user asked for a quote",
  "task": "Get me a quote from api.example.com" }

// The remote paid MCP tool
// tools/call openwallet_call_paid_mcp_tool
{ "server_url": "https://mcp.example.com/mcp",
  "tool": "summarise",
  "arguments": { "text": "…" },
  "max_amount": { "asset": "XRP", "amount": "20000" },
  "reason": "The user asked for a summary" }

Each result has status, the resource or tool result in untrusted_ fields, and a receipt with the transaction hash and an explorer link.