GenerateSaaS

Licensing & Heartbeat

How the license manifest and the daily heartbeat cron validate your installation, exactly what the request sends, and how to opt out permanently with eject.

Every generated project carries a license JWT in .generatesaas/manifest.json, and a daily heartbeat job in @repo/api POSTs it to validate your installation. Each heartbeat also keeps the Projects section of your generatesaas.com dashboard current - domain, version freshness, last check-in.

The heartbeat is license validation by design, not removable telemetry - it sends no user data. With revenue sharing off it sends no application data either; with it on it adds your own aggregate revenue figures and nothing else. The permanent opt-out is eject.

The license manifest

.generatesaas/manifest.json is committed and bundled at build time by packages/api/src/lib/manifest.ts via a static JSON import. When licenseToken is empty, the license layer goes dormant and the heartbeat is skipped.

FieldPurpose
licenseTokenLicense JWT. Empty means the license layer is dormant and no heartbeat runs.
licenseKeyHashHash of your license key, paired with the token.
installIdUnique scaffold identifier.
versionTemplate version this project currently tracks.
initialVersionTemplate version first scaffolded from.
frontendThe frontend the project was generated on. Always nextjs.
appNameDisplay name from scaffold time - the recognizable title in your generatesaas.com dashboard.
projectNameProject slug from scaffold time; a stable fallback identifier.
revenueSharingYour init answer, kept as the fallback. config.revenueSharing.enabled takes precedence.

The file also records every option you chose at init - architecture, deploymentTarget, databaseProvider, cacheProvider, and the feature flags - for update to re-shape with. See the manifest reference for every field.

The daily heartbeat

An Inngest cron in packages/api/src/functions/maintenance/license-heartbeat.ts, listed with the rest in your project's Background jobs reference.

PropertyValue
AutomationDaily, at a stable per-install time of day
EndpointPOST https://generatesaas.com/api/v1/heartbeat
AuthAuthorization: Bearer <licenseToken>
Retries3
Skip conditionNo licenseToken returns { sent: false, reason: "no-license-token" }

The request body is the entire payload - license validation only, no app or user data:

{
  domain,          // env.API_URL host, falling back to config.baseUrl/domain
  version,         // from manifest
  frontend,        // from manifest
  appName,         // from manifest (display name)
  projectName,     // from manifest (slug)
  revenueSharing   // config.revenueSharing.enabled, else the manifest, else false
}

Revenue sharing

config.revenueSharing.enabled in packages/config/src/index.ts is the switch, seeded from your init answer and editable at any time. It gates no features. The manifest's revenueSharing boolean is the fallback for projects generated before that key existed.

  • On: the heartbeat adds six self-reported figures computed from this app's own subscriptions and billing logs - mrr, arr, totalRevenue, revenue30d, activeSubscriptions, mrrCurrency.
  • Off: nothing revenue-related is computed or sent, and figures already reported are cleared on the next heartbeat.

The figures are aggregate, not anonymous - they travel on the same request as your domain and appName. Cash amounts cover only the slice denominated in your base currency (mrrCurrency), never a sum across currencies that no customer was ever charged.

Opting out

To sever every GenerateSaaS tie permanently, run eject.

Commit your working tree so the eject diff is reviewable.
Run generatesaas eject and type eject to confirm (it refuses if the manifest is missing).
It deletes the heartbeat function, the manifest reader, and the internal license route; strips their registrations; removes .generatesaas/ and the AI skills; and cleans .gitignore.

After ejecting, your application code and @repo/config flags keep working - only the CLI's connective tissue and generatesaas update are gone. Editing or deleting the heartbeat job by hand is unsupported.

On this page