Manage Licenses
View, upload, and extend a tenant's license from the SaaS admin console.
Each tenant's license state is managed through the License tab in the tenant detail view of the SaaS admin console (/admin).
View license status
Open the admin console and click on a tenant.
Click the License tab. It shows the current mode:
- Trial — days remaining, trial start/end dates, and current quota usage.
- Licensed — customer name, validity dates, and quota gauges.
- Blocked — the license has been administratively revoked.
A license names a plan (Free, Team, Business, or Enterprise) or is a trial. See Plans and entitlements.
New tenant trials
A new tenant gets a 15-day Team trial licence. The trial starts at creation for self-service
sign-up and admin-created tenants, and at approval for requested sign-ups. The tenant-service
applies it once the tenant's workload is ready, retrying with a growing delay for about two
days. While it is pending, or after it gives up, the tenant's License tab says so; upload a
licence to replace a trial that was not issued. The tenant-service signs the trial with the
licence signing key (aicontrols-license-signing-key Secret); without the key no trial is
issued and you upload a licence instead. A tenant gets the Team trial once, and never over a
licence it already runs.
Change a tenant's plan
Editing a tenant's Plan signs and applies a new license, so a plan change is always a license change.
Open the tenant, click Edit, and choose Free, Team, or Business.
Click Save changes. The tenant-service signs a 12-month license for the new plan with the licence signing key (
aicontrols-license-signing-keySecret), records the signature, and applies it to the tenant. The plan in the tenant list updates to what the tenant's proxy reports. If the proxy refuses the license, the plan, name, and stored license stay as they were.
Tenant feature flags named after a Team or Business feature (for example rbac) are added to
the license as extra entitlements; other flags are not.
Enterprise is not in the list unless the tenant already has it: Enterprise licenses are issued by Nirmata, and you apply one with Upload license…. Without the signing key, a plan change returns an error and nothing changes.
Purchases and invoiced tenants
When SaaS billing is enabled, a Team or Business purchase arrives from Stripe. The tenant service reads the subscription from Stripe and issues the paid license (plan, seats, Advanced Security), then pushes it to the tenant. A license is issued only for an active subscription whose latest invoice is paid. A purchase never issues Enterprise.
A tenant billed by invoice, or managed manually, is never changed by billing. Set its billing mode
(self_serve, invoiced, or manual) with Set billing mode on the Billing tab. While a
tenant is invoiced or manual, its Stripe subscription is listed under license sync failures in
the billing queue and only an admin plan change applies. When you set it back to self_serve, the
license sync runs again.
Billing tab and queue
When SaaS billing is enabled, the tenant list shows a billing badge on each row (Stripe, past due, canceled, invoiced, or manual), and the tenant detail page has a Billing tab beside License. It shows the billing mode, the Stripe customer and subscription (linked to the Stripe dashboard), the billing email, plan, add-ons, any discount, interval, seats, this month's seat usage, the auto-add seats setting (with who accepted the terms, and when), status, period end, any scheduled change, dunning, dispute and licence sync state, recent events, signature history, and the billing audit. A warning appears when seat usage is above the purchased seats.
Seat usage is the peak for the current UTC month, pulled from the tenant every 15 minutes: developers (human seats) and all seat kinds, which also include service accounts and machine credentials. Peaks only rise within a month and start over in the next one. Seat overage also raises a sales signal for the tenant.
Resync and Set billing mode each need a reason, which is recorded in the billing audit. After a resync the tab shows the result (applied, unchanged, or failed) and what had drifted.
The Billing queue tab lists failed or unmatched events (with Replay), past-due tenants, disputes, refunds awaiting approval, licence sync failures, expiring licences, and reconciliation alerts. An hourly reconciliation compares Stripe, the billing records, and each tenant's running license. It lists a license that is about to expire although its subscription has renewed under Expiring licences. Under Reconciliation alerts it lists a Stripe customer that names no tenant, a paid license with no subscription behind it, and a tenant that does not run the license billing applied and could not be updated. An alert clears on the next run after the problem is fixed. To release a pending refund, click Approve, enter a reason, and confirm in the dialog. The refund is sent to the customer in Stripe, the reason is recorded in the billing audit, and the resulting status (approved, refunded, or failed) is shown. Only system administrators can approve refunds.
For a tenant managed by Stripe, the Plan field on the Details tab is disabled; change the billing mode first. When billing is not enabled, the tab and the queue are hidden.
Refunds and disputes
Nothing is refunded automatically. A refund request waits in the Billing queue until a system administrator approves it. Approve needs a reason and is recorded in the billing audit before the refund is sent to Stripe. If Stripe cannot complete it, the request shows failed and stays in the queue; approve it again to retry (the customer is refunded at most once). This includes a refund that Stripe first accepted and later reported as failed or canceled: approving again makes a new refund. A request that is already refunded cannot be approved again.
When a customer disputes a charge, the tenant is flagged disputed, an alert is raised, and the dispute appears under Disputes in the queue with its amount, reason and evidence deadline. If a customer success lead address is configured, they are emailed. The license is not changed while the dispute is open. Respond with evidence in the Stripe Dashboard. A dispute closed as won clears the flag and leaves the queue. One closed as lost stays in the queue for an administrator's decision.
Lapsed tenants
When a self-serve subscription ends (payment retries ran out, the owner canceled, or the period ended after a cancellation), the Billing tab shows the retention window: when the license lapsed and the date the tenant will be purged, 30 days later. The tenant is read-only until then (see When a hosted subscription ends). The owner is emailed when the license lapses and 7 days and 1 day before the purge.
To give a customer more time, extend the window:
curl -X POST "https://YOUR_ADMIN_HOST/api/v1/admin/tenants/TENANT_ID/billing/extend-retention" \
-H "Content-Type: application/json" -b admin-session-cookie \
-d '{"days": 14, "reason": "Customer is migrating off, ticket SUP-2210"}'
days is 1 to 365 and is added to the current purge date. A reason is required. The extension is
recorded in the billing audit with your name, and the 7-day and 1-day emails are sent again for the
new date. It answers 409 when the tenant is not in its retention window.
If the customer subscribes again, the purge date is cleared automatically and full access returns
when the new license is applied. A tenant you have set to invoiced or manual is never purged by
this process. A tenant that is purged is deleted through the same path as Delete tenant: its
Stripe subscriptions are canceled and open checkouts expired first, and if Stripe cannot be reached
the tenant is kept and the purge is retried a minute later.
Billing for tenant owners
Tenant owners see a Billing section on the account page for self-serve tenants. It is hidden for invoiced and manual tenants. Owners can choose a plan and add-ons, preview a change before confirming it (the preview shows the amount due now, including tax, and any warnings), change seats, and turn on auto-add seats up to a ceiling. If a change cannot be made, the page explains why: the seat count is above the plan limit, the account cannot change plans online, the price changed since the preview (preview again), or the payment failed (nothing was changed).
If a renewal payment fails, you receive an email with a link to the account page, where you can update the payment method. Your plan keeps working while the payment is retried for 14 days. If it still fails, the tenant becomes read-only (view and export only) for 30 days, then is deleted. If you cancel, the same happens when the period you paid for ends. You get emails when the tenant becomes read-only and 7 days and 1 day before deletion. Subscribe again from the Billing section at any time in that window to restore full access with your data intact.
The Billing section shows the seats purchased, the developers assigned this month (the peak), and the seats in use of every kind when service accounts or machine credentials add to it. When the month's peak is over the purchased seats, or at 90% of them, a banner offers Add seats, and the owner gets at most one email a week with a link that opens the seat change. Running agents and developers are never blocked while the owner decides.
Auto-add seats
Auto-add seats is off by default. An owner turns it on from Auto-add seats, sets a seat ceiling, and accepts the terms of use. Once on, when developers this month exceed the purchased seats, AIControls adds seats right away, prorated and charged to the card on file, up to the ceiling and the plan maximum (50 for Team, 500 for Business). Each change emails the owner and is recorded in the billing audit with the old and new seat counts, the ceiling and the terms accepted. Turning it on or off, or changing the ceiling, is audited too.
Only developers count. Service accounts, CI and bot keys, and other machine credentials never use up auto-add and never trigger a charge, though they can still show the seat banner. If the payment does not go through, no seats are added and the failure is recorded in the audit.
A tenant on a trial, or without a paid license, subscribes from the same section: choose Choose a plan,
then the plan, interval, seats and add-ons, and Continue to checkout opens Stripe Checkout (USD, tax calculated by Stripe,
promotion codes accepted). The page returns to /account?billing=success and shows the plan as
activating until the paid license reaches the tenant. A tenant whose license is managed by Nirmata
(invoiced or manual, or a stored license that does not match what the tenant runs) cannot subscribe
online. Manage payment and invoices opens the Stripe Customer Portal for the payment method,
invoices and cancelling at period end; plan and seat changes are made on the account page, not in the
portal.
Change plan, billing interval, or seats
Choose Change plan or seats, and set the plan, interval, seats, and add-ons.
Choose Preview change. The preview shows when the change takes effect and what it costs.
Check the confirmation box, and choose Confirm change. If the payment needs your confirmation, follow the link to pay the invoice. The change applies once it is paid.
| Change | Takes effect | Charge |
|---|---|---|
| More seats, Team to Business, or adding Advanced Security | Now | The prorated amount for the rest of the period, charged to the saved card at once. If the payment fails, nothing changes. |
| Fewer seats, Business to Team, or removing Advanced Security | At renewal | None now. Unused seats are not credited. |
| Monthly to annual, or annual to monthly | At renewal | None now. The new price applies from the renewal invoice. |
Seats work like a pool: buy at least 1, up to 50 on Team and 500 on Business. Advanced Security always covers every seat. To reduce seats, first free the seats you no longer need: you cannot reduce below the number of people using seats this month. To move from Business to Team, reduce to 50 seats or fewer first.
A change that adds and removes at once, such as more seats with Advanced Security removed, is refused. Make it as two changes. A change scheduled for renewal shows as a notice on the Billing section until it applies. A new scheduled change replaces it. To keep your current plan, preview your current plan, seats, and add-ons again, and confirm. That cancels the scheduled change. Cancel it before you add seats or upgrade. Once the scheduled change applies at renewal, you can upgrade again. A preview is valid for 15 minutes. If your plan changed in the meantime, preview again. Retrying a confirmed change never charges twice.
Upload a commercial license
Open the tenant's License tab.
Click Upload license….
Select the
.licfile or paste the license text directly.Click Upload. The proxy activates the license immediately; the admin console updates the tenant's plan badge on the next page load (for example from Trial to Enterprise).
A tenant's plan (Free, Team, Business, or Enterprise) shown in the tenant list is a copy of what the tenant's proxy reports. When a license is uploaded or viewed, the tenant-service refreshes it. With SaaS billing enabled, the hourly reconciliation also refreshes it for every billed tenant, so a lapsed paid license shows Free without anyone opening the tenant:
- a running Free, Team, Business, or Enterprise license (or trial) → that plan
- a license that has expired, been removed, or been blocked → Free
This sync also updates the underlying Kubernetes TenantApp workload spec so the proxy tier configuration stays consistent. The plan is never edited directly: it changes only when a license changes.
An upload or trial extension is refused with a 409 when the tenant's AIControls version is older than the license requires, for example because the license uses a plan or limit that version doesn't know. Upgrade the tenant, then retry.
Extend a trial
Extending re-issues the tenant's trial licence with a later end date, signed by the
tenant-service, and applies it to the tenant. It works from the licence last uploaded
through this console: for a trial applied before this feature, upload the trial licence
once first. The tenant-service needs the licence signing key
(aicontrols-license-signing-key Secret); without it Extend returns an error.
Open the tenant's License tab.
Click Extend trial….
Enter the number of additional days (subject to a 90-day total cap from the original trial start).
Click Extend. The new licence takes effect immediately.
When a tenant administrator clicks Request Extension on the tenant's License page, the
request reaches Nirmata by email and is listed as an extension_request sales signal; you
approve it with Extend trial….
Add-on trials
A tenant administrator on Business starts a 14-day Advanced Security trial from the tenant's
License page. The tenant-service re-issues the tenant's current licence with the trial
add-on, applies it, and records an addon_trial_started sales signal. Each tenant gets one
trial of each add-on; a second request is refused. The trial needs the licence signing key.
The tenant-service re-issues the licence it applied, such as the signup trial or a licence
uploaded here. For a tenant whose licence was applied before the tenant-service kept a copy,
upload that licence once first.
License quotas
The License tab displays monthly usage gauges for identities (distinct users + agents) and requests. Colour coding:
| State | Meaning |
|---|---|
| Green | Within quota |
| Amber | ≥ 80% of quota |
| Red | Quota exceeded (soft cap — traffic continues, admin action needed) |
Unlimited dimensions (quota set to 0 in the license) display the raw count with no bar.