TOON Protocol

Value, routed.

Put a price on any HTTP endpoint. Get paid per request, settled onchain, 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
POST /ilp                  claim: 1,000 units
200                        your app's answer, sealed

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 payment channel they opened once, in the token your node prices in, on the chain you settle on. 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.

Run a node in three steps

One binary, one config file, one command. There is no account to open, nobody to ask, and nothing to add to your app.

  1. Pull it

    The connector ships as one Docker image. Pull it and generate the node's key with one line of openssl.

  2. Price a route

    Four lines of TOML point a price at your app. A settlement block names the token you want to be paid in; the guide has the addresses to copy.

  3. Start it

    docker compose up -d. Your node answers GET /ilp with its price list and starts collecting.

the shell

docker pull ghcr.io/toon-protocol/connector:rust-2026.08.28.1
openssl rand -hex 32 > data/signer.key
docker compose up -d

connector.toml

[[routes]]
prefix      = "g.example.app"
handler_url = "http://app:3100/"
price       = 1000

Before it faces the world, put a TLS proxy in front of it: a TOON node refuses plaintext peers. The operator guide covers that, the settlement block, and peering with a second node.

Paying is one install. npm install @toon-protocol/client asks a node what it charges, opens the channel once, and does the sealing and the claims on every request after that.

What it costs

You set the price, in the token you settle in. A route charges a flat amount per request, plus an optional rate per KiB for large bodies. Prices count the token's smallest unit, the way a card terminal counts cents. The node that stores this page prices in USDC, where 1,000 units is a tenth of a cent. Here is what it charged on 2026-09-23, read off its own GET /ilp. This page is a permanent record, so the table is a snapshot. The endpoint answers for today.

requestpriceunits
write a message to the relay$0.0011,000
store a file on Arweave, permanently$0.001 + $0.00003 per KiB1,000 + 30/KiB
fetch a URL anonymously, over the Anyone network$0.0011,000
have a Solana transaction's fee paid for you$0.01212,000

Revision 5 of this page cost $0.0019 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 onchain 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

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 first kind with one thing the others do not have.

