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 — none of them can spend. The model can’t bypass the spend policy either — 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.

piprail_discover — find what’s payable

Section titled “piprail_discover — find what’s payable”

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 — 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–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().

piprail_plan_payment — check you can pay

Section titled “piprail_plan_payment — check you can pay”

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 — 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 — 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.

piprail_register — list a resource you run

Section titled “piprail_register — list a resource you run”

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 — 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() — 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() — 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 — confirms 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 — 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.