Docs

One API serves the pocket, the gadget firmware and Muse. JSON in, JSON out, one token per wallet.

Auth

The pocket asks the wallet to sign one purpose-bound message with personal_sign (EIP-191):

Chipo link v1 | <wallet> | <nonce> | <issuedAt>

The nonce is 32 hex characters and issuedAt an ISO time. The server accepts a message for 10 minutes, spends each nonce once, checks that the recovered address is the wallet, and returns a token:

Authorization: Bearer chipo_<32 bytes base64url>

The server stores only sha256(token), in the wallet's profile. Link again and the server rotates the token: the old one stops working at once. The same token goes to Muse and into the gadget console, where each command starts with >: >chipo token <token>, >chipo api <url> and >chipo status. Tokens never go in URLs or logs.

Errors are {"error": "<short sentence>"} with a 4xx or 5xx status. Amounts are USD strings matching ^\d+(\.\d{1,2})?$; wallets are 0x plus 40 hex characters. A payment recipient must be pasted in EIP-55 mixed case; an all-lowercase or all-uppercase recipient is refused.

Endpoints

CallAuthAnswer
GET /api/healthpublic{ok, relay:{ok, chains}, chain:{id:4663, head, ageSec, ok}, catalog:{count, capturedAt}, storage:{mode, degraded}}, edge cached 30 s
POST /api/linksignature{wallet, message, signature} to {token}
GET /api/profileBearer{wallet, hobbies[], weeklyUsd, payday, currency, createdAt}
POST /api/profileBearer{hobbies[], weeklyUsd, payday, currency}, weeklyUsd 1 to 5000, payday mon to sun or none
GET /api/budgetBearer{wallet, weeklyUsd, spentUsd, leftUsd, periodStart, periodEnd, mood, purchasesThisWeek, updatedAt}
POST /api/purchasesBearer{merchant, category, usd, at?, note?} to {id, ...record}, written once
GET /api/purchases?limit=50Bearer{items:[...], count}
GET /api/deals?hobbies=a,b&limit=12public{items:[{id, name, category, discountPct, cashbackPct, currency, denominations, image, sourceUrl}], source, advice}, edge cached 30 s
GET /api/deals/adviceBearer{advice:[{text, kind}], basis:{leftUsd, daysToPayday}}, kind is timing, swap or wait
POST /api/pay/quotepublic{wallet, usd, recipient, destinationChainId?} to {requestId, inEth, inUsd, outUsd, feesUsd, timeSec, tx:{to, data, value, chainId}, expiresAt}; without a wallet the answer is a preview with tx: null
GET /api/pay/status?requestId=public{status, txHashes[]} from Relay

Payments are capped per transaction (200 USD unless the operator sets another cap). Calls are rate limited per token and per address.

Mood rule

A pure function shared by the server and the pocket. ratio = leftUsd / weeklyUsd.

MoodWhen
dancingratio 0.6 or more, and a purchase logged in the last 24 hours
happyratio 0.4 or more
fineratio 0.2 or more
worriedratio above 0
sadratio 0 or below (over budget)

The week starts Monday 00:00 UTC. With a payday set, the period starts at 00:00 UTC on that weekday.

Categories

The survey's hobby list and the catalog filter: eating-out, coffee, movies, games, music, sport, books, travel, nights-out, hobbies-other.

The catalog is a Bitrefill catalog snapshot captured 2026-10-03: US gift cards whose brand or category maps to one of the ten. The snapshot carries no discount data, so cards rank by hobby match, then popularity. Gift cards are a catalog: pay the invoice address a gift card checkout gives you.

The Relay leg

A payment is one Relay quote, EXACT_OUTPUT: ETH on Robinhood Chain (4663) in, USDC on Base (8453) out, to the recipient you name.

POST https://api.relay.link/quote/v2
{"user": "<wallet>", "recipient": "<address>",
 "originChainId": 4663, "destinationChainId": 8453,
 "originCurrency": "0x0000000000000000000000000000000000000000",
 "destinationCurrency": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
 "amount": "25000000", "tradeType": "EXACT_OUTPUT"}

Checked live on 2026-10-13: 25 USDC on Base cost 0.009974 ETH ($25.04) from Robinhood Chain, about 2 seconds, fees near $0.06 (relayer service). The route is one step: a deposit transaction {to, data, value, chainId}, then /intents/status until it settles. The pocket switches the wallet to chain 4663, sends that transaction and polls the status.

Robinhood Chain

Muse

The first Muse gadget built for fun spending: the public skills catalog listed 43 device skills on 2026-10-13, and none of them keeps a budget.

Privacy

Stored, in a private Vercel Blob store: your profile (hobbies, weekly budget, payday), purchase records keyed by wallet, and the sha256 hash of your token. Used link nonces are kept so a signed message cannot be replayed.

Never stored: private keys, seed phrases, the token itself, and signatures beyond the moment they are verified. Browser mode stores nothing on the server; its data stays in this browser's localStorage.

Verify it yourself

curl -s https://chipo.cash/api/health
curl -s "https://chipo.cash/api/deals?hobbies=coffee,games&limit=3"

The first returns the live Relay chain count, the Robinhood Chain head and its age, the catalog date and the storage mode. The second returns ranked cards with their Bitrefill source URLs.

Risk

Relay is a third party, chains can stall, and smart contracts on the route can fail. A payment that settles cannot be reversed by this site, and the site cannot issue refunds. Each payment is capped. Nothing here is financial advice. Read the terms.