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.
| Field | Purpose |
|---|---|
licenseToken | License JWT. Empty means the license layer is dormant and no heartbeat runs. |
licenseKeyHash | Hash of your license key, paired with the token. |
installId | Unique scaffold identifier. |
version | Template version this project currently tracks. |
initialVersion | Template version first scaffolded from. |
frontend | The frontend the project was generated on. Always nextjs. |
appName | Display name from scaffold time - the recognizable title in your generatesaas.com dashboard. |
projectName | Project slug from scaffold time; a stable fallback identifier. |
revenueSharing | Your 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.
| Property | Value |
|---|---|
| Automation | Daily, at a stable per-install time of day |
| Endpoint | POST https://generatesaas.com/api/v1/heartbeat |
| Auth | Authorization: Bearer <licenseToken> |
| Retries | 3 |
| Skip condition | No 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.
generatesaas eject and type eject to confirm (it refuses if the manifest is missing)..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.
Manifest
The .generatesaas/manifest.json record of every option your project was built with, which update reads to re-shape each new boilerplate version into your exact configuration.
Eject
Permanently sever every GenerateSaaS tie - the heartbeat cron, the manifest, the internal license route, and the update tooling - leaving your application code untouched.