Skip to content
LogoLogo

radius-cli

Local wallet and execution CLI for Radius

View as Markdown

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 --help

Or install the binary globally:

npm install -g radius-cli
command -v radius-cli
radius-cli --help

Use 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 --help

Networks

NetworkChain IDDefault RPC
mainnet723487https://rpc.radiustech.xyz
testnet72344https://rpc.testnet.radiustech.xyz

radius-cli defaults to mainnet. Set the network explicitly in scripts and agent workflows.

RADIUS_NETWORK=testnet radius-cli wallet address

Override the RPC endpoint with --rpc-url or RADIUS_RPC_URL:

RADIUS_NETWORK=testnet RADIUS_RPC_URL={TESTNET_RPC_URL} radius-cli wallet balance

Project-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 --json

On 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 new

Configuration precedence

radius-cli resolves configuration in this order:

  1. CLI flags: --network, --rpc-url, --sbc, --rusd, --json, --private-key
  2. 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
  3. Radius config file in the active Radius home
  4. 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 address

Check balances:

RADIUS_HOME=.radius RADIUS_NETWORK=testnet \
  radius-cli wallet balance --json
 
radius-cli wallet balance 0x0000000000000000000000000000000000000000 --json

The 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 0xSignerAddress

Send native RUSD:

RADIUS_HOME=.radius RADIUS_NETWORK=testnet \
  radius-cli wallet send 0xRecipientAddress 0.10 RUSD

Send SBC:

RADIUS_HOME=.radius RADIUS_NETWORK=testnet \
  radius-cli wallet send 0xRecipientAddress 0.10 SBC

Send 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 0xTokenAddress

Call an arbitrary state-changing contract function:

radius-cli wallet send 0xTokenAddress "transfer(address,uint256)" 0xRecipientAddress 100000

Use --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)" 0xWalletAddress

Inspect chain data:

radius-cli tx 0xTransactionHash --json
radius-cli receipt 0xTransactionHash --json
radius-cli storage 0xContractAddress 0
radius-cli code 0xContractAddress
radius-cli nonce 0xWalletAddress

Function signatures use cast-style syntax: name(args) for writes and name(args)(returns) for decoded reads.

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 \
  -y

POST 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 \
  -y

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

FlagsOffer at or below thresholdOffer above threshold
--thresholdPays without promptingPrompts on a TTY; refuses without
--threshold and -yPays without promptingRefuses (exit code 2)
-y, no thresholdPays any amountPays any amount
NeitherPrompts on a TTY; refuses withoutPrompts 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 \
  -y

The 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 --networks includes 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 --networks order, 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; MPP evm charges, paid with an EIP-3009 authorization and needing no approval or gas.
  • Schemes: exact with EIP-3009 (v1 and v2) or Permit2 (v2), and upto with Permit2 (v2), where the facilitator settles actual usage up to the signed maximum.
  • Redirects: followed by fetch (up to 20). A request whose 402 comes after a redirect is paid at the final URL, repeating the verb and body, with the price cap and --threshold applied 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 402 marked no-store
  • each offer's network is known, its asset and EIP-712 domain are the network's payment asset, its amount parses (and equals --price at the asset's decimals), payTo is an address, and maxTimeoutSeconds is sensible
  • the challenge's resource.url is the requested URL
  • the facilitator's /supported lists each offer's scheme, network and transfer method: the network's default facilitator, or the ones given with --facilitator <url> (RADIUS_FACILITATOR_API_KEY is sent as x-api-key)
  • a radius-sdk buyer 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

TaskPreferred tool
Application reads and writesviem
React wallet UXwagmi + viem
Contract tests and deployment scriptsFoundry
Local agent wallet operationsradius-cli
One-off contract reads from a terminalradius-cli call or Foundry cast call
Paid endpoints from an agent shellradius-cli wallet pay
Check your own paid endpointradius-cli sell check
Accept or make x402 payments in TypeScriptradius-sdk