License

Last updated on May 21, 2026

A TofuPilot license is a signed JWT issued by Orbit that authorizes a self-hosted instance. It encodes the plan tier, hard limits (seats, stations, runs per month), enabled features (SSO, SCIM, Teams), and expiry, and the instance verifies it on every request against an embedded Ed25519 public key so no network call is needed once it is stored.

Licenses apply to self-hosted only, and Cloud customers are governed by their Stripe subscription.

Delivery

Licenses can reach your instance in two modes depending on whether outbound HTTPS is allowed.

ModeTriggerUse when
Phone-homeThe instance fetches a fresh JWT from Orbit using TOFUPILOT_LICENSE_KEY.The instance has outbound HTTPS to tofupilot.com.
Air-gappedAn operator copies the JWT from Orbit and pastes it into the dashboard.The instance has no internet.

Both modes verify the JWT signature with the same embedded public key.

Where to find the license

Open Settings > Plan to view the license card, which shows the plan tier, expiry, current limits, enabled features, and the instance ID. The usage counts on the same page show how close you are to each limit.

Refresh from Orbit

To pull a fresh license, click Refresh license on the license card. The instance posts the license key and instance ID to Orbit, receives a new JWT, verifies the signature, and stores it.

A failed refresh leaves the existing license in place, so there is no silent downgrade.

Air-gapped activation

For air-gapped deployments, you transfer the license token manually.

  1. In Orbit, open the instance menu and select Copy license token.
  2. In your self-hosted dashboard, open Settings > Plan.
  3. Click the upload button on the license card.
  4. Paste the JWT and click Activate.

The instance verifies the signature locally and stores the JWT. For the initial-deploy flow, see Operations.

Air-gapped instances do not auto-renew. Set a reminder before expiry and rotate manually.

License contents

The decoded JWT carries the fields the instance reads at runtime.

FieldMeaning
subInstance ID. Must match the deployment.
orgOrganization name.
planlab, pro, or enterprise.
limits.stationsMax active stations, or null for unlimited.
limits.usersMax active seats, or null for unlimited.
limits.runs_per_monthMonthly run cap, or null for unlimited.
featuresEnabled add-ons (sso, scim, teams).
iatIssued-at timestamp.
expExpiry timestamp.

The instance caches the decoded license in-memory for 60 seconds.

Expiry behavior

After expiry, the instance walks through escalating warnings rather than cutting off access immediately.

StateDays past expiryEffect
validNot expiredNormal operation.
warning0 to 30A banner appears and nothing is restricted.
write_restricted30 to 90New users and stations cannot be created, but existing data and runs continue.
nag_modal90+A renewal modal blocks every page.

To clear the state, you renew in Orbit (or contact sales for Enterprise) and refresh the instance.

Authentication

The TOFUPILOT_LICENSE_KEY is an opaque secret tied to the deployment in Orbit, and you should treat it like an API key by storing it in your secret manager and never committing it to Git.

The JWT itself is not a secret. It is signed and tamper-evident, and it grants no authority beyond the encoded limits.

If the signing key rotates, existing JWTs become invalid. The deploy script bundles the matching public key per release, so you update to the latest version to get the new key.

Refresh failures

A failed refresh does not change the active license. Common causes:

  • No outbound HTTPS: the instance is air-gapped, so switch to manual activation.
  • License key revoked in Orbit: the contract was canceled or replaced, so contact sales.
  • Orbit is down: retry. The cached license keeps the instance running.

The dashboard surfaces refresh errors on the license card, and service does not interrupt until the license expires.

How is this guide?

On this page