License sync
Once linked, your instance will:
- Validate the license on startup
- Sync usage data every hour by default (configurable via
LICENSE_SYNC_INTERVAL_SECONDS, accepted range 60..3600 seconds) - Cache limits locally for fast quota checks
- Report instance health and service stats
Sync runs in-process — you don't need to configure an external cron job or Kubernetes CronJob. Your instance starts syncing automatically after boot.
If a sync fails
If the hub is unreachable or rejects the sync, your instance continues to use cached limits for up to 24 hours (cache TTL) + 24 hours (grace period) before resource creation is blocked. In practice a short outage is invisible to your users.
The last error from the most recent failed sync is persisted and shown on your Admin dashboard (/admin) as a red banner with the error text and timestamp — no need to check server logs or a Kubernetes dashboard. A Retry Sync button on the same card lets you trigger an immediate sync without restarting the instance.
Sync Response
The license sync returns limits and feature flags that your instance uses to gate functionality:
{
"valid": true,
"limits": {
"projects": 20,
"apps": 50,
"databases": 25,
"domains": 50,
"customDomains": 10,
"freeSubdomains": 5,
"purchasableDomains": 0,
"teamMembers": 20,
"buildMinutes": 2000,
"storageBytes": 268435456000,
"instances": 3
},
"features": {
"whiteLabel": false,
"customDomains": true,
"domainPurchase": false,
"aiAssistant": true,
"multiServer": true,
"prioritySupport": false
},
"effectiveRemaining": {
"projects": 8,
"apps": 22,
"databases": 12,
"domains": 20,
"customDomains": 4,
"purchasedDomains": 5,
"freeSubdomains": 7,
"teamMembers": 5,
"buildMinutes": 1150,
"storageBytes": 214748364800
},
"warnings": [],
"billingPeriodReset": "2025-02-01T00:00:00Z",
"gracePeriodHours": 24,
"cacheExpiresAt": "2025-01-12T00:00:00Z"
}
Domain Limits
The sync response includes domain-specific limits:
| Limit | Description |
|---|---|
domains | Total domain slots (legacy) |
customDomains | User-provided custom domains allowed |
freeSubdomains | Free *.kuploy.app subdomains allowed |
purchasableDomains | Domains purchasable through the platform (Enterprise only) |
Multi-Instance Aggregate Quotas
If your plan allows multiple instances (Business: 3, Enterprise: unlimited), usage is aggregated across all instances under the same license.
For example, with a Growth plan (20 project limit):
- Instance A has 8 projects
- Instance B has 5 projects
- Instance C has 3 projects
- Aggregate: 16/20 (80%) — a warning is triggered
Rather than echoing every instance's raw counts back to each instance, kuploy.app sends each instance a per-resource effectiveRemaining number — how many more of each resource that instance may still create under the license. In the example above, each instance would see projects: 4 in its sync response, and its local canCreate() gate allows up to 4 more projects before the aggregate limit is reached.
Instances never see sibling instances' individual counts; only the pre-computed headroom. Warnings and thresholds are also computed server-side and included in the sync response.
Offline Behavior
If your instance can't reach the license hub:
- Cached limits continue to work
- Local quota enforcement remains active
- Usage deltas are queued for next sync
- A warning banner appears in the dashboard
When connection is restored, your instance will sync all pending usage data.
Cache State Machine
The license cache follows this state progression:
| State | Description | Behavior |
|---|---|---|
fresh | Valid license, cache within TTL | Full operation allowed |
stale | Valid license, cache expired, in grace period | Operations allowed, warning banner shown |
frozen | Grace period expired, cannot reach server | New resource creation blocked |
empty | No license configured | Blocks creation if LICENSE_KEY expected |
invalid | License validation failed | New resource creation blocked |