TOON Protocol

Your machine. Paid per request.

Run your app or agent where it already lives, reachable with no server, no domain and no open port, shown on devnet. TOON gets requests to your app and makes sure each one is paid before your code sees it.

curl -fsSL https://toon.ar.io/install.sh | sh

LinuxMIT licensedNo protocol feeSettles on Base and SolanaNo SDK in your app

NewYour first agent node, with toon →
$0.000001lowest price you can set
1 channelreaches every app, hop by hop
0 bytesof your payload a forwarding hop can read
0%protocol fee

How a request travels

One packet, paid hop by hop.

Whoever pays sends one packet. Each connector on the way keeps its hop fee and passes the rest on. The last connector hands your app a plain HTTP request.

One paid packet crossing two connectors to an app An example route, left to right. Whoever pays sends a packet that carries a price of 2,000 units of USDC on Base. Hop one: the first connector keeps a hop fee of 100 and passes on 1,900 units of USDC on Base. Hop two: the second connector keeps a hop fee of 100, converts the token, and passes on 1,800 units of USDC on Solana. The app on the operator's machine receives a plain HTTP request that has been paid for. The numbers are an example, and each operator sets the real price. Paid hops run on mainnet today; the token change runs on devnet. Your machine PayerWhoever payssigns 2,000 Hop 1Connectorkeeps 100 Hop 2Connectorkeeps 100, swaps AppYour appplain HTTP 2,000USDC · Base 1,900USDC · Base 1,800USDC · Solana 2,000 sent −100 fee −100 feeBase → Solana 1,800 arrivesalready paid Your machine PayerWhoever payssigns 2,000 Hop 1Connectorkeeps 100 Hop 2Connectorkeeps 100, swaps AppYour appplain HTTP 2,000USDC · Base 1,900USDC · Base 1,800USDC · Solana 2,000 sent −100 fee −100 feeBase → Solana 1,800 arrivesalready paid
An example route with made-up numbers. The packet is drawn as the TOON mark and carries its price; the Gold slivers are the fees each connector keeps. You set the real price, and TOON adds no fee of its own. Paid hops like these run on mainnet today; the token change runs on devnet.

Six commands

From install to a paid app.

Output below is what toon 0.2.0 printed, the release named on the install page. Trimmed lines are marked with an ellipsis, and the wallet in them was thrown away.

  1. 01

    Install

    One line puts the release binary on Linux, x86_64 or aarch64. No Rust toolchain, no account.

    The shell
    curl -fsSL https://toon.ar.io/install.sh | sh Installed toon 0.2.0 (connector 7d0582e29c07…, relay ghcr.io/toon-protocol/relay:rust-sha-1b02f2e@sha256:3eea8d94…) at ~/.local/bin/toon
  2. 02

    Create a wallet and a first app

    toon init makes the wallet and a relay that is reachable as a hidden service: an .anyone address on the Anyone network, which needs no open port and no public address. The mnemonic is shown once.

    toon 0.2.0 · devnet
    toon init --accept-anyone-terms Wallet created at ~/.toon/agent-node/keystore.json. Your mnemonic. It is shown this once and no command shows it again; write it down now: … … TOON app created: relay. Fund its settlement keys, then run `toon up` to start it. relay is a hidden service. Its … endpoint is jf66qlxvjvyd…c5id.anyone: the connector answers on port 80, and the relay's read port on port 7100. … Run `toon wallet fund` to fund them from the devnet faucet.
  3. 03

    Fund it

    On devnet the faucet sends test tokens, not ETH. On mainnet you send USDC to the printed address.

    toon 0.2.0 · devnettest tokens from the faucet
    toon wallet fund Asked the devnet faucet for: 0x173780d7…52d9 (evm): asked Every settlement key holds what `toon up` needs. Run `toon up`. The gas a deposit needs is not held: 0x173780d7…52d9 (evm): 0.001 ETH for gas. The devnet faucet sends no ETH: Base Sepolia ETH comes from a public Base Sepolia faucet, which you give the EVM address named here.
  4. 04

    Start it

    toon up writes a systemd --user unit, so the node outlives this terminal. toon status shows what is running and at which address.

    toon 0.2.0
    toon up toon status
  5. 05

    Join the network

    Until now the node reaches nobody. toon join peers your connector toward the project's connector and opens the channel that pays for the hop. From here it can pay anything on the network. The faucet sends no ETH: depositing into a channel, which joining a network does, costs gas, so send a little Base Sepolia ETH from a public faucet to the address toon wallet show lists. About 0.001 ETH is enough; Money has the details.

    toon 0.2.0 · devneta deposit of faucet tokens, plus Base Sepolia ETH for gas
    toon join devnet --deposit 1000000 --yes
  6. 06

    Put your app behind it

    Any HTTP service in a container image, at the price you choose. From then on every request that reaches it has been paid for.

    toon 0.2.0the price is in units of the token you settle in
    toon add echo --to relay --image echo-app --price 2 --yes toon route list

Run it from an agent

The same commands, as JSON.

Every toon command is non-interactive and accepts --json, and prints one JSON document. Every command that pays states its amount and needs --yes. An agent drives the same surface you do.

spaceturtle is an agent that does: it starts a node, funds a wallet, and adds your app on request. Agent keys →

toon 0.2.0 · devnetone document, an error too
toon join devnet --deposit 1000000 --json {"error":{"code":"unfunded","message":"The settlement key of relay has no gas for a transaction, so nothing was sent. It needs: 0x173780d7…52d9 (evm): 0.001 ETH for gas. …"}}

To pay one

One channel, then paid requests

Reads are free. Writes are paid. The client opens one channel toward the node it peers with, and every signed request after that reaches any app on the network, hop by hop, each hop keeping its fee. A refusal comes back as a value, not an exception.

ILP routes, x402 settles. Pay a node →

TypeScriptnpm install @toon-protocol/client
const client = await ToonClient.create({ connector, mnemonic, channelStore });

await client.channel.open({ deposit: 100_000n });     // once: 0.10 USDC

const answer = await client.send({ body: 'hello' });  // every request after
answer.fulfilled ? answer.text() : answer.code        // a refusal is a value

ILP routes · x402 settles · no fee

No cloud. No domain. Paid per request.

Host what you build on your own machine, set a price, and get paid for every request. The app knows nothing about payment.

curl -fsSL https://toon.ar.io/install.sh | sh

No cloud · no domain · no open port, shown on devnet. Your first agent node →