Micropayments enable creators to monetize directly. Instead of relying on ads or subscriptions, users pay exactly what content is worth to them...
{/* Rest of article content */}0x33ad9e4BD16B69B5BFdED37D8B5D9fF9aba014Fb
### Utility contracts
These utility contracts are commonly used across tooling and app integrations.
#### Testnet
| Contract | Address | Why you use it |
| ---------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- | --------------------------------------------------------- |
| [Arachnid Create2 Factory (deterministic deployment proxy repository)](https://github.com/Arachnid/deterministic-deployment-proxy) | `0x4e59b44847b379578588920cA78FbF26c0B4956C` | Deploy contracts to deterministic addresses with CREATE2. |
| [CreateX deployment framework repository](https://github.com/pcaversaccio/createx) | `0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed` | Use advanced CREATE/CREATE2/CREATE3 deployment patterns. |
| [Multicall3 repository](https://github.com/mds1/multicall) | `0xcA11bde05977b3631167028862bE2a173976CA11` | Batch multiple read calls into one RPC request. |
| [Uniswap Permit2 repository](https://github.com/Uniswap/permit2) | `0x000000000022D473030F116dDEE9F6B43aC78BA3` | Support signature-based approvals and transfer flows. |
#### Mainnet
| Contract | Address | Why you use it |
| ---------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- | --------------------------------------------------------- |
| [Arachnid Create2 Factory (deterministic deployment proxy repository)](https://github.com/Arachnid/deterministic-deployment-proxy) | `0x4e59b44847b379578588920cA78FbF26c0B4956C` | Deploy contracts to deterministic addresses with CREATE2. |
| [Uniswap Permit2 repository](https://github.com/Uniswap/permit2) | `0x000000000022D473030F116dDEE9F6B43aC78BA3` | Support signature-based approvals and transfer flows. |
| [Multicall3 repository](https://github.com/mds1/multicall) | `0xcA11bde05977b3631167028862bE2a173976CA11` | Batch multiple read calls into one RPC request. |
| [CreateX deployment framework repository](https://github.com/pcaversaccio/createx) | `0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed` | Use advanced CREATE/CREATE2/CREATE3 deployment patterns. |
### Accessibility and verification notes
- Use the **contract name** column to understand purpose before copying an address.
- Use the **Why you use it** column for quick context in screen-reader and scan-first workflows.
- Verify target network before deployment or scripting.
- Prefer checksummed addresses in config files and deployment artifacts.
### Related pages
- [Network and RPC](/developer-resources/network-configuration.md)
- [JSON-RPC API](/developer-resources/json-rpc-api.md)
- [Fees](/developer-resources/fees.md)
---
## Ethereum compatibility
*Behavior differences and RPC constraints*
Radius is EVM compatible. Solidity contracts, standard wallets, and Ethereum tooling work without modification. This page covers the specific areas where Radius behavior differs from Ethereum, with practical guidance for each. For tool-specific setup (Foundry, viem, Hardhat, ethers.js), see [Tooling configuration](/developer-resources/tooling-configuration.md).
### At a glance
| Area | Ethereum behavior | Radius behavior |
| -------------------------- | -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| Gas pricing | Market-based fee bidding | Fixed gas price model |
| `eth_blockNumber` | Monotonic block height | Current timestamp in milliseconds |
| Block storage | Canonical block chain in state | Blocks reconstructed on demand for RPC compatibility |
| Block hash | Hash of block header | Equals block number (timestamp-based value) |
| `COINBASE` account reads | Typically readable account state | Returns beneficiary address, but in-transaction state reads can appear empty |
| `transactionIndex` | Position in block | Can be `0` for multiple transactions in the same millisecond |
| `eth_getLogs` filtering | Address filter optional | Address filter required |
| Block tag on state queries | Reads historical state at specified block | Accepts `latest`, `pending`, `safe`, `finalized`; returns error `-32000` for historical block numbers (no archive state) |
| `eth_getBalance` semantics | Raw native balance | Native + Turnstile-convertible stablecoin equivalent |
| `eth_subscribe` types | `logs`, `newHeads`, `newPendingTransactions` | `logs` only |
| Poll-based filters | `eth_newFilter` / `eth_getFilterChanges` | Not supported |
| Transaction finality | Probabilistic (reorgs possible) | Instant and final |
### Gas pricing
Radius uses a fixed gas price model.
Both legacy (`gasPrice`) and EIP-1559 fee fields are accepted when the effective fee is non-zero.
| Parameter | Supported |
| --------------------------------- | ------------ |
| `gasPrice` (legacy) | β
Supported |
| `maxFeePerGas` (EIP-1559) | β
Supported |
| `maxPriorityFeePerGas` (EIP-1559) | β
Supported |
Current fixed gas price: **~1 gwei** (9.85998816e-10 RUSD per unit of gas).
Query the current gas price with `eth_gasPrice`.
viem works with a standard `defineChain()` β no fee overrides are needed. See [viem configuration](/developer-resources/tooling-configuration.md#chain-definition) for the full chain definition.
#### Foundry example
```bash
cast send --gas-price 1000000000 \
--rpc-url https://rpc.testnet.radiustech.xyz \
--account radius-deployer \
{{CONTRACT_ADDRESS}} "transfer(address,uint256)" {{WALLET_ADDRESS}} 1000000
```
Query `eth_gasPrice` for the current fixed gas price. For comprehensive tooling setup (Foundry config files, Hardhat, wagmi, ethers.js), see [Tooling configuration](/developer-resources/tooling-configuration.md).
### The Turnstile and balances
Radius auto-converts stablecoins to native currency for gas payments through a mechanism called the Turnstile. This changes how balance queries work compared to Ethereum.
#### How the Turnstile works
If an account has SBC but not enough RUSD for gas, Radius runs a zero-fee inline conversion before executing the transaction. The account must hold at least 0.1 SBC for the Turnstile to fire.
| Parameter | Value |
| ------------------------------ | -------------------------------------------- |
| Minimum conversion | 0.1 SBC β 0.1 RUSD |
| Maximum conversion per trigger | 10.0 SBC β 10.0 RUSD |
| Conversion direction | SBC β RUSD only (one-way) |
| Gas overhead | Zero β not charged to the caller |
For a standard ERC-20 transfer, 0.1 RUSD covers roughly 10,000 transactions worth of gas. If a transaction requires more than 0.1 RUSD (for example, a large contract deployment), the Turnstile converts whatever amount is needed up to 10.0. The Turnstile also fires for native RUSD transfers that exceed the account's RUSD balance, converting enough SBC to cover the shortfall.
> **β οΈ Warning:** The Turnstile is one-way. SBC converted to RUSD cannot be converted back through the Turnstile.
#### Three balance methods
Radius exposes three ways to query an account's balance. Each returns a different value for the same address.
| Method | Returns | Use when |
| ------------------------------------ | ---------------------------------------------------- | --------------------------------------------------------------------------- |
| `eth_getBalance` | RUSD + convertible SBC equivalent | Checking if a wallet can pay for gas |
| `rad_getBalanceRaw` | Raw RUSD balance only | Checking actual RUSD on hand (or whether the Turnstile will fire) |
| `balanceOf` on SBC contract | SBC ERC-20 balance | Displaying spendable SBC |
The relationship between them:
**`eth_getBalance` = `rad_getBalanceRaw` + (`balanceOf` Γ 10^12)**
The `10^12` multiplier bridges the decimal gap: SBC uses 6 decimals while RUSD uses 18, so 10^(18 β 6) = 10^12.
##### Worked example
An account holding **0 RUSD** and **5.000000 SBC**:
| Method | Raw value | Human-readable |
| ------------------- | -------------------------------- | ------------------ |
| `balanceOf` | `5000000` (6 decimals) | 5.0 SBC |
| `rad_getBalanceRaw` | `0` | 0.0 RUSD |
| `eth_getBalance` | `5000000000000000000` (5 Γ 10ΒΉβΈ) | 5.0 RUSD |
After the Turnstile converts 0.1 SBC β 0.1 RUSD:
| Method | Raw value | Human-readable |
| ------------------- | --------------------------------- | ------------------ |
| `balanceOf` | `4900000` | 4.9 SBC |
| `rad_getBalanceRaw` | `100000000000000000` | 0.1 RUSD |
| `eth_getBalance` | `5000000000000000000` (unchanged) | 5.0 RUSD |
`eth_getBalance` stays the same because total gas-paying power is unchanged β value moved from SBC to RUSD.
##### Query balances with viem
```typescript
import { createPublicClient, http } from 'viem';
import { radiusTestnet } from './chain';
const client = createPublicClient({
chain: radiusTestnet,
transport: http(),
});
const addr = '0xYourAddress' as `0x${string}`;
// 1. eth_getBalance β native + convertible stablecoin equivalent
const ethBalance = await client.getBalance({ address: addr });
// 2. rad_getBalanceRaw β actual native RUSD only
const rawHex = await client.request({
method: 'rad_getBalanceRaw' as any,
params: [addr] as any,
});
const rusdBalance = BigInt(rawHex as string);
// 3. SBC balance β ERC-20 balanceOf
const sbcBalance = await client.readContract({
address: '0x33ad9e4BD16B69B5BFdED37D8B5D9fF9aba014Fb',
abi: [
{
type: 'function',
name: 'balanceOf',
inputs: [{ name: 'account', type: 'address' }],
outputs: [{ type: 'uint256' }],
stateMutability: 'view',
},
] as const,
functionName: 'balanceOf',
args: [addr],
});
```
##### Query raw balance with `rad_getBalanceRaw`
```bash
curl -X POST https://rpc.testnet.radiustech.xyz \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"rad_getBalanceRaw","params":["0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18"],"id":1}'
```
#### RPC behavior with the Turnstile
The Turnstile operates automatically in the background for most applications. These methods reflect Turnstile-aware behavior:
**`eth_sendRawTransaction`** β If the account lacks RUSD but has sufficient SBC, the Turnstile executes inline before the transaction. Receipt logs include stablecoin conversion events.
**`eth_call` and `eth_estimateGas`** β Simulations include Turnstile execution when the account would be short on RUSD but has sufficient SBC. This ensures gas estimates are accurate for accounts that rely on the Turnstile.
### Blocks
Radius does not use blocks as the execution primitive. The atomic execution unit is a transaction.
To preserve Ethereum JSON-RPC compatibility, block-oriented responses are reconstructed on demand.
#### `eth_blockNumber`
`eth_blockNumber` returns the current timestamp in milliseconds (hex encoded).
Practical implications:
- Do not treat block number as canonical chain height.
- Do not assume "N blocks later" semantics match Ethereum finality patterns.
> **β οΈ Warning:** `block.number` returns millisecond timestamps on Radius. Contracts that use block counts for timing (governance voting periods, timelocks, vesting schedules) produce incorrect results without adjustment. Use `block.timestamp` or OpenZeppelin's timestamp-based clock mode.
##### Affected OpenZeppelin contracts
If you are deploying governance, timelock, or vesting contracts, these differences are critical:
| Contract | Parameter | Ethereum interpretation | Radius interpretation | Recommendation |
| ------------------ | ------------------------ | --------------------------- | --------------------------------- | ------------------------ |
| Governor | `votingDelay()` = 1 | ~12 seconds (1 block) | 1 millisecond | Use timestamp clock mode |
| Governor | `votingPeriod()` = 50400 | ~1 week | ~50 seconds | Use timestamp clock mode |
| TimelockController | Block-based delay | Predictable block intervals | Millisecond timestamps | Use `block.timestamp` |
| Vesting contracts | Block-based schedule | Predictable duration | Duration depends on ms timestamps | Use `block.timestamp` |
OpenZeppelin v5 supports timestamp-based clock mode natively:
```solidity
function CLOCK_MODE() public pure override returns (string memory) {
return "mode=timestamp";
}
function clock() public view override returns (uint48) {
return uint48(block.timestamp);
}
```
#### Block reconstruction
A reconstructed "block" contains transactions executed within the same millisecond.
Practical implications:
- Recent block reads are compatible for tooling, but block composition is not equivalent to Ethereum's globally sequenced blocks.
#### Genesis block
The genesis block (block `0x0`) has a `parentHash` of `0x0`, matching standard Ethereum behavior.
#### Block hashes
Block hash equals block number for a given reconstructed block (timestamp-based value), not a chained header hash.
Practical implications:
- Do not rely on parent-hash lineage assumptions from Ethereum.
- Do not infer canonical history from hash chaining on Radius.
#### `BLOCKHASH` returns predictable values
`BLOCKHASH` is supported, but returns a timestamp-derived value β not a cryptographic hash. `blockhash(block.number - 1)` returns the previous millisecond timestamp cast to `bytes32`.
> **π¨ Danger:** Any contract using `blockhash()` as a randomness source is exploitable on Radius. The returned value is fully predictable.
```solidity
// INSECURE on Radius β "random" value is the previous millisecond timestamp
uint256 random = uint256(blockhash(block.number - 1));
uint256 winner = random % participants.length;
```
Vulnerable contract patterns:
- Lottery and raffle contracts
- NFT trait generation using on-chain randomness
- Commit-reveal schemes that hash against `blockhash()`
- Gaming contracts with randomized outcomes
Use Chainlink VRF, an off-chain oracle, or application-level entropy for any randomness needs.
### Instant finality
On Ethereum, confirmed transactions can be reorganized out of the chain. On Radius, every confirmed transaction is final.
- When `waitForTransactionReceipt` returns, the transaction is final. There are no reorgs and no need to wait for additional confirmations.
- Radius supports [`eth_sendRawTransactionSync`](/developer-resources/json-rpc-api.md#eth_sendrawtransactionsync), a synchronous variant that returns the receipt directly in the send response. This eliminates the need for a separate `waitForTransactionReceipt` call.
- Contracts and off-chain logic that wait for N block confirmations can treat confirmation count = 1 as final on Radius.
### RPC query constraints
#### `eth_getLogs` constraints
`eth_getLogs` on Radius differs from Ethereum in two ways:
- **Address filter required.** Queries without an `address` field return error `-33014`. General-purpose indexers must know contract addresses in advance.
- **Block range limit.** The maximum range between `fromBlock` and `toBlock` is 1,000,000 units. Because block numbers are millisecond timestamps, this covers ~16 minutes 40 seconds β not ~1 million blocks as on Ethereum. Queries exceeding this range return error `-33002`.
To query logs over longer periods, split the range into consecutive chunks of up to 1,000,000. See [`eth_getLogs`](/developer-resources/json-rpc-api.md#eth_getlogs) in the method reference.
#### No historical state access
`eth_getBalance`, `eth_getTransactionCount`, `eth_getCode`, `eth_call`, `eth_getStorageAt`, and `eth_estimateGas` parse block tags correctly:
- `latest`, `pending`, `safe`, and `finalized` return current state.
- Historical block numbers return error `-32000`: _"required historical state unavailable"_.
Radius does not support archive mode. There is no way to read state at a past block.
Practical implications:
- Foundry fork mode (`--fork-block-number`) returns an error β past state is not available.
- `eth_call` at a past block returns an error instead of silently returning current state.
- Indexers and analytics that query historical balances receive clear errors rather than misleading data.
#### WebSocket subscriptions support `logs` only
`eth_subscribe("logs")` works correctly with live notifications and fully populated log fields.
```typescript
import { createPublicClient, webSocket } from 'viem';
import { radiusTestnet } from './chain';
const client = createPublicClient({
chain: radiusTestnet,
transport: webSocket('wss://rpc.testnet.radiustech.xyz'),
});
const unwatch = client.watchContractEvent({
address: contractAddress,
abi: contractAbi,
eventName: 'Transfer',
onLogs: (logs) => {
// process logs
},
});
```
`eth_subscribe("newHeads")`, `eth_subscribe("newPendingTransactions")`, and `eth_subscribe("syncing")` return error `-32602`.
For block tracking, poll `eth_blockNumber` on a 10β30 second interval.
#### Poll-based filters are not supported
`eth_newFilter`, `eth_newBlockFilter`, `eth_newPendingTransactionFilter`, `eth_getFilterChanges`, and `eth_getFilterLogs` are unsupported.
For event monitoring over HTTP, poll `eth_getLogs` with incrementing `fromBlock`:
```typescript
let lastBlock = await client.getBlockNumber();
setInterval(async () => {
const currentBlock = await client.getBlockNumber();
if (currentBlock <= lastBlock) return;
const logs = await client.getLogs({
address: contractAddress,
fromBlock: lastBlock + 1n,
toBlock: currentBlock,
});
lastBlock = currentBlock;
// process logs
}, 15_000); // 15-second interval
```
For real-time events, use WebSocket `eth_subscribe("logs")`.
### Beneficiaries and `COINBASE (0x41)`
Radius pays fees to beneficiary addresses.
`COINBASE` returns the beneficiary address for the current execution environment. However, state reads of beneficiary accounts during execution can return an empty account view.
`eth_getBalance` can still return beneficiary balance views, but those reads are ephemeral and can be stale.
Practical implications:
- Do not write contract logic that depends on fresh in-transaction beneficiary account state.
- Treat `COINBASE` as an identifier, not as a reliable in-transaction state anchor.
### Stored transaction data and receipts
Receipts are broadly Ethereum-like. Contract deployment receipts set `to` to `null` and all log fields (`topics`, `data`, `logIndex`, `address`) are fully populated, matching standard Ethereum behavior.
One caveat:
- `transactionIndex` is not always meaningful on Radius.
- If multiple transactions share the same millisecond timestamp, receipts can report `transactionIndex = 0` for each.
Practical implications:
- Do not rely on `transactionIndex` for ordering.
- Use your own ordering keys (for example: ingestion sequence, application-level nonce tracking, or timestamp plus transaction hash).
### Integration checklist
Before shipping to production, verify:
1. Fee estimation returns non-zero `gasPrice`.
2. No logic assumes Ethereum block height semantics.
3. No logic relies on block hash parent-chain behavior.
4. No contract uses `blockhash()` for randomness.
5. No contract path depends on fresh beneficiary account reads during execution.
6. Indexers and analytics do not treat `transactionIndex` as authoritative ordering.
7. Log queries always include an `address` filter.
8. No logic queries state at a historical block number β Radius returns error `-32000` for historical state requests. Supported tags: `latest`, `pending`, `safe`, `finalized`.
9. Event listeners use `eth_getLogs` polling or WebSocket `eth_subscribe("logs")` β not `eth_newFilter`.
10. Block tracking uses `eth_blockNumber` polling β not `eth_subscribe("newHeads")`.
11. Balance checks use the appropriate method (`eth_getBalance` for spendability, `rad_getBalanceRaw` for actual native balance, `balanceOf` for stablecoin balance).
12. Transaction confirmation logic does not wait for multiple blocks. Execution is final.
### Related pages
- [Tooling configuration](/developer-resources/tooling-configuration.md)
- [JSON-RPC overview](/developer-resources/json-rpc-overview.md)
- [JSON-RPC API](/developer-resources/json-rpc-api.md)
- [Fees](/developer-resources/fees.md)
- [Network and RPC](/developer-resources/network-configuration.md)
---
## Fees
*Fixed gas pricing, transaction costs, and Turnstile conversion behavior*
:::note
**Token names used in this page:**
- **RUSD** is the native token and fee token on Radius.
- **SBC** is an ERC-20 stablecoin used for transfers.
- If an account has SBC but not enough RUSD for gas, the Turnstile can convert SBC to RUSD inline.
:::
### Overview
Radius uses fixed gas pricing with low, predictable fees. A standard ERC-20 stablecoin transfer costs about 0.00010 USD on average.
Fees are paid in RUSD. If an account holds a convertible stablecoin such as SBC, Radius can automatically convert it inline through [the Turnstile](#turnstile) at a 1:1 value [^1].
[^1]: RUSD uses 18 decimals, while SBC uses 6. For SBC, 10^6 base units map to 10^18 base units of RUSD at the same face value.
| Parameter | Value |
| --------------------------------------- | ------------------------------------ |
| Avg. stablecoin transfer cost | 0.00010 USD |
| Target SBC transfers per 1 USD | 100,000 |
| Gas price | 9.85998816e-10 RUSD |
| Gas used (avg. transfer) | 101,444 |
### Query gas price
Use the standard `eth_gasPrice` RPC method to fetch the current fixed gas price:
```bash
curl -X POST https://rpc.testnet.radiustech.xyz \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_gasPrice","params":[],"id":1}'
```
**Example response:**
```json
{
"jsonrpc": "2.0",
"id": 1,
"result": "0x3b9aca00"
}
```
The `result` is the gas price in wei (hex-encoded). `0x3b9aca00` = 1,000,000,000 wei = 1 gwei.
### Use with development tools
Radius accepts both legacy and EIP-1559 fee fields. Some tools (notably viem) need explicit gas price configuration. See [Tooling configuration](/developer-resources/tooling-configuration.md) for setup instructions covering Foundry, viem, wagmi, Hardhat, and ethers.js.
### Turnstile
If a sender has SBC but not enough RUSD for gas, Radius runs an automatic, zero-fee inline conversion before executing the transaction [^2].
[^2]: If the account also lacks sufficient convertible stablecoin balance, the transaction fails.
One minimum conversion (0.1 SBC β 0.1 RUSD) covers roughly 10,000 standard transfers.
For the Turnstile mechanics (conversion limits, one-way behavior, balance methods, and RPC interactions), see [The Turnstile and balances](/developer-resources/ethereum-compatibility.md#the-turnstile-and-balances).
---
## JSON-RPC API
*Method behavior and compatibility*
Radius exposes a JSON-RPC 2.0 API compatible with standard Ethereum tooling. This page documents methods that differ from Ethereum, methods requiring elevated access, pseudo-supported methods, and unsupported methods.
For integration guidance, see [JSON-RPC overview](/developer-resources/json-rpc-overview.md).
### Divergent methods
#### `eth_blockNumber`
Returns the current timestamp in milliseconds, encoded as a hex string.
**Parameters:** None
**Returns:** `string` β Current block number as a hex string.
---
#### `eth_getBalance`
Returns native balance plus the maximum native balance that could be obtained by converting the accountβs SBC via the Turnstile. This supports wallet preflight checks.
**Parameters:**
| Name | Type | Description |
| --------- | -------- | --------------------------------------------------------------------------------------------------------------------- |
| `address` | `string` | Address to query (20 bytes, hex encoded) |
| `block` | `string` | Block tag (`latest`, `pending`, `safe`, `finalized`) or block number. Historical block numbers return error `-32000`. |
**Returns:** `string` β Balance in wei as a hex string.
---
#### `eth_getBlock`, `eth_getBlockByNumber`, `eth_getBlockByHash`
Blocks are reconstructed on demand. Very recent reads are not guaranteed to be stable across repeated calls. `eth_getBlockByHash` returns `null` for hashes that do not correspond to a known block.
See [Ethereum compatibility](/developer-resources/ethereum-compatibility.md#blocks).
---
#### `eth_call`, `eth_estimateGas`
If `from` is specified and the sender lacks sufficient RUSD but has sufficient SBC, the Turnstile execution is included in dry-run behavior.
If `from` is omitted or set to the zero address, gas-payment checks are skipped during dry-run execution.
---
#### `eth_maxPriorityFeePerGas`
Returns the current gas price. On Radius this equals `eth_gasPrice` β there is no separate priority-fee market.
**Parameters:** None
**Returns:** `string` β Gas price in wei as a hex string.
---
#### `eth_getLogs`
Two constraints differ from Ethereum:
**Address filter required.** Every query must include an `address` field. Omitting it returns error `-33014`.
**Block range limit.** The maximum range between `fromBlock` and `toBlock` is 1,000,000 units. Because Radius block numbers are millisecond timestamps (see [`eth_blockNumber`](#eth_blocknumber)), this covers ~16 minutes 40 seconds of wall time. Queries exceeding this return error `-33002`.
To query logs over a longer period, split the range into consecutive chunks of up to 1,000,000 and concatenate the results. For real-time event monitoring, use [WebSocket `eth_subscribe("logs")`](#eth_subscribe) instead.
### Extended methods
These methods are not part of the standard Ethereum JSON-RPC specification but are supported by Radius.
#### `eth_sendRawTransactionSync`
Submits a signed raw transaction and waits synchronously for the transaction receipt before returning. Implements [EIP-7966](https://eips.ethereum.org/EIPS/eip-7966).
Unlike `eth_sendRawTransaction`, which returns a transaction hash immediately and requires the client to poll for inclusion, `eth_sendRawTransactionSync` combines submission and receipt retrieval into a single RPC call. This eliminates the polling round-trip and reduces total confirmation latency by approximately 50%.
This is especially useful for latency-sensitive applications such as [x402 payment flows](/developer-resources/x402-integration.md), where on-chain settlement is on the critical path of an HTTP request-response cycle.
**Parameters:**
| Position | Type | Description | Required |
| -------- | -------- | ---------------------------------------- | -------- |
| 1 | `string` | Signed, RLP-encoded transaction hex data | Yes |
| 2 | `number` | Maximum wait time in milliseconds | No |
If no timeout is provided, the node's configured default is used (recommended: 2 000 ms). The timeout cannot exceed the node-configured maximum.
**Returns:** Transaction receipt object (same structure as `eth_getTransactionReceipt`) on success.
**Method-specific error codes:**
| Code | Type | Description | `data` field |
| ---- | -------------- | --------------------------------------------------------------------- | -------------------- |
| `4` | Timeout | Transaction was added to the mempool but not processed within timeout | Transaction hash |
| `5` | Unknown/Queued | Transaction was not added to the mempool | Transaction hash |
| `6` | Nonce gap | Transaction rejected due to a nonce gap | Expected nonce (hex) |
On error code `6`, the `data` field contains the expected nonce as a hex string directly, so the caller can immediately resubmit with the correct nonce without making a separate `eth_getTransactionCount` call.
On error code `4`, the `data` field contains the transaction hash. The transaction was accepted into the mempool β the caller can continue monitoring via `eth_getTransactionReceipt`.
**Example request:**
```json
{
"jsonrpc": "2.0",
"method": "eth_sendRawTransactionSync",
"params": ["0xf86c808504a817c80082520894ab..."],
"id": 1
}
```
**Example success response:**
```json
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"transactionHash": "0x1234abcd...",
"blockHash": "0xabcd1234...",
"blockNumber": "0x10d4f",
"gasUsed": "0x5208",
"status": "0x1",
"logs": []
}
}
```
**Example timeout response (error code 4):**
```json
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": 4,
"message": "The transaction was added to the mempool but wasn't processed within the designated timeout interval.",
"data": "0x1234abcd..."
}
}
```
### Methods requiring elevated RPC access
#### `eth_subscribe`
Creates a WebSocket subscription for real-time logs. Radius supports `logs` only.
`newHeads` and `newPendingTransactions` are not available.
**Parameters:**
| Name | Type | Description |
| -------- | -------- | --------------------------------------- |
| `type` | `string` | Subscription type (for example, `logs`) |
| `filter` | `object` | Log filter object |
**Returns:** `string` β Subscription ID.
### Pseudo-supported methods
These methods return defaults and do not return errors. Most applications should not rely on them.
#### `eth_accounts`
Always returns an empty array. Radius does not manage accounts.
**Parameters:** None
**Returns:** `array` β `[]`
---
#### `eth_feeHistory`
Returns a static response. Radius uses fixed pricing instead of fee-market history.
**Parameters:** See Ethereum JSON-RPC specification
**Returns:** `object`
---
#### `eth_mining`
Always returns `true`.
**Parameters:** None
**Returns:** `boolean`
---
#### `eth_syncing`
Always returns `false`.
**Parameters:** None
**Returns:** `boolean`
---
#### `eth_hashrate`
Always returns `0x0`.
**Parameters:** None
**Returns:** `string`
---
#### `eth_uninstallFilter`
Always returns `true`. Filters are not persisted.
**Parameters:**
| Name | Type | Description |
| ---------- | -------- | ----------- |
| `filterId` | `string` | Filter ID |
**Returns:** `boolean`
---
#### `net_listening`
Always returns `false`. Radius does not use peer-to-peer networking.
**Parameters:** None
**Returns:** `boolean`
---
#### `net_peerCount`
Always returns `0x0`. Radius does not use peer-to-peer networking.
**Parameters:** None
**Returns:** `string`
### Unsupported methods
Radius returns errors for these methods:
- `eth_coinbase`
- `eth_getBlockReceipts`
- `eth_getFilterChanges`
- `eth_getFilterLogs`
- `eth_getProof`
- `eth_getUncleByBlockHashAndIndex`
- `eth_getUncleByBlockNumberAndIndex`
- `eth_getUncleCountByBlockHash`
- `eth_getUncleCountByBlockNumber`
- `eth_getWork`
- `eth_newBlockFilter`
- `eth_newFilter`
- `eth_newPendingTransactionFilter`
- `eth_sign`
- `eth_simulateV1`
- `eth_submitWork`
- `trace_block`
- `trace_callMany`
- `trace_filter`
- `trace_transaction`
### Error codes
Radius uses standard JSON-RPC 2.0 error codes:
| Code | Message | Description |
| -------- | ------------------ | --------------------------- |
| `-32700` | Parse error | Invalid JSON |
| `-32600` | Invalid request | Invalid request object |
| `-32601` | Method not found | Method does not exist |
| `-32602` | Invalid params | Invalid method parameters |
| `-32603` | Internal error | Internal JSON-RPC error |
| `3` | Execution reverted | Contract execution reverted |
Radius-specific error codes:
| Code | Message | Description |
| -------- | ----------------------- | ------------------------------------------------------------ |
| `-33002` | Block range too wide | `eth_getLogs` range exceeds 1,000,000 units (~16 min 40 sec) |
| `-33014` | Address filter required | `eth_getLogs` called without an `address` field |
### Related pages
- [JSON-RPC overview](/developer-resources/json-rpc-overview.md)
- [Network and RPC](/developer-resources/network-configuration.md)
- [Ethereum compatibility](/developer-resources/ethereum-compatibility.md)
- [Fees](/developer-resources/fees.md)
---
## JSON-RPC overview
*Compatibility and integration guidance*
Radius exposes a JSON-RPC 2.0 API that works with common Ethereum tooling. Use this page to understand what works as expected, what differs from Ethereum, and where to find method-level details.
### Use compatible tooling
Radius works with:
- **viem** for TypeScript and Node.js integrations
- **WAGMI** for React wallet integrations
- **Foundry** for smart contract development and scripting
Most `eth_*` methods behave as expected. Some methods are divergent or pseudo-supported. Review those differences before production deployment.
### Understand key behavior differences
Radius is EVM compatible, but not Ethereum-identical. Keep these differences in mind:
- `eth_blockNumber` returns the current timestamp in milliseconds
- `eth_getBalance` returns native balance plus convertible USD balance
- `eth_feeHistory` returns a pseudo-supported response
For full context and implications, read [Ethereum compatibility](/developer-resources/ethereum-compatibility.md).
### Configure gas and fees correctly
Radius uses fixed gas pricing and accepts both legacy and EIP-1559 fee fields. `eth_maxPriorityFeePerGas` and `eth_gasPrice` both return the correct fixed gas price, so viem's built-in fee estimation works with a standard `defineChain()` β no fee overrides are needed.
Read [Gas pricing](/developer-resources/ethereum-compatibility.md#gas-pricing) for details and [Tooling configuration](/developer-resources/tooling-configuration.md#chain-definition) for the full chain definition.
### Submit transactions synchronously for lower latency
Radius supports `eth_sendRawTransactionSync` ([EIP-7966](https://eips.ethereum.org/EIPS/eip-7966)), which combines transaction submission and receipt retrieval into a single RPC call. Unlike the standard `eth_sendRawTransaction`, this method waits synchronously for the transaction receipt before returning β eliminating the polling round-trip entirely.
This reduces transaction confirmation latency by approximately 50% and is particularly valuable for latency-sensitive applications such as [x402 payment flows](/developer-resources/x402-integration.md), where settlement speed directly affects end-to-end request response time.
- **On success**: returns the full transaction receipt object
- **On timeout**: returns error code `4` with the transaction hash, so you can continue monitoring
- **On nonce gap**: returns error code `6` with the expected nonce, avoiding a separate `eth_getTransactionCount` call
An optional second parameter sets the maximum wait time in milliseconds. If omitted, the node default is used (recommended: 2 seconds).
See [`eth_sendRawTransactionSync`](/developer-resources/json-rpc-api.md#eth_sendrawtransactionsync) in the method reference for full parameter and error code details.
### Use WebSocket subscriptions with the right access
`eth_subscribe` is supported for **logs only** and requires an RPC key with elevated privileges.
- Supported: `logs`
- Not supported: `newHeads`, `newPendingTransactions`, `syncing`
For access and limits, see [Network and RPC](/developer-resources/network-configuration.md).
### Find the complete method reference
For the full list of divergent, pseudo-supported, and unsupported methods, see:
- [JSON-RPC API](/developer-resources/json-rpc-api.md)
### Related pages
- [Network and RPC](/developer-resources/network-configuration.md)
- [Fees](/developer-resources/fees.md)
- [Contract addresses](/developer-resources/contract-addresses.md)
- [Ethereum compatibility](/developer-resources/ethereum-compatibility.md)
---
## Network and RPC
*Endpoints, limits, and integration guidance*
Use this page to configure wallets and apps for Radius. It includes network values, RPC behavior, rate limits, and fee configuration patterns.
### Network configuration
#### Radius Network
| Setting | Value |
| ------------------- | ------------------------------------------- |
| **Network name** | Radius Network |
| **RPC endpoint** | https://rpc.radiustech.xyz |
| **Chain ID** | 723487 |
| **Currency symbol** | RUSD |
| **Explorer** | https://network.radiustech.xyz |
| **Faucet** | Not available on mainnet (Dashboard or API) |
#### Radius Testnet
| Setting | Value |
| ---------------------- | ---------------------------------------------- |
| **Network name** | Radius Testnet |
| **RPC endpoint** | https://rpc.testnet.radiustech.xyz |
| **Chain ID** | 72344 |
| **Currency symbol** | RUSD |
| **Explorer** | https://testnet.radiustech.xyz |
| **Faucet (Dashboard)** | https://testnet.radiustech.xyz/wallet |
| **Faucet (API)** | https://testnet.radiustech.xyz/api/v1/faucet |
### Add Radius to a wallet
#### MetaMask
1. Open MetaMask and select **Add network**.
2. Enter the values from the table above.
3. Save and switch to the Radius network you configured.
#### Programmatic setup (viem)
Use the Radius chain definition from [Tooling configuration β chain definition](/developer-resources/tooling-configuration.md#chain-definition). No fee overrides are needed β viem's built-in estimation works with Radius.
### RPC endpoints and transport
- **HTTP RPC:** Use the endpoint values in the network tables.
- **WebSocket RPC:** Requires an RPC key with elevated privileges.
For WebSocket access requests, contact [support@radiustech.xyz](mailto:support@radiustech.xyz).
### API keys and rate limiting
Radius tracks request volume per API key.
- Requests without an API key have lower limits.
- Default API key limit is **10 MGas/s**.
- For higher limits, contact [support@radiustech.xyz](mailto:support@radiustech.xyz).
In this context, βMGasβ includes both RPC calls and gas consumed by submitted transactions.
#### Avoid throttling
1. Reuse API keys consistently per environment.
2. Add client-side retry with exponential backoff for `429`-style responses.
3. Cache frequent read requests where possible.
4. Batch reads with Multicall3 when practical.
5. Queue and smooth bursty traffic instead of sending spikes.
#### RPC key URL format
Append your API key to the RPC URL path:
https://rpc.radiustech.xyz/YOUR_API_KEY
### JSON-RPC behavior to account for
Radius is EVM compatible, but some methods differ from Ethereum behavior:
- `eth_blockNumber` returns the current timestamp in milliseconds
- `eth_getBalance` returns native balance plus convertible USD balance
- `eth_gasPrice` returns the fixed network gas price
- `eth_feeHistory` returns a pseudo-supported response
See [JSON-RPC API](/developer-resources/json-rpc-api.md) for method details and [Ethereum compatibility](/developer-resources/ethereum-compatibility.md) for rationale.
### Get testnet funds
Use the [Radius testnet faucet](https://testnet.radiustech.xyz/wallet) (Dashboard) to claim SBC tokens with a point-and-click interface.
For programmatic and agent access, use the [Faucet API](/get-started/create-and-fund-wallet.md). The API is available on testnet only β there is no faucet API on mainnet.
### Related pages
- [JSON-RPC API](/developer-resources/json-rpc-api.md)
- [Fees](/developer-resources/fees.md)
- [Contract addresses](/developer-resources/contract-addresses.md)
- [Ethereum compatibility](/developer-resources/ethereum-compatibility.md)
---
## Tooling configuration
*Set up Foundry, viem, wagmi, Hardhat, and ethers.js for Radius*
Radius uses a fixed gas price model, which requires specific configuration in some tools. This page covers setup for each major EVM development tool. For background on how Radius differs from Ethereum, see [Ethereum compatibility](/developer-resources/ethereum-compatibility.md).
### At a glance
| Tool | Configuration needed | Notes |
| --------- | -------------------------------------------------------- | ------------------------------------------------ |
| Foundry | `foundry.toml` with `gas_price`, `evm_version`, `via_ir` | `--broadcast` required for `forge create` |
| viem | `defineChain()` β no overrides needed | Fee estimation works out of the box |
| wagmi | Use custom Radius chain definition in `createConfig` | β |
| Hardhat | Pin to v2, set `gasPrice` in network config | v3 installs by default and is incompatible |
| ethers.js | None β works out of the box | Handles gas pricing gracefully without overrides |
### Foundry
#### Recommended `foundry.toml`
Add these settings to your project's `foundry.toml`:
```toml
[profile.default]
gas_price = 1000000000
evm_version = "cancun"
via_ir = true
```
| Setting | Purpose |
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `gas_price` | Matches Radius's fixed gas price (~1 gwei). Query `eth_gasPrice` for the exact value. Eliminates the need for `--gas-price` on every CLI command. |
| `evm_version` | Targets the EVM version Radius supports. |
| `via_ir` | Uses the IR-based code generator. Required for complex deploy scripts with many contracts to avoid "Stack too deep" errors. |
#### CLI usage
Deploy a contract:
```bash
forge create src/MyContract.sol:MyContract \
--rpc-url https://rpc.testnet.radiustech.xyz \
--account radius-deployer \
--broadcast
```
> **π‘ Tip:** Create the keystore once with `cast wallet import radius-deployer --interactive`. The key is stored encrypted at `~/.foundry/keystores/` and never appears in shell history or process listings.
> **β οΈ Warning:** Starting with Foundry 1.5.1, `forge create` defaults to dry-run mode. Add the `--broadcast` flag to send the transaction on-chain.
Send a transaction with `cast`:
```bash
cast send --gas-price 1000000000 \
--rpc-url https://rpc.testnet.radiustech.xyz \
--account radius-deployer \
{{CONTRACT_ADDRESS}} "transfer(address,uint256)" {{WALLET_ADDRESS}} 1000000
```
### viem
#### Chain definition
Radius uses fixed gas pricing. Standard `defineChain()` works out of the box β viem queries `eth_maxPriorityFeePerGas` and `eth_gasPrice` automatically:
```typescript
import { defineChain } from 'viem';
export const radiusMainnet = defineChain({
id: 723487,
name: 'Radius Network',
nativeCurrency: { decimals: 18, name: 'RUSD', symbol: 'RUSD' },
rpcUrls: {
default: { http: ['https://rpc.radiustech.xyz'] },
},
blockExplorers: {
default: {
name: 'Radius Explorer',
url: 'https://network.radiustech.xyz',
},
},
});
export const radiusTestnet = defineChain({
id: 72344,
name: 'Radius Testnet',
nativeCurrency: { decimals: 18, name: 'RUSD', symbol: 'RUSD' },
rpcUrls: {
default: { http: ['https://rpc.testnet.radiustech.xyz'] },
},
blockExplorers: {
default: {
name: 'Radius Testnet Explorer',
url: 'https://testnet.radiustech.xyz',
},
},
});
```
Use this chain definition with `createPublicClient` and `createWalletClient`:
```typescript
import { createPublicClient, createWalletClient, http } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { radiusTestnet } from './chain';
const publicClient = createPublicClient({
chain: radiusTestnet,
transport: http(),
});
const walletClient = createWalletClient({
account: privateKeyToAccount('0x...'),
chain: radiusTestnet,
transport: http(),
});
```
#### wagmi integration
Use the custom chain definition with wagmi's `createConfig`:
```typescript
import { http, createConfig } from 'wagmi';
import { radiusTestnet } from './chain';
export const config = createConfig({
chains: [radiusTestnet],
transports: {
[radiusTestnet.id]: http(),
},
});
```
Then use standard wagmi hooks in your React components:
```tsx
import { useWriteContract, useWaitForTransactionReceipt } from 'wagmi';
function SendPayment() {
const { writeContract, data: hash } = useWriteContract();
const { isSuccess } = useWaitForTransactionReceipt({ hash });
return (
);
}
```
### Hardhat
#### Version pinning
Hardhat v3 installs by default and uses ESM, which is incompatible with many existing plugins. Pin to v2:
```bash
pnpm add -D hardhat@^2.22.0 @nomicfoundation/hardhat-toolbox@hh2
```
#### Network configuration
Add Radius to your `hardhat.config.ts`:
```typescript
import { HardhatUserConfig } from 'hardhat/config';
import '@nomicfoundation/hardhat-toolbox';
const config: HardhatUserConfig = {
solidity: '0.8.24',
networks: {
radiusTestnet: {
url: 'https://rpc.testnet.radiustech.xyz',
chainId: 72344,
gasPrice: 1000000000,
accounts: [process.env.PRIVATE_KEY!],
},
},
};
export default config;
```
Deploy with:
```bash
pnpm hardhat run scripts/deploy.ts --network radiusTestnet
```
### ethers.js
ethers.js handles Radius's gas pricing out of the box with no overrides. When `baseFeePerGas` is `0x0`, ethers.js returns `maxFeePerGas: null` and falls back to legacy `gasPrice` automatically.
```typescript
import { ethers } from 'ethers';
const provider = new ethers.JsonRpcProvider('https://rpc.testnet.radiustech.xyz');
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, provider);
// Standard transaction β no gas override needed
const tx = await wallet.sendTransaction({
to: recipient,
value: ethers.parseEther('1.0'),
});
await tx.wait();
```
### Related pages
- [Ethereum compatibility](/developer-resources/ethereum-compatibility.md)
- [Fees](/developer-resources/fees.md)
- [Network and RPC](/developer-resources/network-configuration.md)
---
## x402 facilitator API
*Payment verification and settlement endpoints*
A facilitator is a service that verifies x402 payment signatures and settles them on-chain. This page documents the facilitator HTTP endpoints, TypeScript types, headers, status codes, and endorsed facilitators for Radius.
For integration patterns and settlement strategies, see [x402 integration](/developer-resources/x402-integration.md).
:::tip[Migrating from x402 v1?]
The v2 protocol changes header names, network identifiers, and package structure. See the [Migration guide: v1 to v2](https://docs.x402.org/guides/migration-v1-to-v2) for a complete walkthrough.
:::
### Endpoints
#### `GET /supported`
Returns the facilitator's supported networks, schemes, and signer addresses.
**Parameters:** None
**Response body:**
| Field | Type | Description |
| ----------------------------------- | -------- | ------------------------------------------ |
| `kinds` | `array` | List of supported payment kinds |
| `kinds[].x402Version` | `number` | Protocol version (`1` or `2`) |
| `kinds[].scheme` | `string` | Payment scheme (for example, `exact`) |
| `kinds[].network` | `string` | CAIP-2 network identifier |
| `kinds[].extra` | `object` | Scheme-specific metadata |
| `kinds[].extra.assetTransferMethod` | `string` | Transfer method (for example, `erc2612`) |
| `kinds[].extra.name` | `string` | ERC-2612 permit domain name |
| `kinds[].extra.version` | `string` | ERC-2612 permit domain version |
| `extensions` | `array` | Supported protocol extensions |
| `signers` | `object` | Map of CAIP-2 patterns to signer addresses |
**Example response (Radius entries):**
```json
{
"kinds": [
{
"x402Version": 2,
"scheme": "exact",
"network": "eip155:723487",
"extra": {
"assetTransferMethod": "erc2612",
"name": "Stable Coin",
"version": "1"
}
},
{
"x402Version": 2,
"scheme": "exact",
"network": "eip155:72344",
"extra": {
"assetTransferMethod": "erc2612",
"name": "Stable Coin",
"version": "1"
}
}
],
"extensions": [],
"signers": {
"eip155:*": ["0xdeE710bB6a3b652C35B5cB74E7bdb03EE1F641E6"]
}
}
```
**Example request:**
```bash
curl https://x402.stablecoin.xyz/supported
```
---
#### `POST /verify`
Verifies a payment signature without settling on-chain. Use this endpoint to validate payment data before committing to settlement.
**Request body:**
The server passes the decoded `PAYMENT-SIGNATURE` value directly as `paymentPayload` and adds a `paymentRequirements` object built from its own config:
| Field | Type | Description |
| -------------------------------------------------- | -------- | -------------------------------------------------------------- |
| `x402Version` | `number` | Protocol version (`2`) |
| `paymentPayload` | `object` | The decoded client payload from the `PAYMENT-SIGNATURE` header |
| `paymentPayload.x402Version` | `number` | Protocol version (`2`) |
| `paymentPayload.resource` | `object` | (Optional) Resource info echoed from the 402 response |
| `paymentPayload.accepted` | `object` | The payment method the client selected |
| `paymentPayload.accepted.scheme` | `string` | Payment scheme (for example, `exact`) |
| `paymentPayload.accepted.network` | `string` | CAIP-2 network identifier |
| `paymentPayload.accepted.amount` | `string` | Payment amount in raw token units |
| `paymentPayload.accepted.asset` | `string` | ERC-20 token contract address |
| `paymentPayload.accepted.payTo` | `string` | Recipient address |
| `paymentPayload.accepted.maxTimeoutSeconds` | `number` | Maximum time the payment is valid |
| `paymentPayload.accepted.extra` | `object` | Scheme-specific metadata |
| `paymentPayload.payload` | `object` | Signed authorization data |
| `paymentPayload.payload.signature` | `string` | Single 65-byte hex-encoded signature |
| `paymentPayload.payload.authorization` | `object` | EIP-2612 permit fields |
| `paymentPayload.payload.authorization.from` | `string` | Payer address |
| `paymentPayload.payload.authorization.to` | `string` | Spender address (the settlement wallet) |
| `paymentPayload.payload.authorization.value` | `string` | Payment amount in raw token units |
| `paymentPayload.payload.authorization.validAfter` | `string` | Earliest valid timestamp |
| `paymentPayload.payload.authorization.validBefore` | `string` | Latest valid timestamp |
| `paymentPayload.payload.authorization.nonce` | `string` | Unique nonce for replay protection |
| `paymentPayload.extensions` | `object` | (Optional) Protocol extensions data |
| `paymentRequirements` | `object` | Expected payment parameters from the server config |
| `paymentRequirements.scheme` | `string` | Payment scheme (for example, `exact`) |
| `paymentRequirements.network` | `string` | CAIP-2 network identifier |
| `paymentRequirements.amount` | `string` | Required amount in raw token units |
| `paymentRequirements.asset` | `string` | ERC-20 token contract address |
| `paymentRequirements.payTo` | `string` | Expected recipient address |
| `paymentRequirements.maxTimeoutSeconds` | `number` | Maximum time the payment is valid |
| `paymentRequirements.extra` | `object` | Token permit domain metadata |
**Response body:**
| Field | Type | Description |
| ---------------- | --------- | ---------------------------------------------------------------------- |
| `isValid` | `boolean` | `true` if the payment signature and balance check pass |
| `payer` | `string` | Address of the payer |
| `invalidReason` | `string` | (Optional) Machine-readable reason for failure if `isValid` is `false` |
| `invalidMessage` | `string` | (Optional) Human-readable failure message |
| `extensions` | `object` | (Optional) Protocol extensions data |
**Example request:**
```bash
curl -X POST https://x402.stablecoin.xyz/verify \
-H "Content-Type: application/json" \
-d '{
"x402Version": 2,
"paymentPayload": {
"x402Version": 2,
"accepted": {
"scheme": "exact",
"network": "eip155:723487",
"amount": "100",
"asset": "0x33ad9e4bd16b69b5bfded37d8b5d9ff9aba014fb",
"payTo": "{{MERCHANT_ADDRESS}}",
"maxTimeoutSeconds": 300,
"extra": {
"assetTransferMethod": "erc2612",
"name": "Stable Coin",
"version": "1"
}
},
"payload": {
"signature": "{{SIGNATURE}}",
"authorization": {
"from": "{{PAYER_ADDRESS}}",
"to": "{{MERCHANT_ADDRESS}}",
"value": "100",
"validAfter": "0",
"validBefore": "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"nonce": "{{NONCE}}"
}
}
},
"paymentRequirements": {
"scheme": "exact",
"network": "eip155:723487",
"amount": "100",
"asset": "0x33ad9e4bd16b69b5bfded37d8b5d9ff9aba014fb",
"payTo": "{{MERCHANT_ADDRESS}}",
"maxTimeoutSeconds": 300,
"extra": { "name": "Stable Coin", "version": "1" }
}
}'
```
**Example response (success):**
```json
{ "isValid": true, "payer": "{{PAYER_ADDRESS}}" }
```
**Example response (failure):**
```json
{ "isValid": false, "invalidReason": "insufficient_funds", "invalidMessage": "Payer balance is below the required amount", "payer": "{{PAYER_ADDRESS}}" }
```
---
#### `POST /settle`
Settles a verified payment on-chain. The request body matches the `/verify` endpoint. On success, the facilitator submits the permit and transfer transactions to Radius and returns the transaction hash.
**Request body:** Same as [`POST /verify`](#post-verify). The facilitator splits the signature into `v`, `r`, `s` internally when calling the on-chain `permit()` function.
**Response body:**
| Field | Type | Description |
| -------------- | --------- | ---------------------------------------------------------------------- |
| `success` | `boolean` | `true` if settlement completed |
| `transaction` | `string` | On-chain transaction hash (empty string if failed) |
| `network` | `string` | CAIP-2 network identifier where settlement occurred |
| `payer` | `string` | Address of the payer |
| `errorReason` | `string` | (Optional) Machine-readable reason for failure if `success` is `false` |
| `errorMessage` | `string` | (Optional) Human-readable failure message |
| `extensions` | `object` | (Optional) Protocol extensions data |
**Example request:**
```bash
curl -X POST https://x402.stablecoin.xyz/settle \
-H "Content-Type: application/json" \
-d '{
"x402Version": 2,
"paymentPayload": {
"x402Version": 2,
"accepted": {
"scheme": "exact",
"network": "eip155:723487",
"amount": "100",
"asset": "0x33ad9e4bd16b69b5bfded37d8b5d9ff9aba014fb",
"payTo": "{{MERCHANT_ADDRESS}}",
"maxTimeoutSeconds": 300,
"extra": {
"assetTransferMethod": "erc2612",
"name": "Stable Coin",
"version": "1"
}
},
"payload": {
"signature": "{{SIGNATURE}}",
"authorization": {
"from": "{{PAYER_ADDRESS}}",
"to": "{{MERCHANT_ADDRESS}}",
"value": "100",
"validAfter": "0",
"validBefore": "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"nonce": "{{NONCE}}"
}
}
},
"paymentRequirements": {
"scheme": "exact",
"network": "eip155:723487",
"amount": "100",
"asset": "0x33ad9e4bd16b69b5bfded37d8b5d9ff9aba014fb",
"payTo": "{{MERCHANT_ADDRESS}}",
"maxTimeoutSeconds": 300,
"extra": { "name": "Stable Coin", "version": "1" }
}
}'
```
**Example response (success):**
```json
{
"success": true,
"transaction": "0x...",
"network": "eip155:723487",
"payer": "{{PAYER_ADDRESS}}"
}
```
**Example response (failure):**
```json
{
"success": false,
"errorReason": "insufficient_funds",
"errorMessage": "Payer balance is below the required amount",
"transaction": "",
"network": "eip155:723487",
"payer": "{{PAYER_ADDRESS}}"
}
```
---
#### `GET /health`
Returns the facilitator's health status.
**Parameters:** None
**Example request:**
```bash
curl https://x402.stablecoin.xyz/health
```
### TypeScript types
#### `X402Config`
Configuration for x402 payment gating on a server or gateway.
```typescript
interface X402Config {
/** ERC-20 token contract address */
asset: string;
/** CAIP-2 chain identifier, e.g. "eip155:723487" */
network: string;
/** Wallet address that receives payments */
payTo: string;
/** Facilitator service base URL */
facilitatorUrl: string;
/** Payment amount in raw token units (e.g. "100" = 0.0001 SBC with 6 decimals) */
amount: string;
/** Optional API key for the facilitator */
facilitatorApiKey?: string;
/** ERC-2612 permit domain name (default: "Stable Coin") */
tokenName?: string;
/** ERC-2612 permit domain version (default: "1") */
tokenVersion?: string;
/** HTTP header carrying the payment (default: "PAYMENT-SIGNATURE") */
paymentHeader?: string;
}
```
#### `PaymentRequired`
The object encoded in the `PAYMENT-REQUIRED` header when a resource requires payment.
```typescript
interface PaymentRequired {
x402Version: number;
error?: string;
resource: {
url: string;
description?: string;
mimeType?: string;
};
accepts: PaymentRequirementsItem[];
extensions?: RecordConnect your wallet to unlock this content.
This premium content costs {amount} USD to unlock.
One-time payment. No subscription. Instant access.
{isPending &&Awaiting wallet confirmation...
} {isConfirming &&Confirming payment...
} {hash && (Transaction: {hash.slice(0, 10)}...{hash.slice(-8)}
)}Micropayments enable creators to monetize directly. Instead of relying on ads or subscriptions, users pay exactly what content is worth to them...
{/* Rest of article content */}Content for {item.title}
>
> ## Understand account environments
>
> Accounts on Radius Network and Radius Testnet are separate.
>
> If you use both environments, create one account per environment.
>
>
>
> :::note
> Switch environments with the selector at the top of the Dashboard.
### Find fee data in the app
Use these screens to check fees:
1. **Network Activity**: The **Stablecoin Transfer Cost** metric shows the average cost of a standard stablecoin transfer.
2. **Transaction Details**: The **Fee** field shows the fee charged for that transaction.
#### Compare transaction details by transfer type
Transaction details differ by transfer type:
- **ERC-20 transfer** (for example, SBC): shows contract interaction rows and token transfer rows.
- **RUSD transfer**: usually shows one native transfer row.
Both views include the fee, but the operation breakdown is different.
##### ERC-20 transfer example
##### RUSD transfer example
> **βΉοΈ Info:** **Stablecoin Transfer Cost** is an average reference value for standard transfers. Actual fees depend on gas used.
Read more in [Fees](/developer-resources/fees.md).
### Manage RPC API keys
Create RPC API keys in the Dashboard.
Each Dashboard account supports up to five API keys.
For usage details, see [Network and RPC](/developer-resources/network-configuration.md#rate-limiting--api-keys).
### EIP-3091 explorer link support
The Dashboard supports [EIP-3091](https://eips.ethereum.org/EIPS/eip-3091) URL patterns for explorer deep links. It uses standard routes such as `/tx/{hash}`, `/address/{address}`, and `/token/{address}` so wallets and apps can generate links without custom mapping.
> **π Note:** Radius handles blocks differently from Ethereum. Read [Ethereum compatibility](/developer-resources/ethereum-compatibility.md#blocks) for details.
---
## Radius Network
*Build on stablecoin-native infrastructure*
Use this guide to learn how Radius works and move from first transaction to production integration.
> **βΉοΈ Info:** Building with LLMs? Check out these skills.
>
> -
> Radius Dev: Use to build dapps and launch projects
>
>
> -
> Dripping Faucet: Use to fund testnet and mainnet wallets to easily get started
>
### Welcome
Radius is a high-performance settlement engine for machine-to-machine payments. It is EVM compatible, settles in sub-second time, and uses predictable stablecoin-native fees.
Use these docs to get from first transaction to production integration.