ScriptMasterLabs.com · 402Proof Starter Kit
How do I accept x402 payments on XRPL or Xahau?
Copy the middleware for your stack — Express or FastAPI — set your wallet, add your partner key, and deploy. Your route answers a standards-shaped x402 v2 402 challenge on XRPL (xrpl:0) or Xahau (xrpl:21337) and settles through 402Proof, Script Master Labs' facilitator for the XRPL family. The door is partner-keyed by design — the XRPL fee accrues per settlement instead of being collected inside it, so keys are issued to known sellers (one email, reply within one business day). Your buyers pay your own wallet directly; your first settlement lists your resource in 402Proof's discovery index. This kit is the XRPL-family twin of the OMNIGATE starter kit, and the integration the seller offer on /settle-through-sml points at.
Get the kit Request a partner key All rails & fees — the seller offer
Pricing at a glance
XRPL — standard x402 v2, network xrpl:0, native XRP. The facilitator fee is $0.0100 USD per completed settlement. The fee is accrued on a merchant ledger, not collected at settlement (402Proof's pricing publishes automaticCollectionLive: false — accrued, not collected cash). The fee is never deducted from your buyer's payment. Loyalty discounts apply per merchant on prior successful settlements: 100+ settlements → $0.0080 per settlement (20% discount); 1,000+ → $0.0070 (30%); 10,000+ → $0.0050 (50%). Verification, failed settlements, indeterminate settlements and exact replays are free. No subscription is required. A partner key is required. Terms verified live on 2026-11-04 at the sidecar's pricing.json.
Xahau — standard x402 v2, network xrpl:21337, native XAH. The facilitator fee is a flat 0.01 XAH per third-party settlement — exactly 10,000 drops — charged from the first settlement, with no free-settlement allowance. On Xahau the fee is collected at settlement: the payer signs a second native Payment of 10,000 drops to the facilitator fee recipient rEmdJWrAWFtud1vFN8Zm8eWkgK4AVMWPiX, carried in the payment payload as feeTxBlob and bound to the payment by a memo. Your price is paid to your own payTo wallet in full; the merchant amount is never reduced by the fee. Payments to the fee recipient itself (Script Master Labs' own routes) are exempt and carry no fee leg.
Two neighbouring rails, priced separately so nothing is blurred: 402Proof's invoice rail (the main service's product-specific invoice API: invoice → payer-submitted on-chain payment → verification → access token) charges 0.01 in the invoice's own asset per verified settlement — that is how RLUSD- and USDC-denominated XRPL sales settle. The same sidecar also settles standard x402 v2 on Solana at a flat 0.005 USDC per settlement, collected in-transaction. Each rail keeps its own fee model; none is averaged into another.
Every snippet below was test-run on 2026-11-04: unpaid calls answer the exact 402 challenge shape published in 402Proof's live discovery index, a fabricated payment is refused by the live /verify and surfaces as a fresh 402, and the Xahau fee-leg builder's signed blobs were decoded and checked field by field. The dated proof is in the proof section.
The only Xahau facilitator we can find — checked 2026-11-04
Xahau support is the reason this kit exists. The official x402 facilitator list (docs.x402.org; 19 production facilitators at Script Master Labs' 2026-10-30 review) contains no Xahau entry at all — XRPL appears exactly once (T54), and T54 settles XRPL only. On 2026-11-04 we searched again — the official lists, the public facilitator registries, and the web — and found no other facilitator publishing a Xahau (xrpl:21337) /supported or discovery index. As of that check, 402Proof is the only Xahau x402 facilitator we can find, and it publishes its terms, its discovery index and its settlement evidence in public. The rail is still early — that is precisely when a default gets set, and this kit is the default we are offering. If another Xahau facilitator surfaces, this section gets corrected with a date, the same way our index-health page corrects our own listings.
What you get
1 · Settlement on XRPL and Xahau, to your own wallet. The buyer pays your payTo directly with their own signed transaction. The facilitator validates and submits payer-signed payloads — it signs nothing, holds nothing, and never takes custody of your money. Your server never talks to a chain directly.
2 · An automatic discovery listing. The sidecar's /discovery/resources index is the facilitator's own record of registered, settling resources — 20 resources at the 2026-11-04 live read. When a payment for your resource settles through 402Proof, your resource belongs in that index. No submission form, no review queue, no separate listing fee.
3 · Federation into the public aggregation. The sidecar index is one of the sources read by Script Master Labs' /x402-directory aggregation — 16,963 resources across all of its sources at the 2026-11-03 read — and the indexes are re-probed daily on the public /x402-index-health page, so a listing that rots gets caught in public, including ours.
4 · A fee ledger you can read yourself. Because the XRPL fee accrues, you can audit it: GET /v1/partners/usage on the sidecar, under your own key, shows your successful settlements, the discount tier your next settlement gets, and your accrued fees — labeled collectionStatus: "not_collected" in the response itself. Accrual you can inspect is the opposite of a surprise invoice.
How the flow works
- Request a key. Email tim@scriptmasterlabs.com with your service's base URL, the rail, and your receiving wallet (the partner-key block). You receive a one-time invite token, good for 48 hours.
- Activate. POST the invite token to the sidecar's
/v1/partners/activate, accepting the published fee schedule. Thep402_…key it returns is shown once — store it server-side. - Challenge. A buyer calls your route with no payment header. Your server answers HTTP 402 with the challenge — your price in drops, your wallet, a fresh
invoiceId— in the JSON body and base64-encoded in thePAYMENT-REQUIREDheader. - Signature. The buyer's x402 v2 client signs a native Payment for your price and retries with the
PAYMENT-SIGNATUREheader. On Xahau it also signs the 0.01 XAH fee leg and attaches it aspayload.feeTxBlob, memo-bound to the invoice. - Verify. Your server forwards the payload to 402Proof's
POST /verifyunder your partner key — free and read-only. An invalid payment, or a Xahau payment missing its fee leg, is refused here; a refusal submits nothing. - Settle. Your server calls
POST /settle— at most once per payment. 402Proof submits the buyer's signed transaction: your price lands in your payTo (on Xahau, the fee leg lands in the fee recipient in the same flow). - Serve + get indexed. Deliver the resource only on
success: truewith an XRPL-family transaction hash, with aPAYMENT-RESPONSEheader carrying the settlement result — and your resource is now a row in the discovery index.
The kit
Three snippets. The middleware (Express or FastAPI) is the seller side: it answers the challenge and runs verify/settle for both rails — XRPL is wired as the example route, and the Xahau requirements object sits in the same file, a one-word switch (requirePayment("xahau", …)). The third snippet is the buyer side of Xahau: the fee-leg builder your payer clients need. The only values you change are PAY_TO (your wallet), PRICE_DROPS (your price in drops — 1 XRP or 1 XAH is 1000000), and the PROOF402_PARTNER_KEY environment variable.
Express (Node 18+) — the resource server
// ─── x402 starter kit: Express — XRPL + Xahau via 402Proof ────────────────
// One paid route, settled through 402Proof (Script Master Labs' facilitator
// for the XRPL family). Requires: npm i express (Node 18+ for global fetch)
//
// 402Proof is PARTNER-KEYED by design — the XRPL facilitator fee accrues per
// settlement instead of being collected inside it, so keys are issued to
// known sellers. Get yours first (reply within one business day):
// email tim@scriptmasterlabs.com with (1) your service's base URL,
// (2) the rail — XRPL RLUSD, XRPL USDC or Xahau XAH — and
// (3) your receiving wallet address.
// Then activate the invite token you receive:
// POST https://four02proof-x402-v2-xrpl.onrender.com/v1/partners/activate
// { "inviteToken": "inv402_…", "acceptFeeUSDCents": 1 }
// The p402_… key it returns is shown ONCE — store it server-side only.
//
// Verified 2026-11-04 against 402Proof's live /supported + /pricing.json on
// both hosts, the live discovery-index accepts objects, and live /verify
// refusal behavior (see the kit page's proof section).
import express from "express";
const FACILITATOR = "https://four02proof.onrender.com"; // 402Proof (standard x402 v2)
const PARTNER_KEY = process.env.PROOF402_PARTNER_KEY; // p402_… — server-side only, never ship to a browser
const PAY_TO = "rYourReceivingWallet"; // ← your XRPL/Xahau wallet: buyer payments land here directly
const PRICE_DROPS = "1000000"; // 1 XRP (or 1 XAH) — drops: 1 XRP = 1,000,000 drops
// A fresh invoiceId per challenge — your partner key is scoped to your
// payTo, your resource origin, your amount ceiling and the invoiceId.
const newInvoiceId = () =>
"inv-" + Date.now().toString(36) + "-" + Math.random().toString(16).slice(2, 10);
// ── Rail 1: XRPL mainnet (xrpl:0), native XRP ──────────────────────────────
// Requirements shape copied from 402Proof's live discovery index (2026-11-04).
// XRPL carries NO fee leg in the buyer's transaction: the facilitator fee
// ($0.0100 per settlement, loyalty-discounted) accrues on a separate merchant
// ledger — read yours any time at GET /v1/partners/usage on the sidecar.
function xrplRequirements() {
return {
scheme: "exact",
network: "xrpl:0",
asset: "XRP",
amount: PRICE_DROPS,
payTo: PAY_TO,
maxTimeoutSeconds: 300,
extra: { areFeesSponsored: false, invoiceId: newInvoiceId() },
};
}
// ── Rail 2: Xahau (xrpl:21337), native XAH ─────────────────────────────────
// Same middleware, one different requirements object. On Xahau the fee IS
// collected at settlement: the buyer's client signs a SECOND native Payment
// of exactly 10,000 drops (0.01 XAH) to the facilitator fee recipient and
// carries it in the payload as feeTxBlob, bound by a memo (see the payer
// snippet on the kit page). Your amount is never reduced by the fee.
// Payments to the fee recipient itself (SML's own routes) are exempt.
const XAHAU_FEE_RECIPIENT = "rEmdJWrAWFtud1vFN8Zm8eWkgK4AVMWPiX";
function xahauRequirements() {
return {
scheme: "exact",
network: "xrpl:21337",
asset: "XAH",
amount: PRICE_DROPS,
payTo: PAY_TO,
maxTimeoutSeconds: 300,
extra: {
areFeesSponsored: false,
invoiceId: newInvoiceId(),
facilitatorFee: "10000", // drops — flat 0.01 XAH per third-party settlement
facilitatorFeeRecipient: XAHAU_FEE_RECIPIENT,
},
};
}
const REQUIREMENTS_FOR = { xrpl: xrplRequirements, xahau: xahauRequirements };
function challenge(url, description, requirements) {
return {
x402Version: 2,
error: "payment_required",
resource: { url, description, mimeType: "application/json" },
accepts: [requirements],
};
}
async function facilitator(path, paymentPayload, requirements) {
const r = await fetch(FACILITATOR + path, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${PARTNER_KEY}`, // your scoped partner key
},
body: JSON.stringify({ x402Version: 2, paymentPayload, paymentRequirements: requirements }),
});
const text = await r.text();
try {
return JSON.parse(text);
} catch {
// e.g. 401 with an empty body when the key is missing or wrong — a
// refusal, not a crash: surface it as an invalid payment (fresh 402).
return { isValid: false, success: false, invalidReason: `facilitator_http_${r.status}` };
}
}
// The buyer's payload is an official x402 v2 envelope: payload.signedTxBlob
// is the buyer's own signed XRPL/Xahau Payment (plus payload.feeTxBlob on
// Xahau). You forward it exactly as received — your server holds no keys
// for settlement and never talks to a chain directly.
export function requirePayment(rail, description) {
const makeRequirements = REQUIREMENTS_FOR[rail];
return async (req, res, next) => {
const url = `${req.protocol}://${req.get("host")}${req.originalUrl}`;
const requirements = makeRequirements(); // fresh invoiceId per challenge
const body = challenge(url, description, requirements);
const header = req.get("PAYMENT-SIGNATURE"); // x402 v2 payment header
if (!header) {
return res
.status(402)
.set("PAYMENT-REQUIRED", Buffer.from(JSON.stringify(body)).toString("base64"))
.json(body);
}
let paymentPayload;
try {
paymentPayload = JSON.parse(Buffer.from(header, "base64").toString("utf8"));
} catch {
return res.status(402).json(body);
}
const verify = await facilitator("/verify", paymentPayload, requirements);
if (!verify.isValid) {
return res.status(402).json({ ...body, error: verify.invalidReason || "invalid_payment" });
}
// /settle at most once per payment — deliver ONLY on success:true.
const settle = await facilitator("/settle", paymentPayload, requirements);
if (!settle.success) {
return res.status(402).json({ ...body, error: settle.errorReason || "settlement_failed" });
}
res.set("PAYMENT-RESPONSE", Buffer.from(JSON.stringify(settle)).toString("base64"));
next();
};
}
const app = express();
app.get(
"/report",
requirePayment("xrpl", "One full report"), // ← or "xahau" for the Xahau rail
(req, res) => res.json({ ok: true, report: "your paid payload here" })
);
app.listen(3000, () => console.log("paid API on :3000 — try: curl -i localhost:3000/report"));
Xahau payer side (xrpl.js) — building the fee leg
// ─── x402 starter kit: the Xahau payer side — building the fee leg ────────
// For BUYER clients paying a 402Proof Xahau (xrpl:21337) challenge.
// Requires: npm i xrpl
//
// On Xahau the buyer signs TWO native Payments from the same account:
// 1. the merchant leg — full `amount` to the resource's payTo,
// carried in the payment payload as payload.signedTxBlob;
// 2. the facilitator fee leg — exactly 10,000 drops (0.01 XAH) to the
// facilitator fee recipient, sequenced immediately after the main
// leg (Sequence + 1), carried as payload.feeTxBlob and bound to the
// payment by exactly one memo: MemoData = uppercase hex of
// invoiceId + ":fee" (when the requirements carry extra.invoiceId;
// otherwise uppercase hex of the main transaction hash + ":fee").
// 402Proof's /verify rejects a missing, mis-addressed, under-amount,
// wrongly-bound or wrongly-sequenced fee leg. The merchant amount is
// never reduced by the fee.
//
// The build/sign/bind logic below was exercised offline on 2026-11-04:
// both blobs were signed with a throwaway wallet and decoded back to
// the exact fields the facilitator checks. Nothing was broadcast.
import xrpl from "xrpl";
export const XAHAU_FEE_RECIPIENT = "rEmdJWrAWFtud1vFN8Zm8eWkgK4AVMWPiX";
export const XAHAU_FEE_DROPS = "10000"; // 0.01 XAH — flat, per /supported
// Pure builder: hand it prepared fields (sequence, fee, last ledger) and a
// wallet; it returns the payload legs. In production, fill those fields
// with client.autofill() against https://xahau.network (see usage below).
export function buildXahauPayment({
wallet,
payTo,
amountDrops,
invoiceId, // from the challenge's accepts[].extra.invoiceId (may be undefined)
sequence,
lastLedgerSequence,
networkFeeDrops = "100", // the Xahau network's own tx fee — autofill in production
}) {
const mainTx = {
TransactionType: "Payment",
Account: wallet.address,
Destination: payTo,
Amount: String(amountDrops),
NetworkID: 21337,
Sequence: sequence,
LastLedgerSequence: lastLedgerSequence,
Fee: String(networkFeeDrops),
};
const signedMain = wallet.sign(mainTx);
const binding = invoiceId ? `${invoiceId}:fee` : `${signedMain.hash}:fee`;
const feeTx = {
TransactionType: "Payment",
Account: wallet.address,
Destination: XAHAU_FEE_RECIPIENT,
Amount: XAHAU_FEE_DROPS,
NetworkID: 21337,
Sequence: sequence + 1, // immediately after the main leg
LastLedgerSequence: lastLedgerSequence,
Fee: String(networkFeeDrops),
Memos: [
{
Memo: {
MemoData: Buffer.from(binding, "utf8").toString("hex").toUpperCase(),
},
},
],
};
const signedFee = wallet.sign(feeTx);
return {
signedTxBlob: signedMain.tx_blob, // → payload.signedTxBlob
feeTxBlob: signedFee.tx_blob, // → payload.feeTxBlob
mainTxHash: signedMain.hash,
feeTxHash: signedFee.hash,
};
}
// ── Live usage (the shape a real payer client runs) ────────────────────────
// const client = new xrpl.Client("https://xahau.network");
// await client.connect();
// const wallet = xrpl.Wallet.fromSeed(process.env.BUYER_XAH_SEED);
// const prepared = await client.autofill({
// TransactionType: "Payment", Account: wallet.address,
// Destination: requirements.payTo, Amount: requirements.amount, NetworkID: 21337,
// });
// const legs = buildXahauPayment({
// wallet, payTo: requirements.payTo, amountDrops: requirements.amount,
// invoiceId: requirements.extra?.invoiceId,
// sequence: prepared.Sequence, lastLedgerSequence: prepared.LastLedgerSequence,
// networkFeeDrops: prepared.Fee,
// });
// const paymentPayload = {
// x402Version: 2,
// accepted: requirements,
// payload: { signedTxBlob: legs.signedTxBlob, feeTxBlob: legs.feeTxBlob },
// };
// // retry the resource URL with header:
// // PAYMENT-SIGNATURE: base64(JSON.stringify(paymentPayload))
// await client.disconnect();
FastAPI (Python) — the resource server
# ─── x402 starter kit: FastAPI — XRPL + Xahau via 402Proof ────────────────
# One paid route, settled through 402Proof (Script Master Labs' facilitator
# for the XRPL family). Requires: pip install fastapi uvicorn httpx
#
# 402Proof is PARTNER-KEYED by design — the XRPL facilitator fee accrues per
# settlement instead of being collected inside it, so keys are issued to
# known sellers. Get yours first (reply within one business day):
# email tim@scriptmasterlabs.com with (1) your service's base URL,
# (2) the rail — XRPL RLUSD, XRPL USDC or Xahau XAH — and
# (3) your receiving wallet address.
# Then activate the invite token you receive:
# POST https://four02proof-x402-v2-xrpl.onrender.com/v1/partners/activate
# { "inviteToken": "inv402_…", "acceptFeeUSDCents": 1 }
# The p402_… key it returns is shown ONCE — store it server-side only.
#
# Verified 2026-11-04 against 402Proof's live /supported + /pricing.json on
# both hosts, the live discovery-index accepts objects, and live /verify
# refusal behavior (see the kit page's proof section).
import base64
import json
import os
import secrets
import time
import httpx
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
FACILITATOR = "https://four02proof.onrender.com" # 402Proof (standard x402 v2)
PARTNER_KEY = os.environ["PROOF402_PARTNER_KEY"] # p402_… — server-side only
PAY_TO = "rYourReceivingWallet" # ← your XRPL/Xahau wallet: buyer payments land here directly
PRICE_DROPS = "1000000" # 1 XRP (or 1 XAH) — drops: 1 XRP = 1,000,000 drops
XAHAU_FEE_RECIPIENT = "rEmdJWrAWFtud1vFN8Zm8eWkgK4AVMWPiX"
def new_invoice_id() -> str:
# A fresh invoiceId per challenge — your partner key is scoped to your
# payTo, your resource origin, your amount ceiling and the invoiceId.
return f"inv-{int(time.time() * 1000):x}-{secrets.token_hex(4)}"
def xrpl_requirements() -> dict:
# Requirements shape copied from 402Proof's live discovery index
# (2026-11-04). XRPL carries NO fee leg in the buyer's transaction: the
# facilitator fee ($0.0100 per settlement, loyalty-discounted) accrues
# on a separate merchant ledger — read yours at GET /v1/partners/usage.
return {
"scheme": "exact",
"network": "xrpl:0",
"asset": "XRP",
"amount": PRICE_DROPS,
"payTo": PAY_TO,
"maxTimeoutSeconds": 300,
"extra": {"areFeesSponsored": False, "invoiceId": new_invoice_id()},
}
def xahau_requirements() -> dict:
# Same guard, one different requirements object. On Xahau the fee IS
# collected at settlement: the buyer's client signs a SECOND native
# Payment of exactly 10,000 drops (0.01 XAH) to the facilitator fee
# recipient, carried in the payload as feeTxBlob and bound by a memo
# (see the payer snippet on the kit page). Your amount is never
# reduced by the fee.
return {
"scheme": "exact",
"network": "xrpl:21337",
"asset": "XAH",
"amount": PRICE_DROPS,
"payTo": PAY_TO,
"maxTimeoutSeconds": 300,
"extra": {
"areFeesSponsored": False,
"invoiceId": new_invoice_id(),
"facilitatorFee": "10000", # drops — flat 0.01 XAH per third-party settlement
"facilitatorFeeRecipient": XAHAU_FEE_RECIPIENT,
},
}
REQUIREMENTS_FOR = {"xrpl": xrpl_requirements, "xahau": xahau_requirements}
def challenge(url: str, description: str, requirements: dict) -> dict:
return {
"x402Version": 2,
"error": "payment_required",
"resource": {"url": url, "description": description, "mimeType": "application/json"},
"accepts": [requirements],
}
async def facilitator(path: str, payment_payload: dict, requirements: dict) -> dict:
async with httpx.AsyncClient(timeout=30) as client:
r = await client.post(
FACILITATOR + path,
headers={
"Content-Type": "application/json",
"Authorization": f"Bearer {PARTNER_KEY}", # your scoped partner key
},
json={
"x402Version": 2,
"paymentPayload": payment_payload,
"paymentRequirements": requirements,
},
)
try:
return r.json()
except ValueError:
# e.g. 401 with an empty body when the key is missing or wrong — a
# refusal, not a crash: surface it as an invalid payment (fresh 402).
return {"isValid": False, "success": False, "invalidReason": f"facilitator_http_{r.status_code}"}
def b64(obj: dict) -> str:
return base64.b64encode(json.dumps(obj).encode()).decode()
async def guard(request: Request, rail: str, description: str):
"""Returns None when the request is paid (proceed), else a 402 response."""
requirements = REQUIREMENTS_FOR[rail]() # fresh invoiceId per challenge
body = challenge(str(request.url), description, requirements)
header = request.headers.get("PAYMENT-SIGNATURE") # x402 v2 payment header
if not header:
return JSONResponse(body, status_code=402, headers={"PAYMENT-REQUIRED": b64(body)})
try:
payment_payload = json.loads(base64.b64decode(header))
except Exception:
return JSONResponse(body, status_code=402)
verify = await facilitator("/verify", payment_payload, requirements)
if not verify.get("isValid"):
return JSONResponse({**body, "error": verify.get("invalidReason", "invalid_payment")}, status_code=402)
# /settle at most once per payment — deliver ONLY on success: true.
settle = await facilitator("/settle", payment_payload, requirements)
if not settle.get("success"):
return JSONResponse({**body, "error": settle.get("errorReason", "settlement_failed")}, status_code=402)
return None # paid — the route handler serves the resource
app = FastAPI()
@app.get("/report")
async def report(request: Request):
blocked = await guard(request, "xrpl", "One full report") # ← or "xahau"
if blocked is not None:
return blocked
return {"ok": True, "report": "your paid payload here"}
# Run (save this file as main.py):
# PROOF402_PARTNER_KEY=p402_… uvicorn main:app --port 3000
# Test: curl -i localhost:3000/report (expect HTTP 402 + the challenge)
Test it before you trust it
Call your route unpaid — curl -i localhost:3000/report — and expect HTTP 402 with the challenge in the body and the PAYMENT-REQUIRED header, the same accepts shape 402Proof's live discovery index publishes. Until your key is active, that is also all that can happen: without a valid partner key the facilitator refuses /verify (HTTP 401 at the main service; unauthorized_resource_server at the sidecar — both exercised live on 2026-11-04), and the middleware surfaces the refusal as a fresh 402 rather than an error page. After your first real settlement, find your resource URL in the sidecar discovery index.
Request a partner key
Why this door has a key, stated plainly: on Base and Arc (OMNIGATE) the facilitator fee is collected inside the settlement, so no trust is needed and the door is open. On XRPL the $0.0100 fee accrues — Script Master Labs extends each seller a small, growing line of credit and collects later. Credit is extended to known sellers, so the XRPL and Xahau door is partner-keyed: each key is scoped to one payTo wallet, one resource origin, one asset, an amount ceiling and the invoice ID. That scoping is the design that keeps an accrual rail honest — it is not a queue, a review board, or a sales call.
To get one, email tim@scriptmasterlabs.com with:
- Your service's base URL
- The rail: XRPL RLUSD, XRPL USDC, or Xahau XAH
- Your receiving wallet address
Keys are issued by hand — expect a reply within one business day. Activation is then two calls (invite → /v1/partners/activate) and the kit above is the whole remaining integration.
The proof, dated
| Check | Result | When |
|---|---|---|
402Proof sidecar /supported — kinds and fee terms | x402 v2 exact on xrpl:0, Solana and xrpl:21337 (Xahau); Xahau block: fee 0.01 XAH (10,000 drops) to rEmdJWrA…MWPiX, settlementProven: true, feeSettlementProven: true; Solana block: 0.005 USDC flat, both proven flags true | 2026-11-04, live read |
402Proof /pricing.json — the XRPL merchant tariff | Base fee $0.0100; loyalty $0.0080 / $0.0070 / $0.0050 at 100 / 1,000 / 10,000 prior settlements; automaticCollectionLive: false ("accrued, not collected cash"); externalThirdPartySettlementsVerified: false | 2026-11-04, live read |
| Xahau canary settlement (SELF-PROOF) | Merchant leg tx B1781F38EE1C1A88BDC106415EC5E0CB507ABE43B30D88D0AA5C9B0AFC636247 (ledger 26986344, tesSUCCESS, merchant +1,000,000 drops exactly); fee leg tx 49CFFB98B335CE456DD0ED7A338AC670300BD554675C7B302C51D87597731A5A (ledger 26986346, tesSUCCESS, fee recipient +10,000 drops exactly); exact replay returned the recorded result with no second submission | 2026-11-02 |
| Solana canary settlement (SELF-PROOF) | Fee-carrying tx 5d6b2ojznZ6p3BQ52eEAGayj6KQAoJxZSosSNggQGM9SRx1GqL2Gq4McWCCxVUiPjMFef24p5vJ6eP7zTfKrodXg (slot 464625034): one transaction carrying both 5,000-atomic legs, recipient ATA delta exactly +10,000 atomic; a fee-less payment was refused by /verify in the same run | 2026-11-02 |
| Sidecar discovery index size | 20 resources | 2026-11-04, live read |
/verify refusal with no partner key | Main service: HTTP 401. Sidecar: {"error":"unauthorized_resource_server"}. The key gate is live on both hosts | 2026-11-04, live probe |
| Starter-kit test runs (both middleware snippets, local servers) | Unpaid → 402 with the exact challenge shape and a PAYMENT-REQUIRED header that decodes to the body; fabricated payment → live /verify refusal surfaced as a fresh 402; nothing submitted, nothing charged | 2026-11-04 |
| Xahau fee-leg builder test (offline sign + decode) | 13 of 13 field checks passed: NetworkID 21337 on both legs, fee exactly 10,000 drops to the published recipient, fee Sequence = main + 1, exactly one memo = uppercase hex of invoiceId + ":fee" (and of mainTxHash + ":fee" in the no-invoice fallback) | 2026-11-04 |
Honest limits. 402Proof's published settlement proof is SELF-PROOF — the canary payer (rL377LAdWoU1BQRKi82jLsjH2iRCgS9Mih, funded by the operator) paying the operator's own merchant through the operator's own facilitator. SELF-PROOF proves the rails settle end-to-end and charge exactly the published fee. It does not prove outside adoption: 402Proof's own machine-readable pricing publishes externalThirdPartySettlementsVerified: false, and no external partner has settled end-to-end yet — the 20 resources in the sidecar index today are Script Master Labs' own fleet plus its own service endpoints. This kit, and the partner-key door, exist to produce the first outside settlement; the index will show it the day it happens. The XRPL fee's accrual is likewise stated, not hidden: until collection goes live, accrued fees are a ledger entry, not revenue — which is exactly why keys are scoped and issued to known sellers. Presence in an index is also not demand: the metric that matters is unique paying wallets over time, which no index publishes and which Script Master Labs does not manufacture with self-payments.
Request a partner key Integration questions — tim@scriptmasterlabs.com
Selling on Base or Arc?
Those rails settle through OMNIGATE, Script Master Labs' open-door facilitator — no key, no email, just the kit: /settle-through-sml-starter (Express, FastAPI and Hono middleware; 0.005 USDC flat per settlement from the first settlement). The full fee table for every rail is on /settle-through-sml, and 402Proof's evidence file is the attestations page.
Frequently asked questions
What does it cost to settle through 402Proof on XRPL?
The facilitator fee is $0.0100 USD per completed settlement, and it is never taken out of your buyer's payment — it accrues on a separate merchant ledger (402Proof's own pricing publishes automaticCollectionLive: false — accrued, not collected cash, as of 2026-11-04). The fee drops with your settled volume: after 100 prior successful settlements it is $0.0080 (20% loyalty discount), after 1,000 it is $0.0070 (30%), after 10,000 it is $0.0050 (50%). Verification, failed settlements, indeterminate settlements and exact replays are free, and there is no subscription. You can read your own ledger at any time — GET /v1/partners/usage on the sidecar shows your settlements, the discount tier for your next settlement, and your accrued fees labeled collectionStatus: not_collected.
What does it cost on Xahau?
A flat 0.01 XAH per settlement — exactly 10,000 drops — charged from the first settlement with no free allowance. On Xahau the fee is collected inside the settlement: your buyer's client signs a second native Payment of 10,000 drops to the facilitator fee recipient (rEmdJWrAWFtud1vFN8Zm8eWkgK4AVMWPiX) and carries it in the payment payload as feeTxBlob, bound to the payment by a memo. Your price is paid to your payTo in full; the fee never comes out of it. The payer snippet on this page builds that leg exactly the way /verify checks it.
Why do I need a partner key here, when OMNIGATE needs no key at all?
Because the two facilitators collect their fees differently. OMNIGATE (Base/Arc) collects its 0.005 USDC inside the settlement itself, so it needs no trust and its door is open. On XRPL the $0.0100 fee accrues instead of being collected at settlement — Script Master Labs is effectively extending each seller a small, growing line of credit. Credit goes to known sellers: a partner key is scoped to your payTo wallet, your resource origin, your asset, an amount ceiling and the invoice ID, and it is what the facilitator checks before it will verify or settle for your origin. The key is the design that keeps an accrual rail honest, and getting one is one email plus a two-call activation (see the partner-key section).
How do I get a partner key?
Email tim@scriptmasterlabs.com with (1) your service's base URL, (2) the rail — XRPL RLUSD, XRPL USDC, or Xahau XAH — and (3) your receiving wallet address. Keys are issued by hand; expect a reply within one business day. You will receive a one-time invite token (inv402_…, good for 48 hours); activate it by POSTing to https://four02proof-x402-v2-xrpl.onrender.com/v1/partners/activate with the token and your acceptance of the published fee schedule, and the p402_… key it returns — shown once — is what the starter-kit snippets send as the Authorization: Bearer header. Keep it server-side only; never expose it to payer agents or browsers.
Does 402Proof ever hold my money?
Never. On both rails the buyer pays your payTo wallet directly with their own signed transaction; the facilitator validates the signed payload and submits it — it signs nothing and custodies nothing. On Xahau the fee leg likewise moves directly from the payer to the facilitator fee recipient. Your server holds no settlement keys either: it forwards the buyer's signed payload to /verify and /settle under your partner key.
How does my API get listed in the discovery index?
Settle. The sidecar's /discovery/resources index is the facilitator's own record of registered, settling resources — when a payment for your resource settles through 402Proof, the resource belongs in that index (20 resources at the 2026-11-04 live read). There is no separate listing fee. The sidecar index also feeds Script Master Labs' public /x402-directory aggregation — 16,963 resources across all of its sources at the 2026-11-03 read — and both indexes are re-probed daily on the public /x402-index-health page.
What does my buyer need in order to pay me?
An x402 v2 client that can sign XRPL-family Payment transactions with its own wallet. On XRPL it signs one Payment for your price and sends it as payload.signedTxBlob. On Xahau it signs that Payment plus the 0.01 XAH fee leg (payload.feeTxBlob, sequenced immediately after, memo-bound to the invoice) — the payer snippet on this page is the exact construction /verify accepts. If a Xahau payment arrives without a valid fee leg, /verify refuses it and nothing is submitted; your route simply re-issues the 402, which the starter-kit snippets already do.
I want to charge in RLUSD or USDC on XRPL, not native XRP. Does this kit do that?
This kit covers the standard x402 v2 rails: native XRP on XRPL (xrpl:0) and native XAH on Xahau (xrpl:21337). RLUSD- and USDC-denominated sales on XRPL run on 402Proof's invoice rail — the main service's product-specific invoice API (invoice, payer-submitted on-chain payment, verification, access token) priced at 0.01 in the invoice's own asset per verified settlement. It is a separate integration from the v2 flow; the same partner-key email starts it — name the rail (XRPL RLUSD or XRPL USDC) in your request. The invoice rail's evidence lives on the attestations page.
I sell on Base or Arc instead. Is there a kit for me?
Yes — those rails settle through OMNIGATE, Script Master Labs' open-door facilitator, and its starter kit is at /settle-through-sml-starter: copy-paste Express, FastAPI and Hono middleware, 0.005 USDC flat per settlement from the first settlement, no account or key. This page's kit is the twin for the XRPL family, where the fee model makes the door partner-keyed.