# License & Activation

:::note[In short]

The SDK gets its license by attesting your app on the first call to `Octet.start(...)`, then works from a local lease. The lease lifecycle below (refresh, offline grace, states, revocation) is unchanged from 1.x.

:::

## Getting a license

Since 2.0, the SDK obtains its license by attesting your app at first launch, not by carrying a key. Register your app once against your Octet account, then call `Octet.start(...)`. See [Attested bootstrap](/docs/v3.0/concepts/attested-bootstrap/) for the handshake and [Prerequisites](/docs/v3.0/getting-started/prerequisites/) for the registration steps. For local development, CI, and simulators, use a sandbox bypass token.

Use of the SDK is governed by the [Mobile SDK terms](https://octetproof.com/terms/mobile/). The current terms live at `/terms/mobile/`. A dated snapshot lives at `/terms/mobile/vMM.DD.YYYY/`.

The first call bootstraps the license over the network. Subsequent launches read from a local lease and do not bootstrap again until the lease needs to refresh. After a successful activation the SDK keeps working offline for up to 14 days (the offline grace).

As of 1.2, when a lease response returns a refreshed license token, the SDK persists it. The device then carries a fresh token across restarts throughout the offline-grace window, rather than falling back to the token it first activated with.

## Validity

Octet bills per active device: the SDK sends one usage record per device per UTC day, with no identity and no coordinates (see [Metrics](/docs/v3.0/concepts/metrics/)). Aggregate usage counters are on by default and are described under [Usage telemetry](#usage-telemetry). Verifying happens in your own code, offline. See [pricing](https://octetproof.com/pricing).

Licenses renew automatically, so you do not need to replace a working license.

By default a license has no device cap, so you can install on as many devices as you like. Octet can set a device cap on a license. When the cap is reached, a new device fails to activate with `deviceLimitReached`. Devices that already activated keep working and keep refreshing their lease.

## License states

Octet maintains active licenses, so a license in normal use stays in `ACTIVE`. The `GRACE_PERIOD` and `EXPIRED` states below handle prolonged offline periods and revocation. Age alone does not expire a maintained license.

```mermaid
stateDiagram-v2
    [*] --> NOT_ACTIVATED: license verified locally
    NOT_ACTIVATED --> ACTIVE: activation succeeds
    ACTIVE --> RENEWAL_RECOMMENDED: < 30 days to expiry
    ACTIVE --> GRACE_PERIOD: cached past exp, offline
    RENEWAL_RECOMMENDED --> GRACE_PERIOD: same trigger
    GRACE_PERIOD --> EXPIRED: past grace period
    NOT_ACTIVATED --> INVALID: signature / server reject
    ACTIVE --> INVALID: server reject
    EXPIRED --> [*]
    INVALID --> [*]
```

Read the state at any time:

```swift
// iOS
if let status = sdk.licenseStatus {
    print("state: \(status.state), days left: \(status.daysUntilHardStop ?? -1)")
}
```

```kotlin
// Android
sdk.licenseStatus?.let { status ->
    println("state: ${status.state}, days left: ${status.daysUntilHardStop ?: -1}")
}
```

`LicenseStatus.state` drives in-app UI only. It never drives the cryptographic gate. Forcing `state = ACTIVE` in your own code accomplishes nothing.

## Failure modes

`Octet.start(...)` throws a typed `LicenseError`. The complete taxonomy is in [License Types](/docs/v3.0/api-reference/license-types/). The common cases:

- `BootstrapFailed(reason:)`. Attested bootstrap failed. `reason` names the cause. Fix: see [`BootstrapReason`](/docs/v3.0/api-reference/license-types/#bootstrapreason).
- `MalformedKey`. The license token the SDK holds did not verify. Fix: confirm the SDK is on a supported version, and contact support if it persists.
- `NoActivation`. First launch, and the device is offline. Fix: retry when network returns.
- `Expired`. Cached activation past the offline grace, backend unreachable. Fix: reconnect so the SDK can re-activate.
- `ActivationWindowClosed`. Not returned under the current maintained-license model. Retained for compatibility. Fix: contact support.
- `Revoked`. Admin revoke (key leaked, abuse). Fix: contact support.
- `Network(message:)`. Transient. Fix: retry.
- `ServerRejected(httpStatus:, reason:)`. Anything else from the backend. Fix: see `reason`.

## Usage telemetry

The SDK reports aggregate usage counters to the license
backend, indexed by your license: how many proofs were generated, uploaded, or
could not be produced, by coarse level and region type. The counters carry no
location data: no coordinates, no region IDs, no proof contents. They are
buffered in an encrypted file in the app's private storage and uploaded once a
day, plus a best-effort flush when the app enters the background.

Telemetry is on by default. Disable it with `telemetryEnabled = false` on
[`OctetConfig`](/docs/v3.0/api-reference/octet-start/). Disabling deletes any buffered file.

Separately, the SDK sends one usage record per device per UTC day so Octet can
count active devices for billing. That record is always on. See
[Metrics and usage reporting](/docs/v3.0/concepts/metrics/).

## SDK version gating

Added in 1.2. The SDK reports its version and platform on every backend request. The backend can act on that in two ways:

- A hard gate. `Octet.start(...)` throws `LicenseError.upgradeRequired(minVersion:message:)` when the backend rejects an out-of-support version.
- A soft hint. `LicenseStatus.upgradeRecommended` and `minSupportedVersion` flag a version behind the recommended floor without stopping the SDK.

Both paths were inert when they were added in 1.2, because the backend gated no version yet. Octet turns gating on server-side, without an SDK release, so handle `upgradeRequired` and read `upgradeRecommended` now. See [License Types](/docs/v3.0/api-reference/license-types/) for the field and case shapes.

## Where to go next

- [Prerequisites](/docs/v3.0/getting-started/prerequisites/) for how to register your app.
- [License Types API Reference](/docs/v3.0/api-reference/license-types/) for the exact types of `LicenseStatus` and `LicenseError`.
- [Troubleshooting FAQ](/docs/v3.0/troubleshooting/faq/) for what to do when activation fails.
