The interface: a landing page that runs the demo live, and a dashboard an owner creates and manages allowances from. Deployed at stellar-allowance.vercel.app.
The owner signs once. The agent's keypair is generated in the browser during that same step and its secret is shown one time; nothing stores it. The rest is the interface reading the chain and submitting what was signed.
Fetching those URLs happens in /api/offer, not on the page. Sellers send no cross-origin
headers, so a browser cannot read a 402 for itself. That route holds no keys, signs nothing, and
makes the same unpaid GET anyone can make.
Nobody is asked which index to use. Sixty addresses are derived from the owner, their contract
instance entries are fetched in one getLedgerEntries call, and the first address that answers
with nothing is where the next allowance goes.
Pressing the button funds an owner through friendbot, swaps XLM for USDC on the testnet DEX, deploys an allowance, pays a live x402 API and shows two payments refused on chain. All of it from the page: there is no route behind the button and nothing of ours in the path.
That matters under load. A serverless function would serialise on a module-level flag within one instance and cap nothing across instances, and every run would reach friendbot from one shared address, which is what friendbot rate limits. Runs from a hundred browsers are a hundred addresses.
npm run bake drives the same generator from Node and records the result into
lib/demo/baked.json, which is what the page shows before anyone presses anything.
The SDK is linked from ../sdk, so build it once before the first run.
npm --prefix ../sdk install && npm --prefix ../sdk run build
npm install
npm run devTwo values, both public, and no secret. The demo generates every keypair it uses inside the run and discards it, in the visitor's own browser.
NEXT_PUBLIC_SITE_URL |
absolute base for the link preview. Defaults to http://localhost:3000 |
NEXT_PUBLIC_SELLER_URL |
the x402 API the demo pays. Point it at a local seller to develop against one |
npm test # unit
npx playwright test # end to end, against a dev server it starts itself
npm run bake # re-record the run the landing page loads with