Skip to content

Licensing & Tiers

LyEve runs the same engine image with or without a license. With no key it runs the free tier: the core CMS and every free feature, for production use and with no time limit. A license adds the paid features and capabilities it names. This page covers what each side holds, how to apply a license, how to choose which features start, and how to check what is running. Prices and plans are at lyeve.com/pricing.

If you want toRead
Know whether something costs moneyWhat runs free and What a license adds
Put a license on an installApply a license
Know what happens when a license lapsesWithout a license, and when one expires
Run fewer featuresChoose which features start
See what is on right nowCheck what is running

The core CMS is free: content types and entries, drafts and revisions, users and roles, sign-in, the Admin API and the Content API, on PostgreSQL, MySQL and SQL Server.

These features run on every install with no license key. The name is what LYEVE_PLUGINS and GET /api/admin/entitlements call the feature. Some are free up to a ceiling or hold back a paid part, and the capability in the last column lifts the ceiling or opens the part. Each feature's page names exactly what it gates.

FeatureNameFreePaid part
Access rulespermissionsRules for three rolesrbac-pro
AnalyticsanalyticsThe GA4, Mixpanel, Plausible and Segment destinations, one attempt per event, and the delivery loganalytics-pro
API keysapikeyFive active keys per tenant, thirty days of each key's request history, no monthly limit per keyapikey-pro
Bulk importbulk-importEvery format, XLSX included, and the trim, lowercase and uppercase transformscontent-pro
CachingcacheOne cache provider of any kind, and 10 response cache rules per tenantcache-pro
CaptchacaptchaOne provider for the instancemultitenant-customization
Concurrency tuninggoroutine-engine
Content lifecyclecontentEverything except releases and comment threads, with every revision kept and the last 30 days of them readablecontent-pro
Editorial reviewreviewOne workflow per tenant, with every stage feature except escalation, quorum and conditionsreview-pro
EmailemailOne SMTP provider and five templates per tenantemail-pro
Error trackingerror-trackingGrouping, triage and spike alerts by email, with 30 days of events readablealerts-pro
FlowsflowTwenty flows per tenant, on the nodes that stay inside the instanceflow-pro
Idempotent requestsidempotency
LocalizationlocalizationTwo locales per tenantlocalization-pro
LogsloggingEverything, with volume alerts by emailalerts-pro
Magic-link sign-inmagic-link
Mediamedia1,000 generated image variants per tenantmedia-pro
Metrics exporttelemetryEvery exporter for the instancemultitenant-customization
Multi-factor authenticationmfaTOTP, backup codes and signing in with an enrolled passkeymfa-pro
OAuth sign-inoauthOne provider per install, from the Google, GitHub or Apple template or by handoauth-pro
Object storagestorageEverything, region pins included
Password resetpassword-reset
Rate limitingrate-limitThe global limit and the built-in protectionsrate-limit-pro
Request capturerequest-captureEvery request kept 24 hours, with replay and diffrequest-capture-pro
Request profilingprofiler
Scheduled jobscronEvery job, with failure alerts by emailalerts-pro
Schema changesschemaThe list editor, every schema change, the built-in presets and applying any presetschema-pro, config-sync
Synthetic monitoringsynthetic-monitoringThree probes per tenant, each run at most every 300 seconds, with down notices by emailsynthetic-monitoring-pro, alerts-pro
TenantsmultitenantOne tenant, defaultmultitenant-provisioning and the other tenant capabilities below
Usage and quotasusageMetering, and enforcing the quotas already storedusage-pro
Webhookswebhook25 outbound endpoints per tenantwebhook-pro

A free install also holds up to three admin seats: accounts with the admin or super_admin role, in their own tenant or through a tenant membership. Each account counts once across every tenant, disabled accounts included, and the first account, created at setup, is one of the three. Editors and viewers never count. A license that is active or in grace lifts that ceiling, whatever names it carries. Creating a fourth admin, promoting an account to either role, or granting a membership with either role answers {"error": "cap_exceeded", "cap": "admin.seats", "limit": 3, "current": 3, "upgrade_url": ""}. When a license lapses, every admin keeps their role and keeps signing in.

Every install also holds these capabilities, which are about where a free feature keeps its data:

CapabilityWhat it lets you do
cache-redisKeep the cache in Redis.
storage-s3Store media in S3 or an S3-compatible service.
logging-retentionKeep logs for as long as your retention policy says.
rate-limit-distributedShare rate limit counters across replicas through Redis.
idempotency-distributedShare idempotency keys across replicas through Redis.
request-capture-replayReplay captured requests.
telemetry-streamingExport metrics on a schedule.
cost-monitorTrack the cost of each tenant.

