The connector, by hand
The operator surface
A token that reads what you were paid, and a key that moves it.
How you inspect a running node and how you move its money. It mounts only when [operator] is configured, and merges onto client_edge_addr: there is no second port and no second listener.
The one read you will do most: what you were paid.
curl -s -H "Authorization: Bearer $(cat data/operator-bearer-token)" http://127.0.0.1:3000/claims | jq
[operator] bearer_token_file = "/app/data/operator-bearer-token" write_keys_file = "/app/data/operator-write-keys"
Each setting is exactly one of a literal or a path. The file forms are the deployed forms, because a fleet's config files are committed to a public repository and a literal cannot be.
Read and write are different authorities
- Reads take
Authorization: Bearer <token>and nothing more. - Writes take an RFC 9421 HTTP Message Signature from an ed25519 key on
write_keys, with the body bound by an RFC 9530Content-Digest. - A bearer token is never sufficient to move value. Read authority must not confer write authority.
- Every write is attributable and individually revocable. A shared secret is neither.
- An accepted write cannot be replayed. Signatures carry
createdandexpires, and an accepted signature is remembered until its own expiry. - A surface with neither half authenticated refuses to start.
write_keys holds only public halves. The private half lives with whoever is calling and never on the node.
Reads
| Endpoint | Answers |
|---|---|
GET /peers | The peerings this node holds, config and runtime alike. |
GET /routes | The full routing table, with each row's source. |
GET /routes/leased | TTL-bound pushed routes that lapse on their own. |
GET /routes/peers | The durable runtime peer-route table. |
GET /channels | Every channel this node knows, with deposits and status. |
GET /claims | The claim journal: what you have been paid, and by whom. |
GET /identity | This node's operator-facing identity. |
GET /audit-log | Every accepted write, with the key that made it. |
GET /metrics | Prometheus text: toon_packets_total, toon_packets_rejected_total, toon_fees_earned_total, toon_settlement_total. |
There is no unauthenticated metrics path and no dedicated health route. What a container healthcheck probes is GET /ilp/identity on the client edge, which is free and answers only once the config loaded, every settlement backend connected and the router is serving.
Writes
| Endpoint | Does |
|---|---|
POST /packets | Originate a packet from this node. |
POST /peers | Establish a peering from a URL. DELETE /peers/:id removes it. |
POST /routes/peers | Write a durable runtime route. DELETE /routes/peers/:prefix removes it. |
POST /routes/leased | Push a TTL-bound route that lapses on its own. |
POST /channels | Open an outbound x402 channel toward a counterparty, on its published terms. |
POST /channels/:id/fund | Top up an outbound channel by an increment. |
POST /channels/:id/withdraw | Start a withdrawal (EVM) or close (Solana); call again once due to finish. |
POST /channels/:id/land | Land the latest voucher held on an inbound channel now. |
The watchers land your inbound vouchers on their own; land is the lever for planned maintenance. POST /channels journals the channel before it spends, so a retry after an error resumes that channel rather than opening a second. Channel operations answer 503 when no settlement backend is configured. Runtime peers and routes survive a restart, and are refused outright when they would collide with a row the config file owns.
Signing a write
The signature covers exactly three components, @method, @path and content-digest, with alg="ed25519" and keyid set to the signer's own public key in hex. sign-write.sh is the shipped signer: bash and openssl, no other dependency.
docs/operators/sign-write.sh -k operator-write.key -X POST -p /peers \
-b "$BODY" -u https://your-node.example
Omit -u and it prints only the three headers, for a caller assembling its own request. Signing a write is the worked example.
The dashboard
GET /dashboard is the operator's own view of all of the above on one page the node serves: packet traffic and rejects by code, fees earned, inbound and outbound claims, peerings and channels, every route with its source, and the audit log. It needs no token to load, because it holds nothing. Paste the bearer token in and it reads; paste an operator key in and it can peer, write a runtime route or lease one, signing each write in your browser. The key stays in the tab's memory, never stored, never sent. Reach it the way you reach /metrics on that box: on a fleet, an SSH tunnel to client_edge_addr.
Operating it
Logs are structured JSON on stdout. Every line emitted while handling a packet carries the same correlation_id, and because that value is invariant across hops, the same id appears in every connector that handled it. RUST_LOG=debug for more.
Releases. A release builds the image, cuts a dated handle and opens a GitHub Release. It does not deploy: a node repository pins the connector image it runs, by release handle, in its own deploy bundle. Because the binary and a box's mounted TOML are a matched pair in both directions, adding a required config key is a breaking deploy: land the config first, then bump the pin.
Devnet and mainnet. Devnet settles on Base Sepolia and Solana devnet, with test funds from the devnet faucet. The live node that serves toon.ar.io settles on Base mainnet and Solana mainnet-beta. The connector repository's own production tier is a named, empty tier: no fleet machine, no fleet key.
Written from connector/docs/guide/operator-surface.md and operations.md. The rules are numbered in docs/protocol/operator-spec.md.