Skip to content

The agent tools

paymentTools(client) returns the AgentTool descriptors wrapping a configured PipRailClient. Together they give a model the full loop: find a payable resource, price it, check it can pay, then pay it, plus list a resource of its own, read its remaining budget, read the agent contract, and re-verify a receipt it (or anyone) holds.

Only one of the eight moves funds; the other seven are read-only or write to an external index, and none of them can spend. The model can’t bypass the spend policy either, because every payment routes through the same policy / onBeforePay guard on the client these tools wrap.

import { PipRailClient, paymentTools } from '@piprail/sdk'
const client = new PipRailClient({
chain: 'base',
wallet: { key: process.env.AGENT_KEY! },
})
const tools = paymentTools(client) // → the AgentTool descriptors, ready to register
ToolPurposeMoves funds?
piprail_discoverFind payable x402 resources on the open indexes (the phone book).No, read-only
piprail_quote_paymentPrice a gated URL without paying.No, read-only
piprail_plan_paymentCheck you can pay: balance, gas, recipient readiness, across every rail.No, read-only
piprail_pay_requestFetch a gated URL, paying if needed.Yes. The only value-moving tool
piprail_registerList a resource you run on the open indexes.No, writes a listing
piprail_budgetRead remaining budget + time leash.No, read-only
piprail_guideRead the agent contract (how to quote / plan / pay).No, read-only
piprail_verify_receiptRe-verify a verifiable receipt against the chain (wallet-free).No, read-only

The first five are byte-identical in name and order to earlier versions; the read-only tools (piprail_budget, piprail_guide, and piprail_verify_receipt) are appended last.

Searches the open x402 indexes for payment-gated resources, without paying. This answers the agent’s “what can I buy?” question. By default it returns only resources payable on the wallet’s own chain.

ArgTypePurpose
querystringFree-text topic to search for (optional).
networkstringCAIP-2 id, 'self' (your chain, the default), or 'any' (all chains).
categorystringKeep only this category. Strict: uncategorized results are dropped.
assetstringKeep only resources paying in this token symbol, e.g. 'USDC'.
maxPricenumberDrop results advertised above this USD price.
minReliabilitynumberDrop results below this health score (0 to 100); unscored results pass through.
verifiedbooleanPrefer verified listings.
sortstring'relevance' | 'reliability' | 'price' | 'uptime' | 'name'.
limitnumberMax results per index (default 20).

Read-only, open-world (it reaches external indexes). The result is { count, resources }, where each resource carries resource, name, description, source, priceUsd, category, reliabilityScore, health, verified, and networks. Results are cross-scheme, so always piprail_quote_payment a chosen resource, which re-checks the live price, before paying. See Discover & register.

Gets the price of a gated URL without paying: amount, token, chain, recipient, and whether it’s within the spend policy. Returns { gated: false } when the URL needs no payment.

// piprail_quote_payment({ url })
{ "url": "https://api.example.com/report" }
// → { gated: true, amountFormatted: "0.10", symbol: "USDC", network: "eip155:8453", payTo: "0xYourWallet", withinPolicy: true, … }

The result spreads the full PipRailQuote over { gated: true, … }, so read amountFormatted (the human amount, e.g. "0.10") rather than amount (base units). Takes a single required url. Read-only and open-world (it fetches the URL to read the 402 challenge). Backed by quote().

Reads wallet balance, native gas, and recipient readiness across every rail the URL offers on your chain, and returns { gated, payable, status, fundingHint, summary, best, options }. payable: false means do not attempt the payment; fundingHint says exactly what to top up.

// piprail_plan_payment({ url })
{ "url": "https://api.example.com/report" }
// → {
// gated: true,
// payable: true,
// status: "ready", // 'ready' | 'blocked' | 'unknown'
// fundingHint: null, // a sentence when NOT payable
// summary: "Payable: 0.10 USDC on eip155:8453 (gas ~0.00002 ETH). 1 other rail(s) not settleable.",
// best: { network, symbol, amount, gasCoin, gas },
// options: [ … ]
// }

Takes a single required url. Read-only and open-world (it fetches the URL and reads chain state). The result includes a summary line distilling the whole plan for the model: the exact string summarizePlan() produces, gas in the chain’s native coin (never fiat, because PipRail has no price oracle). The session time leash is added only when a time policy is configured. Call it before piprail_pay_request so you never commit to a payment you can’t finish. Backed by planPayment().

piprail_pay_request: the one tool that pays

Section titled “piprail_pay_request: the one tool that pays”

Fetches a gated URL and makes the required payment if needed, subject to the spend policy and the onBeforePay approval hook. It pays whichever rail(s) the client is configured for: onchain-proof (PipRail’s backendless default, where the buyer broadcasts and pays gas), or, when the operator enables it (schemes: ['onchain-proof', 'exact']), the ratified exact rail, where the buyer only signs and the server/facilitator broadcasts, so the buyer pays zero gas (on EVM + Solana + Algorand + Aptos + NEAR; the method, EIP-3009/Permit2/SVM/Algorand/Aptos/NEAR, is auto-selected). With autoRoute on, it pays the cheapest settleable rail, which is the gasless exact one. Returns the HTTP status, the response body, a payment receipt if one settled, and a verifiableReceipt when the gate emitted one. The agent doesn’t choose the rail or method; the client does.