Backing services such as Redis or S3 need no license. Configure the service and the free feature uses it.

Past a ceiling, the request answers 402 Payment Required with a body that names it, and nothing you already hold is taken away. Only the next object is refused:

{"error": "cap_exceeded", "cap": "rbac.roles", "limit": 3, "current": 3, "upgrade_url": ""}

A license carries a list of names. Each paid feature runs when its name is on the list:

FeatureName
A/B testingab-testing
AIai
API analyticsapianalytics
Audit logaudit
Data exportdata-export
Data residencydata-residency
Event replayevents
GraphQL APIgraphql
gRPC APIgrpc
Message broker eventsmessagebroker
PII maskingpii-mask
Realtimerealtime
Recommendationsrecommendations
Replicationcluster
SAML single sign-onsaml
SCIM provisioningscim
Searchsearch
Slow query analysisquery-monitor
Trusted devicesdevice-fingerprint
Web application firewallwaf

Other paid names open part of a feature. The feature runs either way, and the license opens the part:

NamePart ofWhat it opens
flow-proFlowsMore than twenty flows, custom endpoint paths, webhooks, other protocols, outbound nodes and datasources.
webhook-proWebhooksMore than 25 endpoints, payload templates and filters, retry policies, dead-letter replay and dismiss, the payload preview, delivery search, retrying one delivery, and creating or editing incoming webhooks.
email-proEmailA second provider and more, the API transport, more than five templates, creating or editing triggers, the delivery dashboard and bounce classification.
localization-proLocalizationMore than two locales.
oauth-proOAuth sign-inMore than one provider, the Okta and Azure AD templates, role mapping, default roles of your own and a backup provider.
mfa-proMulti-factor authenticationEnrolling a passkey and marking one as the backup key.
synthetic-monitoring-proSynthetic monitoringMore than three probes, and intervals down to 15 seconds.
rate-limit-proRate limitingCustom rate limit rules, changes to the sign-in protections, a tenant's own global limit, address allow and deny lists, and the refusal history.
rbac-proAccess rulesMore than three roles that hold rules.
apikey-proAPI keysMore than five active keys per tenant, the whole request history, and monthly request limits: setting or raising a key's limit.
usage-proUsage and quotasTenant quotas: setting a tenant's request, storage and bandwidth limits, and turning hard limits and blocking on.
alerts-proScheduled jobs, error tracking, logs, synthetic monitoringAlerts in Slack, Discord, PagerDuty or a signed webhook, a tenant's own error spike threshold, and error events older than 30 days.
content-proContent lifecycle, bulk importContent releases, editorial comments, revisions older than 30 days, and saved import mapping templates with the date, split and lookup transforms.
review-proEditorial reviewMore than one workflow per tenant, escalation on a missed deadline, stages that need several approvals, and stages that apply only to some entries.
request-capture-proRequest captureCapture rules per route with sampling and retention up to 30 days, and saved replay sets.
cache-proCachingSeveral cache providers with failover, moving entries between providers, the provider benchmark, and more than 10 response cache rules per tenant.
analytics-proAnalyticsRetry policies, replaying a failed delivery, and the PostHog, Amplitude and webhook destinations.
media-proMediaMore than 1,000 stored image transform variants per tenant.
schema-proSchema changesThe schema canvas with a layout every admin of the tenant shares, and saving presets of your own.
config-syncSchema changesPromoting the configuration: content types, flows, access rules, webhooks and settings to another instance as one bundle. Moving one content type or one flow stays free.
multitenant-provisioningTenantsCreating tenants.
tenant-backupTenantsBacking up, restoring and cloning a tenant.
migration-toolkitTenantsJobs that copy a database to another one, across database types, with cancel and rollback.
multitenant-customizationTenants, captcha, metrics exportThe admin console branded per tenant, a captcha provider per tenant, and a metrics destination per tenant.
audit-retentionAudit logRetention policies and legal holds. A license with audit includes it.
audit-proAudit logStreaming the log to Splunk, Datadog or HTTPS. It needs audit on the same license, and a license with audit does not include it.
supportAIThe support desk. It needs ai on the same license.

A license that carries a free feature's own name opens that feature's paid part too: flow, webhook, email, localization, mfa, oauth, synthetic-monitoring and rate-limit open their -pro part, and multitenant opens multitenant-provisioning, tenant-backup and migration-toolkit.

