Payments Cloud

Cloud Billing Worker

Cloudflare Worker + D1 backend for Stripe Checkout, Customer Portal, webhooks, entitlement state, device activation, and license status.

Cloud Billing Form

Billing rehearsal

Checking command-center API...

Do not paste Stripe keys, webhook secrets, license signing secrets, API tokens, or customer data into dashboard files.

Cloud Billing Snapshot

Status Cloudflare Worker + D1 billing backend scaffold implemented locally; live deployment remains blocked on Cloudflare account, D1 database ID, billing domain, Stripe secrets, price, Customer Portal, support, and legal review Ready
Worker URL Needs deployed Worker URL Needs input
D1 Database ID Needs D1 database ID Needs input
Secret Status Not configured Ready
Config Sync Billing Worker Config Waiting On Handoffs Ready
Check npm run cloud:billing:check Ready
Readiness npm run test:cloud-billing-worker Ready

Billing Worker Config Sync

npm run cloud:billing:config:sync

This turns Cloud Billing page answers into non-secret production Worker config, including ALLOWED_ORIGIN, D1 database_id, and Stripe API version. Stripe keys, webhook secrets, license secrets, and customer data stay out of repo files.

Status Billing Worker Config Waiting On Handoffs Ready
Applied 0 Ready
Waiting 1 Ready
Invalid 0 Ready

Applied

  • No config values changed on the last sync.

Waiting

  • Production billing D1 database_id: Create the billing D1 database and enter billingCloud.d1DatabaseId in the dashboard.

Needs Fix

Routes

RouteStatus
GET /healthReady
POST /api/billing/checkoutReady
POST /api/billing/portalReady
POST /api/billing/webhookReady
GET /api/license/statusReady

Secrets

SecretWhere
STRIPE_SECRET_KEYSecret store
STRIPE_WEBHOOK_SECRETSecret store
NYRA_STRIPE_PRICE_PRO_MONTHLYSecret store
NYRA_BILLING_SUCCESS_URLSecret store
NYRA_BILLING_CANCEL_URLSecret store
NYRA_BILLING_RETURN_URLSecret store
NYRA_LICENSE_API_TOKENSecret store
NYRA_LICENSE_SIGNING_SECRETSecret store

Live Blockers

Deployment Manifest

{
  "service": "nyra-billing-api",
  "scope": "Cloudflare Worker and D1 billing backend for NyrA Swarm Little Buddy paid beta",
  "runtime": "Cloudflare Workers",
  "storage": {
    "type": "Cloudflare D1",
    "binding": "DB",
    "databaseName": "nyra_billing",
    "migrationsDir": "cloud/billing-worker/migrations",
    "tables": [
      "billing_customers",
      "processed_events",
      "device_activations"
    ]
  },
  "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"
  ],
  "requiredVars": [
    "ALLOWED_ORIGIN",
    "STRIPE_API_VERSION"
  ],
  "checks": [
    "npm run cloud:billing:check",
    "npm run test:cloud-billing-worker"
  ],
  "liveBlockers": [
    "Cloudflare account and D1 database ID",
    "Billing Worker custom domain",
    "Stripe test/live secrets in Wrangler secret store",
    "Stripe product/price after final monthly price",
    "Customer Portal configuration",
    "Stripe webhook endpoint and signing secret",
    "Support inbox roundtrip",
    "Attorney/accountant review"
  ]
}

Wrangler Config

{
  "$schema": "../../node_modules/wrangler/config-schema.json",
  "name": "nyra-billing-api",
  "main": "src/index.mjs",
  "compatibility_date": "2026-05-31",
  "compatibility_flags": [
    "nodejs_compat"
  ],
  "observability": {
    "enabled": true
  },
  "vars": {
    "ALLOWED_ORIGIN": "http://localhost:5173",
    "STRIPE_API_VERSION": "2026-02-25.clover"
  },
  "d1_databases": [
    {
      "binding": "DB",
      "database_name": "nyra_billing",
      "database_id": "replace-with-cloudflare-d1-database-id",
      "migrations_dir": "migrations"
    }
  ],
  "env": {
    "local": {
      "vars": {
        "ALLOWED_ORIGIN": "http://localhost:5173",
        "STRIPE_API_VERSION": "2026-02-25.clover"
      },
      "d1_databases": [
        {
          "binding": "DB",
          "database_name": "nyra_billing",
          "database_id": "replace-with-cloudflare-d1-database-id",
          "migrations_dir": "migrations"
        }
      ]
    },
    "production": {
      "vars": {
        "ALLOWED_ORIGIN": "https://porterlabz.com",
        "STRIPE_API_VERSION": "2026-02-25.clover"
      },
      "d1_databases": [
        {
          "binding": "DB",
          "database_name": "nyra_billing",
          "database_id": "replace-with-cloudflare-d1-database-id",
          "migrations_dir": "migrations"
        }
      ]
    }
  }
}