ArgTypePurpose
urlstringFull URL to fetch (required).
methodstringHTTP method, default 'GET'.
bodyobject | stringOptional request body for POST/PUT. An object is JSON-serialised and sent with content-type: application/json set automatically; a string is sent verbatim with no content-type set.
// piprail_pay_request({ url, method, body })
{ "url": "https://api.example.com/jobs", "method": "POST", "body": { "topic": "weather" } }
// → { status: 200, ok: true, body: {…}, receipt: { network, transaction, payTo, … } | null, verifiableReceipt? }
// receipt is the parsed X402Receipt, or null when nothing settled (e.g. the URL wasn't gated)
// verifiableReceipt is present only when the gate emitted one: the PipRailReceipt JSON
// ({ piprail: "1", receipt, resource, … }, stamped with the fetched URL), re-checkable via piprail_verify_receipt

Every SDK failure comes back as a structured object, never a thrown crash, so the model can reason about it. A policy or approval refusal returns { ok: false, declined: true, code, reason, explain, reasonCode? } with no funds moved; common failures arrive with a code and a one-line explain. When a broadcast-but-unconfirmed payment times out (code: 'PAYMENT_TIMEOUT' / 'MAX_RETRIES_EXCEEDED' / 'CONFIRMATION_TIMEOUT'), the result carries a ref. The never-re-pay rule in the agent guide tells the model to recover via that ref rather than pay again.

Lists a payment-gated resource you run on the open indexes so other agents can discover it. The default target is 402 Index: no auth, no signature, no payment. Returns { outcomes }, one outcome per index ({ source, ok, detail, visibility, note }); a step a chain can’t satisfy comes back ok: false with the reason.

ArgTypePurpose
urlstringFull URL of the resource to list (required).
namestringDisplay name (defaults to the host).
descriptionstringWhat the resource offers.
categorystringThe top findability lever, since most listings have none. A real category ('ai', 'finance', …) makes a listing rank + filter.
tagsstring[]Keywords, folded into the description for search and sent as a tags field.
priceUsdnumberAdvertised price in USD (metadata).
networkstringNetwork slug to advertise, e.g. 'base' (defaults to the paying chain). Set it when registering from a multi-chain wallet so the listing names the right chain.
assetstringPayment asset symbol, e.g. 'USDC' (metadata).
providerstringWho runs the resource (provider/org name).
contactEmailstringContact email for the listing (also used by the domain claim).

Writes a listing to an external index but moves no funds and hosts nothing on PipRail’s side (destructiveHint: false).

Reads how much spend budget and time leash is left: per-(network, asset) remaining, the cross-token grand total per denomination, the payment-count leash, the session time envelope, and your spend so far. Use it in Mode A (headless) to self-check before paying, rather than discovering the leash by hitting a decline.

// piprail_budget() takes no arguments
// → { spent, remaining, grandTotal, counts, session, policy, report }

remaining is the per-(network, asset) budget; grandTotal is the cross-token cap remaining per denomination (USD/EUR/…); counts is the payment-count leash; policy reads back the configured leash; report is a one-line spend summary from formatSpendReport(). Takes no arguments. Read-only and idempotent. Backed by the client’s spend ledger; see Spend ledger and Payment policy.

Returns the PipRail agent contract: the quote → plan → pay loop, how to read a refusal (and which declines are terminal), the never-re-pay rule for broadcast-but-unconfirmed payments, and Mode A vs Mode B.

// piprail_guide() takes no arguments
// → { guide: "…the full agent contract as text…" }

Takes no arguments. Read-only and idempotent. Call it once if unsure how to use these tools. The full text also has its own page: the agent guide.

piprail_verify_receipt: re-verify a receipt

Section titled “piprail_verify_receipt: re-verify a receipt”

Re-verifies a PipRail verifiable receipt against the chain, confirming a payment really settled (the funds provably moved to payTo for at least the stated amount) without trusting whoever handed over the receipt. Read-only and wallet-free: it takes a PipRailReceipt JSON: the verifiableReceipt a prior piprail_pay_request returned, or a receipt handed over by any third party.

ArgTypePurpose
receiptobjectThe PipRailReceipt JSON ({ piprail, receipt, resource, decimals? }) to re-verify (required).
rpcUrlstringOptional RPC URL for the receipt’s chain. Required for chains outside the common presets.
// piprail_verify_receipt({ receipt })
// → {
// ok: true, // the chain confirms the settlement
// onChain: { payTo, asset, amount, payer }, // payer is RE-DERIVED from the tx
// matchesClaims: true, // false ⇒ the receipt forged the payer
// ageSeconds: 42,
// error: null // a chain/RPC problem comes back HERE, never thrown
// }

onChain.amount is a verified lower bound, and matchesClaims: false flags a forged payer. Read-only and open-world (it reads the on-chain tx via RPC). Unlike the other tools it never throws, because there’s no wallet and no payment, so a chain or RPC failure is reported in error rather than raised. It wraps the static PipRailClient.verifyReceipt, so the same anyone-verifiable check is available in code; see Verifying receipts and Verifiable receipts.