These names are in beta: alerts-pro, analytics-pro, apikey-pro, audit-pro, cache-pro, config-sync, content-pro, flow-pro, localization-pro, media-pro, migration-toolkit, multitenant-customization, multitenant-provisioning, request-capture-pro, review-pro, schema-pro, support, synthetic-monitoring-pro, tenant-backup and usage-pro. So are these paid features: ai, cluster, data-residency, device-fingerprint, messagebroker, query-monitor, recommendations and saml. Each works as its page describes, and its fields can still change before it is marked stable. Each page says what keeps working when the license lapses.

Which names each plan carries is on lyeve.com/pricing. A feature can also be bought on its own, and however a name reached the license, it works the same.

A paid feature the license does not cover does not start, so its routes answer 404. One that was running when the license lapsed can answer 402 until the next restart. A paid part of a running feature answers 402 with the name it needs:

{"error": "payment_required", "plugin": "multitenant-provisioning", "feature": "feature:multitenant_provisioning", "upgrade_url": ""}

You receive a license as a signed token, or as a license key that starts with lyeve_live_ (lyeve_test_ for a test key). Either works in both places below.

In the environment. Set LYEVE_LICENSE_KEY and restart the engine:

Terminal window
docker run -e LYEVE_LICENSE_KEY="<token or key>" ... ghcr.io/lyeve-labs/lyeve-core:latest

In the admin console. A super admin opens Settings > License, pastes the token or key into License token or key, and selects Activate license, or Renew license when one is already in force. The same call over the API:

Terminal window
curl -X POST http://localhost:3001/api/admin/license/renew \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"license_key": "<token or key>"}'
{"plan": "pro", "state": "active", "features": ["..."], "license_source": "token", "expires_at": "2027-01-31T00:00:00Z"}

The route takes the super_admin role and a signed-in session, not an admin token or an API key. The instance stores what you enter, and encrypts a key with ENCRYPTION_KEY, so a restart and every replica pick it up.

What changes at once and what waits for a restart:

  • Paid parts of a running feature, such as flow-pro or multitenant-provisioning, apply to the next request.
  • A paid feature that was not running at boot starts at the next restart.
AnswerMeaning
200Applied. The body is the new entitlement.
400 invalid JSONThe body is not JSON.
400 license_key is requiredThe body carried no key.
400 license verification failedThe token does not verify.
400 the license server refused this keyThe key is invalid, revoked or out of activations.
409LYEVE_LICENSE_KEY holds a license key, and the environment wins. Change the key there.
502The license server could not be reached, or returned a token that does not verify.
503 license key exchange is not configured on this instanceLYEVE_LICENSE_SERVER_URL is not usable, so a key cannot be exchanged.

A signed token is verified on the instance with no network call, so an air-gapped install behaves like any other. The check cannot be turned off, and a development or staging install is checked the same way. See Verify offline.

A license key is exchanged for a token:

  1. At start the engine sends the key and a random id for the install to LYEVE_LICENSE_SERVER_URL. It accepts https only and never follows a redirect.
  2. It verifies the token that comes back exactly as it verifies one you paste. A token that does not verify grants nothing.
  3. It caches the token in LYEVE_LICENSE_CACHE_DIR with a digest of the key, never the key itself. A later start uses the cached token with no network call until the token is within seven days of its expiry.
  4. From then on it exchanges the key again. A running engine checks every six hours, and also retries while it holds no active token.

Nothing else is sent: no content, users, configuration or usage. When the server refuses the key (invalid_key, key_revoked or quota_exceeded), the cached token is discarded and the install runs the free tier. When the server cannot be reached, a cached token keeps working, and with none the install runs the free tier. Any other answer, such as a proxy's 403, counts as unreachable. The reason is logged and reported as license_error by GET /api/admin/entitlements.

Mount LYEVE_LICENSE_CACHE_DIR on a volume so the cached token survives a new container.

StateWhenPaid features
freeNo license, none that verifies, or a license whose grace has endedOff
activeThe license verifies and has not expiredOn
graceExpired less than seven days agoStill on, with a warning in the log every hour

The engine checks the clock every hour. An active license past its expiry moves to grace, and grace that ends moves the install to free, both without a restart. The log also warns 30, 14, 7, 3 and 1 days before expiry.

In every state the free tier keeps running. A missing or expired license never takes a free feature away, and a paid feature that stops keeps its data. Past a free ceiling after a downgrade, everything you hold stays, and only the next object is refused. Renew before grace ends and the paid features carry on without a gap.

A feature runs when all three hold:

