# Online leases and renewal

> Understand Infra-managed lease claims, quota accounting, authorization deadlines, and the chrovia.license API.

Source: https://console.getchrovia.com/en/docs/sdk-leases

A **lease** keeps a License that requires online authorization active for the current browser instance. Chrovia Infra handles renewal automatically.

## Standard integration: keep Chrovia Infra

Install the browser with its `Extensions/chrovia-infra` directory intact. For ordinary SDK use, Infra already obtains and renews leases; your plugin should not run a second renewal loop. See [plugin installation](https://console.getchrovia.com/en/docs/sdk-plugins).

1. Install a valid [License](https://console.getchrovia.com/en/docs/sdk-license) for the instance.
2. Keep the machine connected to Console with available License quota.
3. Start the browser with Chrovia Infra installed. It handles initial authorization and renewal, including after its Service Worker wakes.
4. If a renewal fails, use the troubleshooting steps below rather than starting another renewal loop.

Only an officially issued License with `payload.noLease: true` skips this flow. Removing Infra or going offline does not convert a leased License into an offline one.

## Current timing and quota

| Item | Current behavior |
| --- | --- |
| Startup grace | 10 minutes for a valid License requiring a lease |
| Lease validity | Up to 60 minutes, capped at License expiration by Console |
| Scheduled renewal | Infra checks every 50 minutes |
| Transient-failure retry | Infra schedules a retry after 1 minute |
| Soft grace | 5 minutes beyond an accepted lease's expiry |
| Terminal rejection | Infra invalidates immediately; remaining lease time is not preserved |

These intervals do not guarantee precise renewal while the machine is asleep. On lost authorization the browser displays a License lock prompt: **Yes** dismisses it temporarily; **No** exits the browser. If authorization remains unavailable, the prompt returns. Dismissing it does not renew authorization.

Each successful server issuance consumes one quota hour, even if the response is lost or the browser exits early. Multiple independent instances share the License's quota. Full restarts get a new instance identity and do not reuse an old process's lease. Do not manually claim leases merely to inspect status. See [billing and quota](https://console.getchrovia.com/en/docs/commercial-license-billing) for monthly accounting.

## Read the snapshot correctly

```js
const state = await chrovia.license.get();
console.log({
  valid: state.valid,
  requiresLease: state.requiresLease,
  leaseExpiresAt: state.leaseExpiresAt,
});
```

| Field | Meaning |
| --- | --- |
| `valid` | The License loaded successfully; not a live lease-authorized flag |
| `requiresLease` | Whether online leasing is required |
| `licenseId`, `instanceId` | Identifiers used to bind a claim and its reply |
| `claimTimestamp`, `claimMac` | Pass these values unchanged when requesting a lease; obtain fresh values for each request and do not log or reuse them |
| `leaseExpiresAt` | Future renewal deadline, or `null`; startup grace can populate it before the first claim |

The status response does not include the full License or an entitlement list. API object presence alone is not proof of current online authorization. Use the License details in Console to check capabilities and the renewal troubleshooting steps below to diagnose a lock prompt.

## Manual lease API

Use this only when your integration replaces Infra's renewal handling; do not run both. Send `POST https://console.getchrovia.com/api/license/lease` with `licenseId`, `instanceId`, `timestamp`, and `mac`, using fresh `license.get()` values (`claimTimestamp` → `timestamp`, `claimMac` → `mac`). Keep the machine clock synchronized. Pass the complete response unchanged to `applyLease()` in the requesting instance.

| API | Result |
| --- | --- |
| `license.get()` | Promise of a snapshot, no renewal |
| `license.applyLease(lease)` | Promise of a snapshot; rejects if the lease is rejected |
| `license.invalidate(reason)` | Promise of a snapshot; marks a leased process terminally unauthorized |

`applyLease` rejects with `DataCloneError` for a non-object payload or `DataError` for an invalid, expired, or incompatible lease. Do not save a lease as `Chrovia License` or `Extended Preferences`.

`invalidate` is not a logout helper or a status probe. A terminally invalidated process cannot recover through another `applyLease`; resolve the server-side cause and fully restart it. There is no `renew()` method on the kernel API.

## Diagnose renewal failures

Inspect **Chrovia Infra's Service Worker**, not your popup or a page console. Errors are logged with `Chrovia Infra: lease refresh failed`. Check the actual shipped extension, its Console host permission, connectivity, system clock, and the License card in Console.

Infra treats `expired`, `revoked`, `quota_exceeded`, and `not_found` as terminal. Network errors and other rejections schedule retries; grace is finite. Restoring connectivity may recover a transient expiry, but restarting cannot fix a revoked or expired License. After quota resets, restart a process terminally invalidated by quota rejection.
