Cloudflare Worker that serves as the backend for Cmdr: licensing, telemetry, crash reports, downloads, and admin endpoints.
For architecture, data flow, environments, and dev instructions, see CLAUDE.md.
User clicks "Buy" on getcmdr.com
→ Paddle checkout
→ User pays → Paddle sends webhook to this server
→ Server generates Ed25519-signed license key
→ Server emails license key to user via Resend
→ User enters key in Cmdr app
→ App validates signature locally (no server call needed)
These steps only need to be done once, by a human. After this, agents can handle dev and deployment via the instructions in CLAUDE.md.
pnpm install- Generate Ed25519 key pair:
pnpm run generate-keys→keys/public.key+keys/private.key - Copy public key hex to
PUBLIC_KEY_HEXinverification.rs - Resend: Create API key at https://resend.com/api-keys. Add
getcmdr.comdomain at https://resend.com/domains (adds DNS records to Cloudflare automatically). - Paddle: Create accounts at https://paddle.com (live) and https://sandbox-vendors.paddle.com (sandbox).
- Paddle (both environments): Create product "Cmdr" (standard tax category), then two prices:
- Commercial subscription: $59/year
- Commercial perpetual: $199, one-time
- Paddle (both environments): Create notification destination → webhook URL, subscribe to
transaction.completed.- Sandbox:
https://unsickerly-acclivitous-lala.ngrok-free.dev/webhook/paddle(for local dev via ngrok) - Live:
https://api.getcmdr.com/webhook/paddle
- Sandbox:
- Cloudflare: Set
CLOUDFLARE_API_TOKEN(see cloudflare.md). - Wrangler secrets (deployed worker, live values):
npx wrangler secret put PADDLE_WEBHOOK_SECRET_LIVE npx wrangler secret put PADDLE_WEBHOOK_SECRET_SANDBOX npx wrangler secret put PADDLE_API_KEY_LIVE npx wrangler secret put PADDLE_API_KEY_SANDBOX npx wrangler secret put ED25519_PRIVATE_KEY npx wrangler secret put RESEND_API_KEY npx wrangler secret put PADDLE_ENVIRONMENT # "live" npx wrangler secret put PRICE_ID_COMMERCIAL_SUBSCRIPTION # live price ID npx wrangler secret put PRICE_ID_COMMERCIAL_PERPETUAL # live price ID .dev.vars(local dev, sandbox values): see CLAUDE.md for the full table.- Save
keys/private.keyin a secure store, then delete it from the filesystem. - Deploy:
cd apps/api-server && npx wrangler deploy
Test the full purchase flow through Paddle's sandbox. Only works with sandbox credentials.
- The default payment link in Paddle sandbox should be
http://localhost:4321(the local website). Live useshttps://getcmdr.com. Check at https://sandbox-vendors.paddle.com/checkout-settings. - Create a client-side token: https://sandbox-vendors.paddle.com/authentication-v2 → "Client-side tokens" tab →
create (starts with
test_).
Start the local website (pnpm dev in apps/website) and the local API server (pnpm dev in apps/api-server +
ngrok). Then use the buy buttons on http://localhost:4321/pricing/.
Use test card 4000 0566 5566 5556 / CVC 100. More test cards:
https://developer.paddle.com/concepts/payment-methods/credit-debit-card#test-payment-details
Standalone checkout playground: There's also a minimal test page at pnpm test:checkout (port 3333). To use it,
temporarily change the default payment link to http://localhost:3333 in the sandbox checkout settings.
| Error | Fix |
|---|---|
| "Something went wrong" | Check default payment link matches your localhost origin |
Token doesn't start with test_ |
Use sandbox token from sandbox-vendors.paddle.com |
| "Invalid price" | Ensure price ID is from the same sandbox account |