protocolswhat they answerand 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 onchain, 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.
Only TOON The app never sees a payment. Routes chain across nodes with the payload sealed, each hop keeps a flat fee, and one onchain transaction settles thousands of requests.

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 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)"
  },
  "rev5": {
    "what": "TOON landing page rev 5, served as a paid TOON write (rev 6 embeds this object)",
    "date": "2026-09-13",
    "file": "landing.html",
    "sha256": "698c6a51fc238f3f10a15dfd2ebb001e1e71b3b7b9fba8cce2179b19b1d54bc0",
    "bytes": 23060,
    "arweave_txid": "eVq5fpCYo3dmm1Ve28FE96awJoCPpGIBO8vBA7OdeO8",
    "route": "g.drew.ario (ADR 0065 schedule: 1000 base + 30 per KiB)",
    "content_changes": "the verbatim appendices (operator README, RFC departures, ADR 0046, ADR 0058) are replaced by links to the repository; a wire block under the hero shows the unpaid 402 (x402 v2 terms) and the paid 200; 'Who it is for' folds into 'What it does' and the colophon into 'Proof'; new section 'Where it sits' places TOON against pay-per-request protocols (x402, L402, Circle Nanopayments) and purchase-authorization protocols (AP2, ACP, Visa TAP, Mastercard Agent Pay); the price table is read off the node's GET /ilp at build time and dated; the cost line is a receipt (rev 4 cost $0.0047); one sentence states the mainnet contracts are live; page shrinks 93,089 B to 23,060 B",
    "hop1_client_edge": {
      "channel": "DcW6wGmZChYD674SnibLYwMJSWzdR4rYwrgq5ecc8efz",
      "claim": "nonce 67 -> 68, cumulative 634,420 -> 636,350, advance 1,930 = 1000 base + 30 x 31 KiB (the base64 blob inside the job event, not the 23,060 B file)",
      "captured": "client channel store before/after the write"
    },
    "hop2_edge_store": {
      "channel": "27XcKjUVe3SbVfkrj72bqMcZf3QuEasGxci4kberf8fu",
      "claim": "nonce 88 -> 89, cumulative 658,710 -> 660,540, advance 1,830 = 1,930 - 100 edge fee = 900 base + 30 x 31 KiB",
      "captured": "GET /claims?book=client on the store connector operator surface after the write, 2026-09-13"
    },
    "storage_leg": "free signed tier at the bundler (23,060 B is under the 107,520 B ceiling)",
    "arns": {
      "name": "toon",
      "ant": "H5VJzteoQ1t2sZ1VgWvE1XDbyMKY9Qk4eZY6EBcKx8mn",
      "set_tx": "2K5SsuBRmdb1i6nJ2ZuMZV5vJ1V6JxqvtosrC7Ckr9RJcAcAkNPWCZR4rwJkrji47ovU5VWH1SA2hNG9NkFyY9jB",
      "record": "@ -> eVq5fpCYo3dmm1Ve28FE96awJoCPpGIBO8vBA7OdeO8, ttl 900, CONFIRMED on chain 2026-09-13, first attempt"
    },
    "served": "ar-io.dev byte-identical within a minute; ar.io 404 on the raw txid at first check (propagation); permagate.io 502 (its outage, ongoing since 09-10)"
  },
  "rev6": {
    "what": "TOON landing page rev 6, served as a paid TOON write (rev 7 embeds this object)",
    "date": "2026-09-23",
    "file": "landing.html",
    "sha256": "baf2cac00ca968a24945dbefaa37f13f1024af5546c9cf0bfed1b06905210969",
    "bytes": 30731,
    "arweave_txid": "R1AsnnPqN0MBGQVibDz2qSFPj4pqrplGdmr44XsEXmc",
    "route": "g.drew.ario (ADR 0065 schedule: 1000 base + 30 per KiB)",
    "content_changes": "motto 'Value, routed.' replaces 'Open harness for the agent economy'; the claim reads 'settled onchain' instead of 'in USDC'; copy is token-agnostic, naming USDC, Base and Solana only as facts about this node; look and feel follow the console site (system sans, dark by default with a light scheme, sky accent, raised cards), still no scripts; new section 'Run a node in three steps'; a mainnet banner under the header; 'Where it sits' now correctly calls TOON the first (pay-per-request) kind",
    "hop1_client_edge": {
      "channel": "DcW6wGmZChYD674SnibLYwMJSWzdR4rYwrgq5ecc8efz",
      "claim": "nonce 68 -> 69, cumulative 636,350 -> 638,580, advance 2,230 = 1000 base + 30 x 41 KiB (the base64 blob inside the job event)",
      "captured": "client channel store before/after the write"
    },
    "hop2_edge_store": {
      "channel": "27XcKjUVe3SbVfkrj72bqMcZf3QuEasGxci4kberf8fu",
      "claim": "expected advance 2,130 = 2,230 - 100 edge fee; book read after the write: nonce 511, cumulative 1,146,630. The channel also carries the hourly canary and the daily record, so this one advance is not isolated",
      "captured": "GET /claims?book=client on the store connector operator surface after the write, 2026-09-23"
    },
    "storage_leg": "free signed tier at the bundler (30,731 B is under the 107,520 B ceiling)",
    "arns": {
      "name": "toon",
      "ant": "H5VJzteoQ1t2sZ1VgWvE1XDbyMKY9Qk4eZY6EBcKx8mn",
      "set_tx": "5bW2h4jQ4oNBcvhac58SBLAZ4ZqKBrYitqSwtJT83k51JWSjhantiS7qkZQrGaYeeNSuUUECaTJWdpf3qDJspfWC",
      "record": "@ -> R1AsnnPqN0MBGQVibDz2qSFPj4pqrplGdmr44XsEXmc, ttl 900, CONFIRMED on chain 2026-09-23, first attempt"
    },
    "served": "ardrive.net and vilenarios.com byte-identical on the raw txid within a minute; ar.io 404 on the raw txid at first check (propagation); permagate.io 502/503 (its outage)"
  }
}

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