radius-cli
Local wallet and execution CLI for Radius
radius-cli is the canonical terminal surface for local Radius wallets and agent workflows. Use it to create or select a wallet, sign messages, check balances, send transactions, read contracts, inspect transactions, and pay for x402- and MPP-protected endpoints.
Use viem for application code and radius-sdk to accept or make x402 payments from TypeScript. Use Foundry for smart contract builds, tests, and deployment scripts. Use radius-cli when an agent or terminal needs to operate a local Radius wallet.
Install and verify
Requires Node.js 22 or later.
Run one command with npx:
npx radius-cli --helpOr install the binary globally:
npm install -g radius-cli
command -v radius-cli
radius-cli --helpUse radius-cli version 0.4.0 or later. From 0.3.0, wallet balance reports RUSD and SBC separately, and wallet send transfers any ERC-20. From 0.4.0, wallet pay (formerly wallet x402, with --threshold and --approve-permit2 formerly --x402-threshold and --x402-approve-permit2) also pays MPP challenges and USDC on Base. From 0.5.0, sell check checks a seller's 402 before you deploy it. Verify that your installed binary exposes the payment command:
radius-cli --version
radius-cli wallet pay --helpNetworks
| Network | Chain ID | Default RPC |
|---|---|---|
mainnet | 723487 | https://rpc.radiustech.xyz |
testnet | 72344 | https://rpc.testnet.radiustech.xyz |
radius-cli defaults to mainnet. Set the network explicitly in scripts and agent workflows.
RADIUS_NETWORK=testnet radius-cli wallet addressOverride the RPC endpoint with --rpc-url or RADIUS_RPC_URL:
RADIUS_NETWORK=testnet RADIUS_RPC_URL={TESTNET_RPC_URL} radius-cli wallet balanceProject-scoped agent wallet
Use RADIUS_HOME to isolate wallet state per project, repo, or agent run:
export RADIUS_HOME=.radius
export RADIUS_NETWORK=testnet
radius-cli wallet address
radius-cli wallet balance --jsonOn first use, account-needing commands such as wallet address, wallet balance, wallet sign, and wallet send create a keystore in the configured Radius home. By default that is ~/.radius; with RADIUS_HOME=.radius, it is local to the current project.
To opt into a password before creating a wallet, set RADIUS_PASSWORD:
RADIUS_HOME=.radius RADIUS_NETWORK=testnet RADIUS_PASSWORD='use-a-secret-manager' radius-cli wallet newConfiguration precedence
radius-cli resolves configuration in this order:
- CLI flags:
--network,--rpc-url,--sbc,--rusd,--json,--private-key - Environment:
RADIUS_NETWORK,RADIUS_RPC_URL,RADIUS_SBC_ADDRESS,RADIUS_RUSD_ADDRESS,RADIUS_PAY_NETWORKS,RADIUS_BASE_RPC_URL,RADIUS_BASE_SEPOLIA_RPC_URL,RADIUS_PASSWORD,RADIUS_KEYSTORE_PATH,RADIUS_HOME - Radius config file in the active Radius home
- Built-in defaults
SBC defaults to 0x33ad9e4BD16B69B5BFdED37D8B5D9fF9aba014Fb, its address on both mainnet and testnet. Set RADIUS_SBC_ADDRESS or pass --sbc only to use another deployment of the same token.
Wallet commands
Create or import a wallet:
radius-cli wallet new
radius-cli wallet import 0xPRIVATE_KEY
radius-cli wallet addressCheck balances:
RADIUS_HOME=.radius RADIUS_NETWORK=testnet \
radius-cli wallet balance --json
radius-cli wallet balance 0x0000000000000000000000000000000000000000 --jsonThe JSON reports sbc and rusd separately (with sbcWei and rusdWei), their sum as totalUsd, and aggregateWei, the value eth_getBalance returns. On Radius eth_getBalance already includes SBC; see The Turnstile and balances.
Sign and verify messages:
radius-cli wallet sign "hello"
echo -n "hello" | radius-cli wallet sign -
radius-cli wallet verify "hello" 0xSIGNATURE --address 0xSignerAddressSend native RUSD:
RADIUS_HOME=.radius RADIUS_NETWORK=testnet \
radius-cli wallet send 0xRecipientAddress 0.10 RUSDSend SBC:
RADIUS_HOME=.radius RADIUS_NETWORK=testnet \
radius-cli wallet send 0xRecipientAddress 0.10 SBCSend any other ERC-20 by its address; decimals are read from the token:
RADIUS_HOME=.radius RADIUS_NETWORK=testnet \
radius-cli wallet send 0xRecipientAddress 0.10 0xTokenAddressCall an arbitrary state-changing contract function:
radius-cli wallet send 0xTokenAddress "transfer(address,uint256)" 0xRecipientAddress 100000Use --json for machine-readable output and --no-wait when you only need the submitted transaction hash.
Read commands
Read a contract:
radius-cli call 0xTokenAddress "balanceOf(address)(uint256)" 0xWalletAddressInspect chain data:
radius-cli tx 0xTransactionHash --json
radius-cli receipt 0xTransactionHash --json
radius-cli storage 0xContractAddress 0
radius-cli code 0xContractAddress
radius-cli nonce 0xWalletAddressFunction signatures use cast-style syntax: name(args) for writes and name(args)(returns) for decoded reads.
Paid endpoints
Use radius-cli wallet pay <verb> <url> to request an endpoint that charges over x402 or MPP. If the endpoint responds with 402 Payment Required, the CLI checks the offer, signs and pays from the local wallet, then retries the request. The protocol side is radius-sdk, the same client applications use.
Agent-friendly GET request:
RADIUS_HOME=.radius RADIUS_NETWORK=testnet \
radius-cli wallet pay get https://example.com/protected \
--threshold 0.001 \
--json \
-yPOST with headers and JSON body:
RADIUS_HOME=.radius RADIUS_NETWORK=testnet \
radius-cli wallet pay post https://api.example.com/query \
-H "Content-Type: application/json" \
-d '{"query":"radius"}' \
--threshold 0.01 \
--json \
-ySupported verbs are get, post, put, patch, delete, head, and options. -d accepts a literal string, @path to read a file, or - to read stdin.
Spending limits
--threshold is in display units for the payment asset, not raw integer units. For SBC, 0.01 means 0.01 SBC.
| Flags | Offer at or below threshold | Offer above threshold |
|---|---|---|
--threshold | Pays without prompting | Prompts on a TTY; refuses without |
--threshold and -y | Pays without prompting | Refuses (exit code 2) |
-y, no threshold | Pays any amount | Pays any amount |
| Neither | Prompts on a TTY; refuses without | Prompts on a TTY; refuses without |
Use --threshold with -y for agent runs: the threshold stays a hard cap, and -y only removes the prompt. The threshold limits one request; it does not enforce a total budget across requests.
Networks and protocols
By default the CLI pays SBC on Radius. --networks radius,base also pays USDC on Base, and --network testnet pairs Radius testnet with Base Sepolia. The same wallet signs on every network:
RADIUS_HOME=.radius RADIUS_NETWORK=testnet \
radius-cli wallet pay get https://example.com/protected \
--networks radius,base \
--threshold 0.001 \
--json \
-yThe list is a preference order among the networks your wallet can pay on: when a server accepts more than one, the CLI reads the wallet's balance on each and pays on the first that covers the price. A wallet that holds only USDC on Base pays on Base with --networks radius,base. Set the list for every run with RADIUS_PAY_NETWORKS or payNetworks in the config file. Base RPC endpoints come from RADIUS_BASE_RPC_URL and RADIUS_BASE_SEPOLIA_RPC_URL, or rpcUrls in the config file.
The CLI pays x402 and MPP (WWW-Authenticate: Payment challenges for evm charges). With --protocol auto, the default, a server that offers both is paid over x402; --protocol x402 or --protocol mpp restricts it to one.
What the CLI pays
- Network and asset: SBC on Radius, and USDC on Base when
--networksincludes it. Offers on other networks or in other assets are refused before anything is signed, and the keystore is unlocked only after an offer is accepted. - Offer choice: x402 before MPP, then networks in
--networksorder, then offers in the server's order, skipping networks where the wallet's balance does not cover the price. - Protocol versions: x402 v1 and v2, selected from the server's
x402Version; MPPevmcharges, paid with an EIP-3009 authorization and needing no approval or gas. - Schemes:
exactwith EIP-3009 (v1 and v2) or Permit2 (v2), anduptowith Permit2 (v2), where the facilitator settles actual usage up to the signed maximum. - Redirects: followed by
fetch(up to 20). A request whose402comes after a redirect is paid at the final URL, repeating the verb and body, with the price cap and--thresholdapplied to that offer. A redirect after payment is followed without the payment header, and the receipt is read from it.
Permit2 approval
Permit2 payments need a SBC allowance for the Permit2 contract. When the server declares eip2612GasSponsoring, as the Radius facilitator does, the CLI signs a permit for the payment amount with each payment and sends no approval transaction, so a wallet that holds only SBC can pay.
A facilitator that sponsors a raw unlimited approve (erc20ApprovalGasSponsoring) instead of a permit is treated like an unsponsored approval: the CLI prompts, or refuses without a TTY unless you pass --approve-permit2 (or -y).
Without sponsorship, pass --approve-permit2 (or -y) to send a one-time unlimited approval automatically, paying gas in SBC on Radius or ETH on Base; otherwise the CLI prompts, or refuses without a TTY. --approve-permit2 also sends the approval when the payment is sponsored, which resolves a facilitator 412 response. Each payment is still authorized by a Permit2 signature capped to its amount.
Output
The response body goes to stdout. Payment confirmation and, with --include, status and headers go to stderr. With --json, stdout is one object: {status, headers, body, bodyEncoding, payment}. payment.network is the CAIP-2 network paid on and payment.protocol is x402 or mpp.
Check a paid endpoint
Use radius-cli sell check <url> on your own paid route, locally or deployed, to see what buyers will be asked for. It requests the URL without paying (-X sets the method, -H and -d work as for wallet pay), decodes the x402 PAYMENT-REQUIRED challenge (or, as the SDK buyer does, an x402 challenge in the JSON body) and any MPP WWW-Authenticate: Payment challenge with radius-sdk, and checks:
- the unpaid response is a
402markedno-store - each offer's network is known, its asset and EIP-712 domain are the network's payment asset, its amount parses (and equals
--priceat the asset's decimals),payTois an address, andmaxTimeoutSecondsis sensible - the challenge's
resource.urlis the requested URL - the facilitator's
/supportedlists each offer's scheme, network and transfer method: the network's default facilitator, or the ones given with--facilitator <url>(RADIUS_FACILITATOR_API_KEYis sent asx-api-key) - a
radius-sdkbuyer would select the offer, and each MPP challenge mirrors an x402 offer
radius-cli sell check http://localhost:8787/api/lookup --price '$0.001'
radius-cli sell check https://api.example.com/query -X post -d '{"q":1}' --facilitator https://facilitator.example
radius-cli --json sell check http://localhost:8787/api/lookup --probe-head--probe-head also sends an unpaid HEAD and warns when it is served, because routers answer HEAD with the GET handler. --pay --threshold <amount> then makes one paid request from the local wallet and checks that a receipt comes back. It pays on testnet unless --network mainnet is given, whatever RADIUS_NETWORK says. The paid request gets a longer timeout than --timeout, and if it still fails after the payment was sent, the report says the payment may have settled.
The command prints one line per check (ok, warn, FAIL, skip, info); with --json, stdout is one object with ok, offers, mpp, facilitators, checks and summary. It exits 0 when no check failed, 1 when one did, and 2 on invalid flags (a malformed -H, an unreadable -d @file, an unknown --network, a bad --price or --threshold).
When to use other tools
| Task | Preferred tool |
|---|---|
| Application reads and writes | viem |
| React wallet UX | wagmi + viem |
| Contract tests and deployment scripts | Foundry |
| Local agent wallet operations | radius-cli |
| One-off contract reads from a terminal | radius-cli call or Foundry cast call |
| Paid endpoints from an agent shell | radius-cli wallet pay |
| Check your own paid endpoint | radius-cli sell check |
| Accept or make x402 payments in TypeScript | radius-sdk |
Related pages
- Build with LLMs
- Create and Fund a Wallet
- Tooling configuration
- Network and RPC
- radius-sdk
- x402 payments
- Agent payments
- Example projects