Skip to content

About

Subscription checkout paid on the Stellar blockchain: access granted only after Horizon confirms a memo-matched, single-use payment.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

StellarFit — Maco Gym Coach × Stellar

Online fitness coaching subscriptions paid over the Stellar blockchain (testnet MVP). A full-stack demo for a real coaching brand: the client picks a plan, pays in XLM, and access is granted only after the payment is cryptographically verified on-chain — the server trusts the ledger, never the client. Brand, palette, and plan structure reuse the pre-built Maco Gym Coach landing (a separate project, not included in this repo).

Key features

  • Three subscription tiers priced in XLM (Base 25 / Coaching 1:1 50 / Élite 100 per 30 days)
  • Memo-matched on-chain verification against Horizon: tx successful + exact memo + destination + amount ≥ price
  • Freighter wallet checkout: server builds an unsigned payment XDR, the user signs in the wallet
  • One-click demo payment and live client onboarding (friendbot-funded account created and charged on-chain)
  • Double-charge and anti-replay protection: each checkout binds to a unique FIT-XXXXXXXX memo, and every redeemed transaction hash is recorded single-use — a settled payment stays valid on-chain forever, so the memo alone would not stop it being re-submitted
  • Deployable to Vercel as a serverless function (vercel.json + api/index.js)

Tech stack: Node.js · Express · @stellar/stellar-sdk · Horizon (testnet) · vanilla HTML/JS frontend · Freighter wallet API · Vercel.

1. Technical blueprint

┌─────────────────────────────  BUILD TIME  ─────────────────────────────┐
│  AI Labs / Claude Code  ──►  Stellar Raven MCP (raven.stellar.org/mcp) │
│  The AI queries Raven's Search (283-entry catalog: docs, SDKs,         │
│  Horizon/RPC refs) + sandboxed Execute to generate/verify this code.   │
│  Raven is a dev-time copilot layer — NOT a runtime dependency.         │
└────────────────────────────────────────────────────────────────────────┘
┌──────────────────────────────  RUNTIME  ───────────────────────────────┐
│  Browser (public/index.html)                                           │
│    ├─ tier selection → POST /api/checkout  (order + unique memo)       │
│    ├─ Freighter wallet: /api/build-tx → sign in wallet → /api/submit   │
│    └─ Demo payer:      /api/pay-demo (server-signed, same rails)       │
│  Express API (server.js)                                               │
│    └─ verifyAndActivate(): loads tx from Horizon, checks               │
│       tx.successful + memo match + native payment op with              │
│       to == merchant && amount >= tier price → grants subscription     │
│  Stellar testnet (horizon-testnet.stellar.org)                         │
│    └─ source of truth: access is only granted from confirmed ledger    │
│       state, never from client claims                                  │
└────────────────────────────────────────────────────────────────────────┘

Why memo-based verification: each checkout gets a unique FIT-XXXXXXXX text memo. The payment is valid only if the on-chain transaction carries that exact memo, pays the merchant account, and covers the tier price. This is the standard Stellar deposit-matching pattern (same one exchanges use) — no smart contract needed, which is what makes it shippable in 30 minutes while remaining cryptographically verifiable.

2. 30-minute execution plan

Min Action
0–3 npm install
3–5 npm run setup — generates + friendbot-funds merchant & demo payer accounts, writes .env
5–6 npm start → open http://localhost:3000
6–9 Smoke test: pick Coaching 1:1 → ⚡ Pago demo 1-clic → verify ACCESS card + tx on Stellar Expert
9–14 Freighter test (optional): install extension, switch to Testnet, fund via friendbot, pay a tier
14–20 Pitch polish: open the Stellar Expert tx tab, rehearse the flow, screenshot the access card
20–25 Buffer for wifi/testnet hiccups (re-run npm run setup if friendbot rate-limits)
25–30 Live demo: tiers → checkout → on-chain payment → access confirmation

3. Quickstart

npm install
npm run setup   # one-time: creates funded testnet accounts → .env
npm start       # http://localhost:3000

Configuration

All configuration lives in .env (gitignored — start by copying .env.example). Everything is Stellar TESTNET only: the accounts hold test XLM with no real-world value, and no real funds are ever involved.

Variable What it is Where to get it
MERCHANT_PUBLIC Public key (G…) of the coach/merchant account that receives every subscription payment. Required — the server exits without it. Generated by npm run setup, or create a keypair manually (see below)
MERCHANT_SECRET Secret key (S…) of the merchant account. Written by setup.js for your reference; the server never reads it (it only receives payments). Same keypair as above
DEMO_PAYER_SECRET Secret key (S…) of a pre-funded testnet account that powers the one-click ⚡ Pago demo button. Optional — leave empty and the demo button is hidden. Second generated keypair
PORT Local HTTP port (default 3000). —

