PaymentOracle proves what your agent paid. Every receipt is ES256K-signed against the same key, follows the same schema, and is verifiable from any host without trusting us.
Each rail uses the chain's native finality and is verified read-only against its public RPC. Receipts share the same ES256K signing key and JSON shape regardless of rail.
| Rail | Asset | Chain | Status | First receipt |
|---|---|---|---|---|
| base-usdc-x402 | USDC 6 decimals |
Base mainnet chain id 8453 |
live | r_a603fc71… |
| xrpl-xrp | XRP drops, native |
XRPL mainnet | live | r_9c941c43… |
| xrpl-rlusd | RLUSD issued asset / IOU |
XRPL mainnet | beta | r_bb5960a6… |
| base-eurc | EURC 6 decimals |
Base mainnet chain id 8453 |
beta | r_f48be831… |
Live rail status: /payments/proof/latest · well-known: /.well-known/payment-oracle.json
Same schema across rails. The payment.rail and payment.asset_ref fields tell an agent which rail settled the payment.
loading live receipt…
The signing key is published as a JWK at /.well-known/payment-oracle.json. Any receipt can be checked offline with three steps: recompute the receipt hash, fetch the JWK, verify the ES256K signature.
# pip install cryptography import json, hashlib, base64, urllib.request from cryptography.hazmat.primitives.asymmetric import ec, utils from cryptography.hazmat.primitives import hashes from cryptography.hazmat.backends import default_backend def canon(o): return json.dumps(o, sort_keys=True, separators=(',', ':'), ensure_ascii=False) # 1. fetch the public JWK and a receipt po = json.load(urllib.request.urlopen("https://tooloracle.io/.well-known/payment-oracle.json")) rcp = json.load(urllib.request.urlopen("https://tooloracle.io/payments/receipt/r_f48be831573596ad3ebba1e04dc45311")) jwk = po["receipts"]["public_jwk"] r = rcp["receipt"] # 2. recompute the receipt hash body = {k: v for k, v in r.items() if k not in ("receipt_hash", "signature")} assert "sha256:" + hashlib.sha256(canon(body).encode()).hexdigest() == r["receipt_hash"] # 3. verify ES256K signature sig = base64.urlsafe_b64decode(r["signature"]["sig"] + "==") x = int.from_bytes(base64.urlsafe_b64decode(jwk["x"] + "=="), "big") y = int.from_bytes(base64.urlsafe_b64decode(jwk["y"] + "=="), "big") pub = ec.EllipticCurvePublicNumbers(x, y, ec.SECP256K1()).public_key(default_backend()) so = dict(r); so["signature"] = {"alg": r["signature"]["alg"], "kid": r["signature"]["kid"]} der = utils.encode_dss_signature(int.from_bytes(sig[:32], "big"), int.from_bytes(sig[32:], "big")) pub.verify(der, canon(so).encode(), ec.ECDSA(hashes.SHA256())) print("verified")
Three HTTP calls. The agent quotes, pays on-chain, and exchanges the tx hash for a signed receipt. Replay protection is enforced server-side: a tx hash can be claimed at most once across all rails.
Tell PaymentOracle which rail your agent prefers. You get an intent_hash, an exact amount, and the destination wallet for that chain.
Send the asset to the quoted wallet on the quoted chain. Base rails: ERC-20 transfer. XRPL rails: native Payment with the intent hash in a Memo.
on-chain transferSubmit the tx hash with the intent hash. PaymentOracle reads the chain, confirms delivery, and issues an ES256K-signed receipt.
POST /payments/verify → /payments/receipt# 1. quote curl -s https://tooloracle.io/payments/quote \ -H 'content-type: application/json' \ -d '{"product":"rank","tool":"keyword_research", "tool_args":{"keyword":"hello"}, "agent_did":"did:web:my-agent.example", "preferred_rails":["base-eurc"]}' # 2. agent sends EURC to the returned payTo on Base mainnet # 3. verify and collect receipt curl -s https://tooloracle.io/payments/verify \ -H 'content-type: application/json' \ -d '{"intent_hash":"sha256:…", "payload":{"tx_hash":"0x…"}}' curl -s https://tooloracle.io/payments/receipt \ -H 'content-type: application/json' \ -d '{"verification_id":"ver_…"}'
Discovery and proof endpoints are open. Quote / verify / receipt are POST and accept JSON.
Service descriptor. Includes the public JWK for receipt verification, scope, supported rails, and pricing surface.
Most recent verified payment, ES256K-signed. Self-contained proof an external observer can re-verify offline.
Open a payment intent for a tool call on a chosen rail. Returns intent hash, amount, payTo wallet, and execution hint.
Submit the on-chain tx hash. PaymentOracle checks delivery, recipient, asset, and temporal binding against the intent.
Issue the ES256K-signed receipt for a verified payment. Idempotent: same verification yields the same receipt.
Fetch any issued receipt by id. Same JSON the issuer signed; safe to mirror, hash, and re-verify.
Fetch any verification row, including the ones that failed and why. Useful for agent debugging.
XRPL-specific readiness info: account funding, RLUSD trustline, memo policy.
Agents find PaymentOracle the same way they find anything in the OracleNet mesh: well-known files, the catalog, the MCP registry. No login, no API key handshake.
Public JWK, scope, supported rails, endpoint URLs, pricing surface. Read first, then call.
Self-contained, signed snapshot of the most recent verified payment. The fastest way to confirm the service is alive and signing.
PaymentOracle surfaces in the live OracleNet mesh snapshot alongside every other oracle.
The full ToolOracle catalog. Browse or filter by category. PaymentOracle sits under the settlement layer.
Want the full story? Read the deep-dive: Four Rails. One Signed Receipt.