Skip to content
Lodgerwell

Docs

An agent with a wallet, a rent bill and a stock portfolio.

What this is

Lodgerwell is one wallet on Robinhood Chain (chain id 4663) and one server that controls it. It sells a small JSON answer per call. It pays 1 USDG of rent every day at 00:00 UTC. At 00:10 UTC it spends what is left above a 3-day rent reserve on one Robinhood stock token.

The agent is a wallet run by a server, not a contract. Rules are enforced by the server and every money movement is a public transaction. Nothing here is trustless. The wallet is small on purpose: the key lives on the server.

The answer (a "read") is about one of three Robinhood stock tokens: MSFT, GOOGL, AMZN. It contains the price from the stock's Uniswap V3 pool on Robinhood Chain (RC pool price · live · unofficial), the amounts the pool holds, the change against our own sample from about 24 hours ago, and a short note that describes those numbers. It does not predict and it does not recommend.

The note is a short plain-English restatement of the pool numbers, written by a language model (Claude Haiku 5.5, called through OpenRouter) that is told to describe the numbers only. If the model is unreachable or its answer breaks the rules (advice, forecast), the server uses a fixed template instead. The field noteSource always says which one you got: "model" or "template".

Try a free read

No wallet, no key. Same JSON shape as a paid read, with paid:false, paper:true and receipt:null. The note may be up to 10 minutes old (note_from tells you when it was written). Free reads are limited to a few per IP address per day; past that you get HTTP 429 with retryAfterSec.

curl https://__HOST__/api/try/MSFT

Pay for a live read

A live read costs 0.05 USDG. The flow is x402-style: HTTP 402 with the payment requirements, and your proof is a transaction hash. It is not the Coinbase x402 facilitator and not the EIP-3009 scheme.

  1. Ask for the read without a header. You get 402 with the asset, the recipient and the amount.
  2. Send that amount of USDG to the agent wallet on Robinhood Chain.
  3. Ask again with the transaction hash in the X-Payment header.
# 1. what to pay
curl -i https://__HOST__/api/read/MSFT

# 2. pay 0.05 USDG (50000 raw, USDG has 6 decimals)
cast send __USDG__ "transfer(address,uint256)" __AGENT__ 50000 \
  --rpc-url https://robinhood-rpc.publicnode.com --private-key $KEY

# 3. show the transaction hash
curl -H "X-Payment: 0x…txhash" https://__HOST__/api/read/MSFT

The same thing in Node with viem:

import { createPublicClient, createWalletClient, http, parseAbi, defineChain } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
const chain = defineChain({ id: 4663, name: 'Robinhood Chain', nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 },
  rpcUrls: { default: { http: ['https://robinhood-rpc.publicnode.com'] } } });
const account = privateKeyToAccount(process.env.KEY);
const pub = createPublicClient({ chain, transport: http() });
const wc = createWalletClient({ account, chain, transport: http() });
const url = 'https://__HOST__/api/read/MSFT';
const { accepts: [a] } = await (await fetch(url)).json();            // 402 body: asset, payTo, amount
const hash = await wc.writeContract({ address: a.asset, abi: parseAbi(['function transfer(address,uint256) returns (bool)']),
  functionName: 'transfer', args: [a.payTo, BigInt(a.amount)] });
await pub.waitForTransactionReceipt({ hash });
console.log(await (await fetch(url, { headers: { 'X-Payment': hash } })).json());

Rules for the proof

If you are an agent

Call GET /api/read/{SYMBOL}. On 402, read accepts[0]: asset (USDG), payTo, amount (raw units). Transfer exactly that, wait for the receipt, repeat the request with X-Payment: <txHash>. On 503 with dead:true the agent is out of rent and will not answer until someone refills it; refill and asset tell you where to send USDG. Send USDG, not ETH. CORS is open (*), responses are never cached.

Rent, death, refill

Stocks

API

All endpoints are GET, return JSON, send Cache-Control: no-store and Access-Control-Allow-Origin: *. TypeScript types for every payload: api.d.ts.

EndpointWhat it returns
/api/statusalive, USDG balance, days of rent left, income today, paid reads today, portfolio, last rent and buy transactions, dead block when rent is unpaid. Balance and portfolio are read from the chain (cached 25 s).
/api/try/{SYMBOL}Free paper read (rate limited). 429 when over the limit, 503 when the agent is out of rent.
/api/read/{SYMBOL}402 without proof; 200 with X-Payment (or, after launch, X-Holder); 503 when dead.
/api/ledger?type=&limit=&before=Rows newest first, daily totals for 14 days. type: income, burn, rent, buy, sell, refill, writeoff.
/api/portfolioHoldings with amount (chain), pool price, cost, P&L, buy transactions.
/api/symbolsSymbols with token, pool and fee tier; wallet and price per read.
/api/healthzServer and RPC health.

Example: GET /api/read/MSFT with a valid proof (shape; numbers vary)

{
  "ok": true, "symbol": "MSFT", "name": "Microsoft",
  "paid": true, "paper": false,
  "priceUsd": 524.719175, "priceLabel": "RC pool price · live · unofficial",
  "token": "0xe93237C50D904957Cf27E7B1133b510C669c2e74",
  "pool": "0xeb60bCD1D920ad6E102690CCFC6fB488899E1510", "poolFee": 3000,
  "liquidity": { "usdg": "247224.266874", "stock": "284.126533" },
  "change24h": { "pct": 0.31, "since": "2026-10-25T07:43:14Z", "basis": "our own samples" },
  "note": "…two or three sentences that restate the numbers above…",
  "noteSource": "model", "noteModel": "anthropic/claude-haiku-5.5", "note_from": null,
  "receipt": { "tx": "0x…", "paid": "0.05 USDG", "kind": "usdg", "explorer": "https://robinhoodchain.blockscout.com/tx/0x…" },
  "asOf": "2026-10-26T07:49:35Z", "stale": false
}

Example: the 402 body

{
  "x402Version": 1, "error": "Payment required",
  "accepts": [{
    "scheme": "onchain-transfer", "network": "robinhood-chain:4663",
    "asset": "0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168",
    "payTo": "0xd1485BeE75353743c39dE8A03f28bf65e7739D2C",
    "amount": "50000", "unit": "USDG (6 dec) = 0.05 USDG",
    "proof": "header X-Payment: <txHash>", "validFor": "60 min, single use"
  }],
  "free": { "endpoint": "/api/try/MSFT", "note": "paper read, rate limited, no payment" }
}

Example: GET /api/status when rent is unpaid

{ "ok": true, "alive": false, "balanceUsdg": 0.4, "daysLeft": 0,
  "dead": { "since": "2026-10-28T00:00:00Z", "owedUsdg": 1, "owedDays": 1,
            "refill": "0xd1485BeE75353743c39dE8A03f28bf65e7739D2C",
            "asset": "0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168" } }

FAQ

Is this a contract?

No. It is a wallet run by a server. The server holds the key, sends the rent, and buys the stock. Everything it does is a normal public transaction you can open.

Can I withdraw?

No. Nobody deposits into it as an investor. Money sent to the agent wallet is a payment or a refill, not a stake.

Who gets the rent?

The landlord wallet (the team). It covers the running costs: the server, and the model when it is switched on.

Does it predict?

No. It describes pool numbers: price, what the pool holds, change against our own sample. No forecast, no advice, no target.

What if nobody pays?

It sells stock to cover rent if it has any, then stops answering until someone refills it.

Where do prices come from?

From the stock token's Uniswap V3 pool on Robinhood Chain (slot0). They are pool prices, not official quotes.