D1 Migration

CREATE TABLE IF NOT EXISTS billing_customers (
  customer_id TEXT PRIMARY KEY,
  checkout_session_id TEXT,
  subscription_id TEXT,
  device_id TEXT,
  email TEXT,
  status TEXT,
  entitlement TEXT,
  price_id TEXT,
  current_period_end INTEGER,
  cancel_at_period_end INTEGER NOT NULL DEFAULT 0,
  last_invoice_id TEXT,
  last_invoice_status TEXT,
  stripe_entitlements_json TEXT,
  updated_at TEXT NOT NULL
) STRICT;

CREATE INDEX IF NOT EXISTS idx_billing_customers_checkout_device
  ON billing_customers (checkout_session_id, device_id);

CREATE INDEX IF NOT EXISTS idx_billing_customers_subscription
  ON billing_customers (subscription_id);

CREATE TABLE IF NOT EXISTS processed_events (
  event_id TEXT PRIMARY KEY,
  type TEXT NOT NULL,
  processed_at TEXT NOT NULL
) STRICT;

CREATE TABLE IF NOT EXISTS device_activations (
  customer_id TEXT NOT NULL,
  device_id TEXT NOT NULL,
  activated_at TEXT NOT NULL,
  last_checked_at TEXT NOT NULL,
  last_active INTEGER NOT NULL DEFAULT 0,
  PRIMARY KEY (customer_id, device_id)
) STRICT;

NyrA Cloud Billing Worker

This Worker is the Cloudflare-native billing backend path for NyrA Swarm Little Buddy. It mirrors the local Node billing service routes while replacing file-backed entitlement storage with D1.

It does not contain live Stripe keys, webhook secrets, certificate material, or customer data.

Routes

Route Purpose
GET /health Verifies required secrets and D1 reachability.
POST /api/billing/checkout Creates a Stripe Checkout Session in subscription mode.
POST /api/billing/portal Creates a Stripe Customer Portal Session for an authenticated customer/device.
POST /api/billing/webhook Verifies Stripe webhook signatures and records subscription/customer state.
GET /api/license/status Returns active entitlement, offline grace metadata, device activation, license blob, and device access token.

Device access tokens are signed bearer tokens for the paid device and include expiresAt. They expire at the subscription offline-grace boundary when Stripe period data is available, or after a 24-hour fallback window while checkout/subscription state is still settling.

Storage

D1 tables are defined in migrations/0001_billing.sql:

This path removes the paid-beta need for NYRA_ENTITLEMENTS_FILE when the Worker is selected as the hosted backend, but it still requires a real Cloudflare account, D1 database, custom domain, Stripe secrets, webhook endpoint, and support/legal readiness before live payments.

Required Secrets

Set these with wrangler secret put or the Cloudflare dashboard secret store. Do not commit them.

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

Local Checks

npm run cloud:billing:check
npm run test:cloud-billing-worker

Deploy Rehearsal

npx wrangler d1 create nyra_billing
npx wrangler d1 migrations apply nyra_billing --cwd cloud/billing-worker --local
npx wrangler dev --cwd cloud/billing-worker --env local

For production, replace the D1 database ID in wrangler.jsonc, set secrets outside the repo, configure the Stripe webhook endpoint to https://<billing-domain>/api/billing/webhook, and use Stripe test mode first.

After saving the Cloud Billing dashboard fields, run:

npm run cloud:billing:config:sync
npm run test:cloud-billing-config-sync

The sync writes only non-secret production Worker config values such as ALLOWED_ORIGIN, D1 database_id, and the pinned Stripe API version. Stripe keys, webhook secrets, license secrets, and customer data must stay in Wrangler secrets, Stripe, or temporary shell variables.

No-Go Rules

Cloud Billing Worker Deployment Checklist

This checklist is for the Cloudflare Worker + D1 hosted billing path. It is not legal, tax, accounting, or Stripe support advice.

Before Deployment

Required Cloudflare Secrets

Use wrangler secret put or Cloudflare dashboard secrets:

Required Verification

Run locally:

npm run cloud:billing:check
npm run cloud:billing:config:sync
npm run test:cloud-billing-config-sync
npm run test:cloud-billing-worker
npm run billing:live-preflight -- --mode test --allow-blocked

Then, against the hosted Worker in Stripe test mode:

Rollback