ConditionSet byMeaning
IncludedThe engine imageThe published image includes every feature.
LicensedLYEVE_LICENSE_KEYThe feature is free, or the license carries it.
RequestedLYEVE_PLUGINSThe feature is on your list. Empty means every licensed feature.

LYEVE_PLUGINS is a comma-separated list of feature names, with whitespace around each name trimmed and names matched exactly. Once set, only the listed features start, free ones included, plus any licensed feature a listed one depends on. It can narrow what runs but never widen it, so naming a feature your license does not carry has no effect. Use it for a lean deployment with fewer routes:

Terminal window
LYEVE_PLUGINS=apikey,multitenant,content,media,storage,schema,search
Licensed?In LYEVE_PLUGINS?ResultReason reported
YesYes, or the list is emptyRunningnone
YesNoOffgranted but not requested via LYEVE_PLUGINS
NoYesOffrequested via LYEVE_PLUGINS but not granted by the capability set
NoNoOffnot granted by the capability set

A listed name the image does not include logs LYEVE_PLUGINS requested a plugin not compiled into this binary at start and reports plugin not compiled into this build, so a typo is easy to find.

In the admin console, Operations > Plugins lists every feature with its state and, for one that is off, the reason. Admins and super admins see it. Settings > License shows the plan, its state, the expiry and any license problem.

Over the API, three routes answer:

Terminal window
curl http://localhost:3001/api/admin/entitlements \
-H "Authorization: Bearer $TOKEN"

GET /api/admin/entitlements takes the admin or super_admin role and reports the license in force. A free install answers:

{
"plan": "free",
"plan_label": "Free",
"state": "free",
"features": ["analytics", "apikey", "bulk-import", "cache", "cache-redis", "..."],
"tenant_quota": 1,
"withheld": [],
"caps": {"admin.seats": 3},
"license_module": true
}
Entitlement fields
FieldMeaning
plan, plan_labelThe plan, and the label the admin console shows.
statefree, active or grace.
featuresEvery name the install may run, sorted: the license's names, the free features and the free capabilities.
tenant_quotaHow many tenants the install may hold. 0 means unlimited.
capsEach ceiling the license decides. 0 means unlimited.
withheldFeatures a super admin withheld from the caller's tenant. See Tenants.
license_sourcetoken, key or stored_key, when a license is set.
expires_at, grace_ends_atWhen the license expires, and when grace ends while in grace.
license_errorWhy the last key exchange failed.
license_moduleWhether this build can verify a license.

The answer never carries the token, the key, the license id or the install id.

GET /api/admin/plugins/status takes the admin or super_admin role and returns one row per feature in the image: whether it is compiled, entitled, requested and active, its phase, and for one that is off a reason. A feature off for lack of a license also carries an upgrade_url, a path on your own install that opens the license page.

A status row
{
"name": "graphql",
"compiled": true,
"entitled": false,
"requested": false,
"active": false,
"phase": "registered",
"reason": "not granted by the capability set",
"upgrade_url": "/admin/settings/license?plugin=graphql",
"manifest": {
"label": "GraphQL",
"description": "A GraphQL API generated from your content types, with subscriptions over WebSocket and a persisted-query allowlist.",
"category": "delivery",
"maturity": "stable"
}
}

The top level also carries compiled and entitled lists, and a requested list when LYEVE_PLUGINS is set. manifest.category is one of content, delivery, access, automation, insight, operations, compliance, ai or platform, and maturity is stable or beta. A running feature that serves routes lists them under routes, each with method, pattern and the group that may call it (public, auth, admin or super_admin).

GET /api/admin/plugins/running answers any signed-in role with names only: plugins lists what runs for the caller's tenant and withheld what runs on the install but is withheld from that tenant.

In the log, the license decision at start is on lines that begin with license::

LineMeaning
license: no key setLYEVE_LICENSE_KEY is empty. The free tier runs.
license: activeThe token verified. The line carries the plan and the feature count.
license: key exchanged for a signed tokenA license key was exchanged for a token.
license: verification failed, checking grace cacheThe token did not verify, so the engine looks for a cached one in grace.
license: running on offline graceA cached token is in its grace period.
license: no valid tokenNothing verified. The free tier runs.
VariableWhat it doesDefault
LYEVE_LICENSE_KEYThe signed token or the license key. Empty runs the free tier.empty
LYEVE_LICENSE_SERVER_URLWhere a license key is exchanged. Never contacted for a token.https://api.lyeve.com
LYEVE_LICENSE_CACHE_DIRWhere the verified token and the install id are cached./var/lib/lyeve
LYEVE_PLUGINSThe features to start. Empty starts every licensed feature.empty

The configuration reference lists the rest.