GenerateSaaS

Licensing & Heartbeat

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

Every generated project carries a license JWT in its .generatesaas/manifest.json manifest, and a daily heartbeat job in @repo/api POSTs it to validate your installation. Revenue sharing is a self-reported boolean in that manifest - not a @repo/config flag, so it gates no features.

The heartbeat is by design, not removable telemetry - it validates your license and sends no application or user data. The supported, permanent opt-out is generatesaas eject (see 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.

FieldTypePurpose
licenseTokenstringLicense JWT. Empty → license layer dormant, no heartbeat.
licenseKeyHashstringHash of your license key, paired with the token.
installIdstringUnique scaffold identifier.
versionstringTemplate version this project currently tracks.
initialVersionstringTemplate version first scaffolded from.
frontendstringFrontend framework recorded at scaffold time.
appNamestringDisplay name from scaffold time; the recognizable title for this project in your generatesaas.com dashboard.
projectNamestringProject slug from scaffold time; a stable fallback identifier.
revenueSharingbooleanSelf-reported opt-in; defaults to false. Not a config flag.

The same file also records repo, architecture, aiTools, deploymentTarget, databaseProvider, and cacheProvider for generatesaas update. Of all these, only version, frontend, appName, projectName, and revenueSharing are sent in the heartbeat (plus a derived domain).

The daily heartbeat

The heartbeat is an Inngest cron in packages/api/src/functions/maintenance/license-heartbeat.ts. It runs on the schedule below and is listed among the full cron roster in Background jobs. Each heartbeat also keeps the Projects section of your generatesaas.com dashboard current, so you can monitor every install's domain, version freshness, and last check-in there.

PropertyValue
ScheduleDaily, at a stable per-install time of day
Endpointhttps://generatesaas.com/api/v1/heartbeat
Method / authPOST, Authorization: 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:

// body of POST https://generatesaas.com/api/v1/heartbeat
{
  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: revenueSharing ?? false // from manifest
}

When revenue sharing is enabled in the manifest, the heartbeat additionally includes self-reported revenue metrics - MRR, ARR, all-time total revenue, trailing 30-day revenue, and active-subscription count (with mrrCurrency) - computed from this app's own subscriptions and the fiat amounts recorded on its billing logs. With the opt-in off, nothing revenue-related is computed or sent.

Opting out

To sever every GenerateSaaS tie permanently, run eject. Commit first so the change is reviewable.

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.

Frequently asked questions

Is the heartbeat telemetry I should remove? No. It is license validation by design - it sends no application or user data, only the manifest fields above. Editing or deleting the job is unsupported; use eject for a clean opt-out.

Does it run if I never authenticate? No. With an empty licenseToken the function returns { sent: false, reason: "no-license-token" } and the license layer stays dormant.

Where are revenue-sharing terms stored? In the revenueSharing boolean inside .generatesaas/manifest.json. It is self-reported, defaults to false, and is not a @repo/config flag, so it gates nothing.

What does the heartbeat actually send? Only domain, version, frontend, appName, projectName, and revenueSharing - authenticated with your license JWT as a bearer token. If you opted into revenue sharing, it also self-reports an estimated MRR (mrr, mrrCurrency); without the opt-in no revenue data is computed or sent.

On this page