x402 temperature demo · architecture

Follow the money, then follow the packets

Two C4 views of the whole solution: the container diagram (what the pieces are and how they talk) and the deployment diagram (where each piece physically runs, from the cloud down to the physical sensor at home). Amber edges carry value; blue edges carry data; dashed grey is state & telemetry.

money path (signed payment / settlement) data & control state & telemetry

C4 · Level 2 — Container diagram

system: x402 Temperature Demo · numbers ①–⑤ are the actual protocol sequence

Buyer

[Person]

A human learner — follows the 3-step flow and approves each payment in the wallet.

Slush Wallet

[Software System · browser extension]

Holds the Sui keypair. Signs the gasless payment tx via the Wallet Standard — and never submits it.

x402 TEMPERATURE DEMO — ONE VERCEL PROJECT

Walkthrough SPA

[Container: React 19 · Vite · @mysten/dapp-kit]

Renders the annotated protocol steps and raw HTTP frames; builds the canonical payment transaction (withdrawal → redeem_funds → send_funds, ValidDuring bound to the challenge); polls the seller log.

Seller API

[Container: Vercel Functions · Node 24 · @suimpp/mpp/x402]

/api/temperature — issues single-use 402 terms, verifies X-PAYMENT structurally, fetches the reading, settles on Sui, serves.
/api/events — the seller’s side of the story.

Seller state

[Container: Upstash Redis]

challenges (10 min TTL) · digest replay store (3 d) · event log

Sui Testnet

[Software System · blockchain]

USDC settlement, ~400 ms finality. The seller verifies directly over gRPC — no facilitator.

Production temperature service

[Software System · existing, self-hosted]

Secret-path API over Home Assistant — the same service t2000 sells for real money on mainnet.

uses [HTTPS]
sign the payment — sign only, nothing hits the chain
GET → 402 + terms
GET + X-PAYMENT
polls /api/events
state
fetch reading first — sensor down ⇒ no charge
settle: executeTransaction(txBytes, sig)
Sign, don’t submitThe buyer’s wallet only ever signs. The signed bytes travel as an HTTP header; the seller is the one who touches the chain.
Why Redis existsThe 402-issuing invocation and the settling invocation are different serverless processes — challenges, replay digests and the log must live outside them.
Fetch before settleThe reference t2000 rail settles first and refunds on failure; this demo has no refund path, so it reads the sensor before taking the money.

C4 · Deployment diagram — production

testnet money · real sensor · no inbound ports anywhere near the house

BUYER WORKSTATION — BROWSER signing happens here, offline

Walkthrough SPA

[static assets from CDN]

Wallet extension (Slush)

[keys never leave the machine]
VERCEL CLOUD

Edge network

[CDN — serves dist/]

Serverless functions

[Fluid compute · Node 24]

api/temperature · api/events

UPSTASH CLOUD

Redis

[challenges · digests · log]
SUI TESTNET

Fullnode

[gRPC-web :443]
CLOUDFLARE EDGE

Public hostname

[Cloudflare Tunnel ingress — secret path]
PRIVATE HOME NETWORK
NAS — DOCKER COMPOSE

cloudflared

[outbound-only tunnel]

temp-paid-service

[node:24-alpine · :8402]

Home Assistant

[REST API · :8123]

Smart thermo sensor

[outdoor temperature probe]
app assets
/api/* [x402]
state
settle [gRPC]
GET the secret path [HTTPS]
tunnel — outbound only, zero port-forwarding
http://temp-api:8402
GET /api/states [Bearer]
integration
The house exposes nothingcloudflared dials out to Cloudflare; the public hostname terminates at the edge. There is no port-forward, and after go-live the :8402 LAN mapping can be dropped entirely.
The buyer’s machine never talks to SuiThe browser only fetches assets and calls /api/*. The only chain traffic in the whole system is the seller’s settle call and its chain-context reads.
Secrets stay server-sideThe secret service path lives only in Vercel env vars (and web/.env.local); the Home Assistant token only on the NAS. The repo contains neither.