Creating the two testnet accounts

Easiest: run npm run setup. It generates both keypairs, funds each with 10,000 test XLM via friendbot, and writes .env for you.

Manual alternative:

  1. Generate two keypairs (e.g. in the Stellar Lab account creator, or Keypair.random() from @stellar/stellar-sdk).
  2. Fund each one on testnet: open https://friendbot.stellar.org?addr=<PUBLIC_KEY>.
  3. Copy .env.example to .env; put the first account's public key in MERCHANT_PUBLIC (and its secret in MERCHANT_SECRET), and the second account's secret in DEMO_PAYER_SECRET.

For Vercel, set the same variables in the project's Environment Variables settings (at minimum MERCHANT_PUBLIC; add DEMO_PAYER_SECRET if you want the demo button).

API

Endpoint What it does
GET /api/config network, merchant address, demo availability
GET /api/tiers subscription tiers (Base 25 / Coaching 50 / Élite 100 XLM)
POST /api/checkout {tier} creates pending order with unique memo
POST /api/build-tx {orderId, payerPublic} unsigned payment XDR for wallet signing
POST /api/submit {orderId, signedXdr} submits signed tx, verifies, activates
POST /api/pay-demo {orderId} server-side demo payment (real testnet tx)
POST /api/verify {orderId, txHash} verifies an externally-paid tx
GET /api/subscription/:account access check for a Stellar account

Demo-only endpoints

These let a visitor try the full flow without installing a wallet. They generate and accept Stellar secret keys over HTTP, which is acceptable only because every account here is a friendbot-funded testnet account holding no real value. Remove these routes before pointing this code at mainnet.

Endpoint What it does
POST /api/create-account generates a fresh testnet keypair, funds it via friendbot, returns it to the browser for instant onboarding
POST /api/pay-client signs a payment server-side using a secret supplied in the request body
GET /api/balances reads XLM balances for the demo accounts

Notes

  • Testnet only. Secrets live in .env (gitignored). For mainnet: remove the demo payer, keep only MERCHANT_PUBLIC on the server, switch Horizon URL + passphrase.
  • db.json is MVP-grade persistence (auto-created on first run, gitignored); swap for a real DB after the hackathon.
  • .mcp.json points at the official Stellar Raven MCP (https://raven.stellar.org/mcp) — the dev-time copilot used to build this project with Claude Code. Cloning the repo shares that config with any teammate; it is a build-time tool only, never a runtime dependency.
  • PITCH.md is the demo runbook, and public/slides.html the build-process slide deck.

Engineering highlights

A compact (~3k line) but complete blockchain payments slice: frontend -> API -> ledger verification -> access grant.

Languages JavaScript (Node), vanilla HTML/CSS/JS frontend
Backend Express REST API, deployable as a Vercel serverless function
Blockchain @stellar/stellar-sdk against Horizon (testnet) - builds unsigned payment XDRs, submits signed transactions, and reads the ledger as the source of truth
The core idea The server never trusts the client. Access is granted only after Horizon confirms a transaction that is successful, carries the order's unique memo, pays the merchant account, and covers the tier price.
Payment integrity Unique per-order memos, a single-use redemption ledger for transaction hashes (a settled payment stays valid on-chain forever, so the memo alone cannot prevent replay), and server-recomputed prices so a client can never lower the amount.
Wallet integration Freighter browser wallet - sign-in-wallet flow, plus a server-signed demo path for visitors without an extension

Skills demonstrated: blockchain/Web3 integration, cryptographic payment verification, REST API design, serverless deployment, wallet UX, and reasoning about replay and double-spend.

Disclaimer and terms of use

  • Stellar TESTNET only — this is a demo, not a payment product. Every account here is funded by friendbot with test XLM that has no monetary value. Do not point it at mainnet as-is.
  • The demo endpoints hand out secret keys on purpose. POST /api/create-account returns a freshly generated secret and POST /api/pay-client accepts one in the request body, so a visitor can try the flow without a wallet. That is only acceptable because the funds are worthless. Delete those routes before any mainnet adaptation (see the API section).
  • Not audited for production payments. Order state is a JSON file, there is no account system, and nothing here has had a financial-grade security review. Treat it as a reference implementation of on-chain payment verification, not as a payment gateway.
  • Not financial advice, and not affiliated with the Stellar Development Foundation, Freighter, or any wallet or exchange.
  • Brand. The storefront uses a real coaching brand as demo content, published with the owner's permission. If you fork this, replace that content with your own.
  • No warranty. Provided "as is", without warranty of any kind (see LICENSE).

License

MIT — see LICENSE. Copyright (c) 2026 Diego Ostertag.

About

Subscription checkout paid on the Stellar blockchain: access granted only after Horizon confirms a memo-matched, single-use payment.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages