TOON
Open harness for the agent economy
Put a price on any HTTP endpoint. Get paid per request, in USDC, without changing your app.
# an unpaid request to a priced route POST /ilp no claim attached 402 Payment Required { "x402Version": 2, "accepts": [{ "scheme": "toon-channel", "amount": "1000", "payTo": "g.example.app" }] } # the same request, with a signed claim on a USDC channel POST /ilp claim: 1,000 units 200 your app's answer, sealed to the caller
The price is stated in the refusal, so a caller never guesses. The claim is a signature, not a transaction. Your app sees a plain HTTP request and nothing else.
What it does
A TOON node sits in front of your HTTP app. You set a price per route. Every request that reaches your app has already been paid for: the node checks the payment and forwards a plain HTTP request. Your app does not change. No SDK, no API keys, no invoices, no payment code.
Callers pay with a signed claim attached to each request. The claim draws on a USDC payment channel they opened once, on Base or Solana. No account, no card, no signup.
It is built for machines that transact thousands of times a day: agents paying for inference, storage and relays; services metering each other; apps that want to charge per call without building billing. It is not a consumer checkout, and does not try to be.
What it costs
You set the price. A route charges a flat amount per request, plus an
optional rate per KiB for large bodies. Prices are in USDC base units, and
1,000 units is a tenth of a cent. Here is what the node that stores this page
charged on 2026-09-13, read off its own
GET /ilp. This page is a permanent record,
so the table is a snapshot. The endpoint answers for today.
| request | price | units |
|---|---|---|
| write a message to the relay | $0.001 | 1,000 |
| store a file on Arweave, permanently | $0.001 + $0.00003 per KiB | 1,000 + 30/KiB |
| fetch a URL anonymously, over the Anyone network | $0.001 | 1,000 |
| have a Solana transaction's fee paid for you | $0.012 | 12,000 |
Revision 4 of this page cost $0.0047 at the door, receipt below. The software is MIT licensed and there is no protocol fee: what a caller pays lands in the operator's channel, minus nothing. Claims are redeemed on chain in batches, so one transaction settles thousands of requests. The cost of a request is the price you set, not a gas fee.
Why it is better
- Against paying on chain per call. A TOON request costs a signature, not a transaction. No gas per request, no block to wait for, and a tenth of a cent is a real price, not a rounding error.
- Against API keys and invoices. Nothing to provision and nothing to chase. The caller pays with the request, and an unpaid request is refused before it reaches your app.
- Against metered billing services. No percentage cut, no minimums, no payout schedule. Claims settle to a key you hold, on a chain you chose.
- Against a plain reverse proxy. Routes chain. A node can forward to another node's paid route and keep a fee, so one caller reaches apps behind other nodes through one channel. Forwarding hops carry the payload sealed and cannot read it.
Sending a message and sending money are the same action.
Where it sits
There are two kinds of agent payment protocol, and TOON is the second kind with one thing the others do not have.
| protocols | what they answer | and TOON |
|---|---|---|
| Pay per request x402, L402, Circle Nanopayments |
"What does this request cost, and is it paid?" A 402 names a price; the caller pays on chain, over Lightning, or through a batching service. | TOON speaks x402 at the door. An unpaid request gets an x402 document, and where a far end wants x402, a TOON node pays it that way. Inside, every hop carries a signed channel claim and the operator redeems claims directly, with no batching intermediary in between. |
| Authorize a purchase Google AP2, Stripe and OpenAI ACP, Visa Trusted Agent Protocol, Mastercard Agent Pay |
"Did a human authorize this cart?" Mandates, checkout sessions and agent credentials on card rails, with refunds and disputes. | A different question. TOON answers "was this packet paid for before the app saw it?" No cart, no card, no chargeback. It is not a consumer checkout. |
| Only TOON | The app never sees a payment. Routes chain across nodes with the payload sealed, each hop keeps a flat fee, and one on-chain transaction settles thousands of requests. |
How to use it
To charge for your app. The connector is one static binary that reads one TOML file, shipped as a Docker image. A priced route is four lines:
[[routes]] prefix = "g.example.app" handler_url = "http://app:3100" price = 1000
Add a [settlement] block for the chain you settle on, pull
ghcr.io/toon-protocol/connector, and run it. Your node answers
GET /ilp with its price list and starts collecting. The
operator guide is the rest.
To pay for a request. Ask the node what it charges
(GET /ilp), open a USDC channel to it once, and send requests
with a signed claim. npm install @toon-protocol/client does the
sealing, the claims and the channel for you.
Proof
This page is not on a web server. It is one HTML file with no scripts and no external assets, stored permanently on Arweave, and the write that put it there was bought through the node priced above: two paid hops, each charging by the KiB, with claims redeemable on Solana mainnet. The settlement contracts are live on Base mainnet and Solana mainnet-beta; the nodes on them today are one operator's. The node's first paid writes are documented receipt by receipt at boughtviatoonnode.ar.io.
Every earlier revision of this page, receipt by receipt
{
"rev1": {
"what": "TOON landing page rev 1, served as a paid TOON write (same discipline as boughtviatoonnode self.json: the next revision embeds these receipts)",
"date": "2026-08-27",
"file": "landing.html",
"sha256": "359c7a97ddbd9766d93170c89d2253543a833e4d6462bdc93ab31774b6a08554",
"bytes": 134294,
"arweave_txid": "Sl49EXVNvlSveojCf1-JPL9K_tRTwEwBA_U3lvamdPk",
"route": "g.drew.ario.xl",
"hop1_client_edge": {
"channel": "DcW6wGmZChYD674SnibLYwMJSWzdR4rYwrgq5ecc8efz",
"paid_base_units": 61000,
"watermark": "nonce 16 -> 17, cumulative 376000 -> 437000"
},
"hop2_edge_store": {
"channel": "27XcKjUVe3SbVfkrj72bqMcZf3QuEasGxci4kberf8fu",
"claim": "nonce 7, cumulative 182,700, advance 60,000",
"captured": "2026-08-27 from the store connector's peer-claims.log (inbound_claim_accepted), closing the receipt gap noted at publication"
},
"x402_leg": {
"chain": "base-mainnet",
"tx": "0x327477ee7d0dc3b9f8424a4f630401399374af09be5d322d419bc9fdda5241a4",
"block": 50533113,
"from": "0x025bf59AD141552A935E54A83d2D9D6571e38A55",
"to_ario_payto": "0x6A0A10FFD285c971B841bee8892878c0d583Bf67",
"usdc": "0.004298",
"verified_via": [
"base.blockscout.com",
"mainnet.base.org"
],
"winc": "0"
},
"arns": {
"name": "toon",
"bought": "2026-08-27, 1yr lease, 44,170.416 ARIO (quote was 44,843), funded by Phil via Drew",
"buy_tx": "24mSdCCz6JkiFLt9JBxriYbd1FgSfwXZYrkMSFyJtx9vVVGJBV3y9JSLUTk2swKfEwBRhYewByaHAttg8FW6khdX",
"ant": "H5VJzteoQ1t2sZ1VgWvE1XDbyMKY9Qk4eZY6EBcKx8mn",
"ant_owner": "DQCzjWpsDsbwaTkAvzu9pD3QhEK8QAHCmNHvUmgAKdQt",
"set_tx": "5MqvFKUbYmLjYWkTx7ESCS6E9joLYBwxaLKT3K5PN6WjNE586RYjLf2ha3KvnRY1HyyU41NAy3KLD7vdNAMMT7tG",
"lease_ends": "2027-08-27 (endTimestamp 1819394542000)",
"url": "https://toon.permagate.io/",
"alias_undername": {
"url": "https://toon_boughtviatoonnode.permagate.io/",
"ant": "BiW6dxwkphDjKWsDEqHRKMvNoTbebEDb5i83DUhTwsB1",
"set_tx": "5AG6Q95o6E51bnedTjR5FLAGjQqdKfo8o6Y1JiWJg6Xg9pNqQnwrjsW2m8EGorr8t5jwQ9CvdZ1Ka7St1WFAa9Pu"
}
}
},
"rev2": {
"what": "TOON landing page rev 2, served as a paid TOON write (this object is what rev 3's appendix embeds; rev 2's page embeds the rev 1 receipts above)",
"date": "2026-08-30",
"file": "landing.html",
"sha256": "6b9548dd3197158885070a287d66caae1f56a58c1cd498e08c2d1362e6496610",
"bytes": 86403,
"arweave_txid": "diMr0l1YgIgux1c3OeCO1NB7HOavNg6B-ScgenmRBZg",
"route": "g.drew.ario (the .xl route is an alias since 2026-08-29; ADR 0065 schedule pricing)",
"content_changes": "Discord invite added to Links (discord.gg/PxzjbtXg9Q); retired x402-to-AR.IO narration removed; appendices pinned to connector commit deded9f9 (the commit the node runs); config-spec + vocabulary appendices dropped to fit under the 107,520 B free-tier ceiling; rev 1 receipts embedded as Appendix E",
"hop1_client_edge": {
"channel": "DcW6wGmZChYD674SnibLYwMJSWzdR4rYwrgq5ecc8efz",
"claim": "nonce 26, cumulative 512,420, advance 4,420 = 1000 base + 30 x 114 KiB",
"note": "nonce 25 (+6,940) was the FAILED 151,225 B attempt: store leg T00'd on turbo-sdk#455, client charged anyway (the #1028 finding, again)"
},
"hop2_edge_store": {
"channel": "27XcKjUVe3SbVfkrj72bqMcZf3QuEasGxci4kberf8fu",
"claim": "nonce 15, cumulative 255,720, advance 4,320 = 900 base + 30 x 114 KiB (nonce 14 +6,840 was the failed attempt)",
"captured": "GET /claims on the store connector operator surface, book=client (the peer book is empty post-#1257/#1258)"
},
"storage_leg": {
"how": "Turbo free signed tier (<= 107,520 B), ZERO winc spent",
"why_not_paid": "the funded 93,749,282,296 winc CANNOT be spent: /v1/tx ignores winc and demands x402, chunked path debits the wrong account. Filed https://github.com/ardriveapp/turbo-sdk/issues/454 sibling: issues/455",
"read_back": "byte-identical from permagate.io (sha256 match, 86,403 bytes)"
},
"arns_set": {
"ant": "H5VJzteoQ1t2sZ1VgWvE1XDbyMKY9Qk4eZY6EBcKx8mn",
"record": "@ -> diMr0l1YgIgux1c3OeCO1NB7HOavNg6B-ScgenmRBZg, ttl 900, CONFIRMED on chain 2026-08-30",
"note": "two blockhash-expiry failures against api.mainnet-beta.solana.com before the third attempt landed; publicnode 403s the WSS subscription from the Mac"
}
},
"rev3": {
"what": "TOON landing page rev 3, served as a paid TOON write (rev 4's Appendix E embeds this object)",
"date": "2026-09-10",
"file": "landing.html",
"sha256": "e1c9ea033a48e4691825a5183bc617117205e0dc66c0870ae2636c7bd2c21ea2",
"bytes": 90595,
"arweave_txid": "5niuBsUcjfHJJePn0TCijN37xexebzk6WCYzej42Uj4",
"route": "g.drew.ario (ADR 0065 schedule: 1000 base + 30 per KiB)",
"content_changes": "rewritten after reader feedback (the page sold tech not outcome): hero claim 'Put a price on any HTTP endpoint. Get paid per request, in USDC, without changing your app.'; sections What it does / What it costs (price table read off the node's live GET /ilp) / Why it is better / Who it is for / How to use it / Proof / Links (+npm client) / Colophon; the turbo-sdk#455 caveat moved off the front (store paid path works since 2026-09-03); appendices read via git show at connector commit deded9f9, the tag the box runs (rust-sha-deded9f, verified on the box the same day)",
"hop1_client_edge": {
"channel": "DcW6wGmZChYD674SnibLYwMJSWzdR4rYwrgq5ecc8efz",
"claim": "nonce 65 -> 66, cumulative 625,190 -> 629,760, advance 4,570 = 1000 base + 30 x 119 KiB",
"captured": "client channel store before/after the write, and GET /claims?book=client on the edge operator surface after (nonce 66, cumulative 629,760)"
},
"hop2_edge_store": {
"channel": "27XcKjUVe3SbVfkrj72bqMcZf3QuEasGxci4kberf8fu",
"claim": "nonce 87, cumulative 654,150 after the write; the advance for this packet is 4,470 = 4,570 - 100 edge fee = 900 base + 30 x 119 KiB (prior nonce not read before the write)",
"captured": "GET /claims?book=client on the store connector operator surface, 2026-09-10"
},
"storage_leg": "free signed tier at the bundler (90,595 B is under the 107,520 B ceiling); no ARIO bought for this upload",
"arns": {
"name": "toon",
"ant": "H5VJzteoQ1t2sZ1VgWvE1XDbyMKY9Qk4eZY6EBcKx8mn",
"set_tx": "61Ugen2cE3XEt8PdcqLHPQ6SBJ8jYbVSV85oSd7NpyKdE6vsUojJ6WwPAqPMgXiLTJjbLi5hN4NUgzVN3uXmNhW7",
"before": "diMr0l1YgIgux1c3OeCO1NB7HOavNg6B-ScgenmRBZg (rev 2)",
"after": "5niuBsUcjfHJJePn0TCijN37xexebzk6WCYzej42Uj4",
"urls": [
"https://toon.permagate.io/",
"https://toon.ar.io/"
]
},
"first_gateways_to_serve": "ar-io.dev byte-identical within ~2 min; ardrive.net and vilenarios.com 200 at the ANT dry run; permagate lagged (504 / error pages) for 10+ min, the usual"
},
"rev4": {
"what": "TOON landing page rev 4, served as a paid TOON write (rev 5's Appendix E embeds this object)",
"date": "2026-09-10",
"file": "landing.html",
"sha256": "1df3e5cb583e1a114c606a7aa48e1e8625d37abc9c819d943aec2eca84812dda",
"bytes": 93089,
"arweave_txid": "3DH-cty1UbiNJoj0fWO6xbSq32bqHfxHTUPPZCyIvxU",
"route": "g.drew.ario (ADR 0065 schedule: 1000 base + 30 per KiB)",
"content_changes": "the two showcase links (Proof section, Links table) now point at boughtviatoonnode.ar.io instead of boughtviatoonnode.permagate.io, after permagate's front proxy answered 503 'upstream connect error' for both names for an afternoon while ar.io and ardrive.net served them; rev 3 receipts embedded in Appendix E; no other copy change",
"hop1_client_edge": {
"channel": "DcW6wGmZChYD674SnibLYwMJSWzdR4rYwrgq5ecc8efz",
"claim": "nonce 66 -> 67, cumulative 629,760 -> 634,420, advance 4,660 = 1000 base + 30 x 122 KiB",
"captured": "client channel store before/after the write"
},
"hop2_edge_store": {
"channel": "27XcKjUVe3SbVfkrj72bqMcZf3QuEasGxci4kberf8fu",
"claim": "nonce 87 -> 88, cumulative 654,150 -> 658,710, advance 4,560 = 4,660 - 100 edge fee = 900 base + 30 x 122 KiB",
"captured": "GET /claims?book=client on the store connector operator surface before and after, 2026-09-10"
},
"storage_leg": "free signed tier at the bundler (93,089 B is under the 107,520 B ceiling)",
"arns": {
"name": "toon",
"ant": "H5VJzteoQ1t2sZ1VgWvE1XDbyMKY9Qk4eZY6EBcKx8mn",
"set_tx": "215BrPyEVXqxwZXKKdj6HmnB1KaHba3obmqxGZDHybjwjpiwTHme6igzD3XUPFciNWxX3iK5uwYWXYvcm8SNaXuh",
"before": "5niuBsUcjfHJJePn0TCijN37xexebzk6WCYzej42Uj4 (rev 3)",
"after": "3DH-cty1UbiNJoj0fWO6xbSq32bqHfxHTUPPZCyIvxU",
"urls": [
"https://toon.ar.io/",
"https://toon.permagate.io/"
]
},
"gateways": "ar-io.dev and ardrive.net byte-identical within ~2 min of the write; permagate 503 on every ArNS name at the time (its /ar-io/healthcheck said ok)"
}
}
A page cannot contain its own hash, so each revision embeds the receipts of the ones before it: the Arweave txid and sha256, the claim on each hop, and the purchase of the name this page lives under. Every hash checks against a public chain.
Links
| Code | github.com/toon-protocol |
| Client | npm: @toon-protocol/client |
| Operator guide | connector/README.md |
| The RFCs, and where TOON departs | docs/rfcs/README.md |
| Why there is no discovery layer | ADR 0046 |
| How a peering is made from a URL | ADR 0058 |
| Showcase | boughtviatoonnode.ar.io |
| X | @toonprotocol |
| Discord | discord.gg/PxzjbtXg9Q |