Payment Center
Stripe
Subscription, Customer Portal, webhook, billing backend deployment, and license activation command page.
Payment Launch Pack
Open packUse this pack as the exact money-path checklist before creating Stripe products, prices, webhook endpoints, or live checkout links.
Stripe Setup Runbook
Scope: NyrA Swarm Little Buddy desktop app only
This runbook is for the first paid launch path. It is not a substitute for tax, accounting, or legal advice.
Stripe Integration Choice
Use:
- Stripe Billing for subscriptions.
- Stripe-hosted Checkout for signup/payment.
- Stripe Customer Portal for cancellation, payment method updates, and invoices.
- Webhooks for entitlement updates.
- Server-side Stripe secret keys only.
Do not:
- Put Stripe secret keys in Electron.
- Trust local desktop state as the source of subscription truth.
- Build manual recurring billing loops with raw PaymentIntents.
- Make cancellation harder than signup.
Dashboard Setup
- Confirm Stripe account identity.
- Set public business name and branding.
- Create product:
- Name: NyrA Swarm Little Buddy Pro
- Type: subscription product
- Create monthly price:
- Currency: USD
- Amount: use the user-approved output from the command center Pricing page.
- Trial: none
- Configure Customer Portal:
- Enable invoice history.
- Enable payment method updates.
- Enable cancellation.
- Enable plan changes only after multiple plans exist.
- Configure Stripe Tax or document launch tax scope.
- Add webhook endpoint once backend URL exists.
Webhook Events
Minimum events to process:
checkout.session.completedinvoice.paidinvoice.payment_failedcustomer.subscription.updatedcustomer.subscription.deleted
Recommended when using Stripe Entitlements:
entitlements.active_entitlement_summary.updated
Backend Requirements
The payment/license backend needs:
POST /api/billing/checkoutPOST /api/billing/portalPOST /api/billing/webhookGET /api/license/status- A customer table.
- A device activation table.
- A subscription/entitlement table.
- Webhook idempotency records.
- License token signing.
Initial implementation files:
server/nyra-billing-server.mjsserver/billing-config.example.envserver/check-billing-setup.mjsserver/README.mdsrc/services/license.tssrc/features/billing/LicensePanel.tsxdocs/license-activation-gates.mjs
Validation command:
npm run billing:checknpm run billing:smokenpm run billing:live-preflight -- --mode testnpm run test:billing-live-rehearsal
Local helper commands:
npm run billing:init-envnpm run pricing:modelnpm run billing:stripe-setup -- --env server/.env.local --price-cents 2500npm run billing:stripe-setup -- --env server/.env.local --price-cents 2500 --executenpm run billing:live-preflight -- --mode testnpm run billing:live-rehearsal -- --mode test
The setup tool dry-runs by default. It only creates Stripe resources with --execute.
Desktop Requirements
The Electron app needs:
- Billing screen or activation screen. Status: alpha Settings panel exists.
- Device ID generation. Status: alpha client generates/stores a device ID.
- License activation. Status: checkout-session claim and device-scoped access token flow exists locally.
- Entitlement refresh. Status: alpha refresh button and service helper exist.
- Offline grace period. Status: server returns grace metadata and client caches active licenses.
- Expired subscription state. Status: inactive/error state appears in the Settings panel.
- Customer Portal button. Status: button calls the server-side portal route with the device access token.
- Billing/support links.
- Paid feature enforcement. Status: main-process IPC gate blocks API swarm chat, voice, realtime, screen capture, computer control, file/app control, and developer terminal unless an active cached license is still inside offline grace.
The internal NYRA_LICENSE_API_TOKEN remains server-side only for admin/smoke checks. Customers should activate with checkout session + device token, not a shared API token.
Test Mode Checklist
- New checkout succeeds.
- No-trial subscription activates immediately after payment.
- Customer Portal opens for the authenticated customer.
- Customer can cancel.
- Canceled subscription revokes access at the correct time.
- Failed invoice limits access.
- Duplicate webhook does not double-apply.
- Out-of-order webhook does not corrupt entitlement state.
- Desktop reinstall can reactivate a valid customer.
- Expired license blocks paid features cleanly.
Use docs/billing/BILLING_LIVE_REHEARSAL.md and the command-center Billing Rehearsal page for the guarded preflight before creating live payment paths.
Current Blockers
- Product/price cannot be created safely until monthly price is chosen from the Pricing page.
- Support email must be created or confirmed.
- Business/legal identity must be accurate in Stripe.
- Domain/success/cancel URLs are not chosen.
- Hosted AI launch budget/limits are not chosen from the Pricing page.
NyrA Billing Server
This is the first server-side payment and licensing service for the Swarm Little Buddy app.
It uses Stripe-hosted Checkout, Stripe Customer Portal, Stripe webhooks, and a local JSON entitlement store for early beta/dev wiring. Replace the JSON store with a real database before public launch.
The paid-beta JSON store now has atomic writes and /health runs a writable storage probe. In production or when NYRA_BILLING_REQUIRE_PERSISTENT_STORAGE=true, the server refuses to start unless NYRA_ENTITLEMENTS_FILE is set to an absolute mounted persistent path.
Commands
npm run billing:check
npm run billing:init-env
npm run billing:smoke
npm run test:billing-storage
npm run billing:stripe-setup -- --env server/.env.local
npm run billing:live-preflight -- --mode test
npm run billing:live-rehearsal -- --mode test
npm run billing:server
npm run test:billing-deploy
npm run test:billing-live-rehearsal
Local Config
Copy server/billing-config.example.env into your local secret manager or shell environment. Do not commit real Stripe keys.
Required values:
STRIPE_SECRET_KEYSTRIPE_WEBHOOK_SECRETNYRA_STRIPE_PRICE_PRO_MONTHLYNYRA_BILLING_SUCCESS_URLNYRA_BILLING_CANCEL_URLNYRA_BILLING_RETURN_URLNYRA_LICENSE_API_TOKENNYRA_LICENSE_SIGNING_SECRETNYRA_ENTITLEMENTS_FILENYRA_BILLING_REQUIRE_PERSISTENT_STORAGE
Routes
GET /healthPOST /api/billing/checkoutPOST /api/billing/portalPOST /api/billing/webhookGET /api/license/status
Customer checkout is public:
POST /api/billing/checkout
Customer license activation uses the paid checkout session plus the local device ID:
GET /api/license/status?checkoutSessionId=<cs_...>&deviceId=<device-id>
When active, the server returns a signed deviceAccessToken. Future license checks and Customer Portal requests use:
Authorization: Bearer <deviceAccessToken>
The internal NYRA_LICENSE_API_TOKEN is still available for server/admin smoke tests and controlled back-office checks. It should not be entered into the customer desktop app.
Deployment Pack
The backend now has a standalone deployment shape under server/:
server/package.json: minimal production dependency manifest for the billing service.server/Dockerfile: Node 24 production container with health check and non-root runtime user.server/.dockerignore: keeps.env*,.data, logs, and local dependencies out of container builds.server/deployment-manifest.json: machine-readable routes, secrets, storage, webhook, and blocker list.server/DEPLOYMENT_CHECKLIST.md: human handoff for a container host with HTTPS, secret store, logs, and persistent storage.
Validate the deploy pack:
npm run test:billing-deploy
npm run test:billing-storage
Build locally when Docker is available:
docker build -f server/Dockerfile server -t nyra-billing-server:local
Do not deploy live mode until the command center has a monthly price, hosted AI cap, domain/backend URL, confirmed support inbox, Stripe identity/tax setup, Stripe product/price, Customer Portal configuration, webhook secret, and attorney/accountant review status.
Use docs/billing/BILLING_LIVE_REHEARSAL.md before live mode. It checks command-center decisions, required Stripe webhook events, Customer Portal/support/legal blockers, secret shapes, HTTPS URLs, and live-mode approval flags without printing secret values.
Current Limits
- The entitlement store is a local JSON file for early development.
- Desktop activation uses checkout-session claiming plus a device-scoped access token. The internal server token is no longer entered into Settings.
- License status records device activation checks and returns offline grace metadata.
- Stripe product and price still need to be created after the monthly price is chosen.
- Customer Portal must be configured in the Stripe Dashboard.
Desktop Activation Shell
The app Settings panel includes License & Billing.
Current device activation flow:
- Start the billing server.
- Enter the billing server URL and checkout email in Settings.
- Use
Start Checkoutto open Stripe Checkout. - Use
Refresh Activationafter webhooks update entitlement state. - The server exchanges the paid checkout session for a signed device access token.
- Use
Billing Portalfor subscription management after activation.
The desktop caches the signed license response and uses the server-provided offline grace timestamp if the billing server is temporarily unreachable.
Stripe Product/Price Tool
Dry run:
npm run billing:stripe-setup -- --env server/.env.local --price-cents 2500
Create or reuse product/price in the Stripe account:
npm run billing:stripe-setup -- --env server/.env.local --price-cents 2500 --execute
Create or reuse product/price and create a payment link:
npm run billing:stripe-setup -- --env server/.env.local --price-cents 2500 --execute --payment-link
Use test keys first. Do not use live keys until pricing, support email, tax setup, domain URLs, and policy pages are ready.
NyrA Billing Backend Deployment Checklist
Scope: NyrA Swarm Little Buddy paid beta only.
This service is the server-side Stripe Checkout, Customer Portal, webhook, and license activation backend. Stripe secret keys must stay here, never in Electron.
Deployable Shape
- Runtime: Node.js 24.
- Container entrypoint:
server/Dockerfile. - Build context:
server. - Start command:
node nyra-billing-server.mjs. - Health check:
GET /health. - Public webhook path:
POST /api/billing/webhook. - Customer checkout path:
POST /api/billing/checkout. - Customer portal path:
POST /api/billing/portal. - License check path:
GET /api/license/status.
Build locally when Docker is available:
docker build -f server/Dockerfile server -t nyra-billing-server:local
Run locally with a private env file:
docker run --rm --env-file server/.env.local -p 8788:8788 nyra-billing-server:local
Do not commit .env.local, live Stripe keys, webhook secrets, signing secrets, or entitlement data.
Required Secret Store Values
STRIPE_SECRET_KEYSTRIPE_WEBHOOK_SECRETNYRA_STRIPE_PRICE_PRO_MONTHLYNYRA_BILLING_SUCCESS_URLNYRA_BILLING_CANCEL_URLNYRA_BILLING_RETURN_URLNYRA_LICENSE_API_TOKENNYRA_LICENSE_SIGNING_SECRETNYRA_ENTITLEMENTS_FILEif using a mounted persistent file storeNYRA_BILLING_REQUIRE_PERSISTENT_STORAGE=truefor hosted paid-beta billing
Host Requirements
- HTTPS public URL for the backend.
- Private secret store.
- Logs available for webhook/debug review.
- Persistent disk for
NYRA_ENTITLEMENTS_FILEduring paid-beta rehearsal, or a managed database before broader public launch. NYRA_ENTITLEMENTS_FILEmust be an absolute mounted persistent path whenNYRA_BILLING_REQUIRE_PERSISTENT_STORAGE=trueorNODE_ENV=production.GET /healthverifies entitlement storage is writable through a probe file before reportingok: true.- Ability to configure Stripe webhook endpoint to:
https://<billing-domain>/api/billing/webhook
Stripe Dashboard Steps
- Confirm business identity, payout, statement descriptor, and support details.
- Create
NyrA Swarm Little Buddy Promonthly subscription price after the monthly price is chosen. - Configure Customer Portal for cancellation, payment method updates, and invoices.
- Add webhook endpoint after the backend public URL exists.
- Store the webhook signing secret in the deployment secret store.
- Test checkout, portal, cancellation, failed invoice, duplicate webhook, and desktop reactivation in Stripe test mode.
- Run the guarded rehearsal preflight before exposing any paid checkout link:
npm run billing:live-preflight -- --mode test
Go/No-Go
No live paid beta until these are true:
- Monthly price is saved in the command center.
- Hosted AI cap is saved in the command center.
- Pricing model snapshot is current:
npm run pricing:modelandnpm run test:pricing-model. - Billing live rehearsal static gate passes:
npm run test:billing-live-rehearsal. - Billing storage guard passes:
npm run test:billing-storage. - Billing live preflight passes against the intended mode and environment.
- Support inbox is confirmed.
- Domain and backend HTTPS URL are chosen.
- Stripe product and price exist.
- Customer Portal cancellation is enabled.
- Webhook endpoint is receiving test-mode events.
- License activation and paid-feature gates pass against the hosted backend.
- Attorney/accountant review is complete enough for paid beta.
Rollback
If hosted billing fails during beta:
- Disable or pause the Stripe price.
- Remove the checkout CTA from the public launch site.
- Keep existing customers able to open Customer Portal.
- Preserve entitlement storage and logs.
- Announce support path and fix window through the support inbox.
Deployment Manifest
{
"service": "nyra-billing-server",
"scope": "NyrA Swarm Little Buddy paid beta billing and license activation",
"runtime": "Node.js 24",
"container": {
"dockerfile": "server/Dockerfile",
"buildContext": "server",
"startCommand": "node nyra-billing-server.mjs",
"portEnv": "NYRA_BILLING_PORT",
"defaultPort": 8788,
"healthCheck": "GET /health"
},
"routes": [
"GET /health",
"POST /api/billing/checkout",
"POST /api/billing/portal",
"POST /api/billing/webhook",
"GET /api/license/status"
],
"requiredSecrets": [
"STRIPE_SECRET_KEY",
"STRIPE_WEBHOOK_SECRET",
"NYRA_STRIPE_PRICE_PRO_MONTHLY",
"NYRA_BILLING_SUCCESS_URL",
"NYRA_BILLING_CANCEL_URL",
"NYRA_BILLING_RETURN_URL",
"NYRA_LICENSE_API_TOKEN",
"NYRA_LICENSE_SIGNING_SECRET"
],
"storage": {
"current": "NYRA_ENTITLEMENTS_FILE JSON store with atomic writes and health-check writable probe for dev/paid-beta rehearsal",
"env": "NYRA_ENTITLEMENTS_FILE",
"productionGuard": "NYRA_BILLING_REQUIRE_PERSISTENT_STORAGE=true or NODE_ENV=production requires NYRA_ENTITLEMENTS_FILE to be an absolute mounted persistent path",
"healthCheck": "GET /health verifies entitlement storage is writable",
"paidBetaRequirement": "absolute mounted persistent disk at minimum",
"publicLaunchRequirement": "replace JSON file with managed database before broad public launch"
},
"stripeWebhook": {
"path": "/api/billing/webhook",
"requiredEvents": [
"checkout.session.completed",
"invoice.paid",
"invoice.payment_failed",
"customer.subscription.updated",
"customer.subscription.deleted"
],
"recommendedEvents": [
"entitlements.active_entitlement_summary.updated"
]
},
"externalBlockers": [
"monthly price",
"hosted AI cap",
"domain and HTTPS backend URL",
"confirmed support inbox",
"Stripe account identity/tax setup",
"Stripe product and price",
"Customer Portal configuration",
"webhook endpoint secret",
"persistent storage or managed database"
]
}