# Migrating from 1.x

This page lists what changed for an app moving from 1.x to 2.0, breaking changes first. 3.0 changes more on top of 2.0, so after this page read [Upgrading from 2.x](/docs/v3.0/getting-started/upgrading-from-2x/). The 1.x docs stay available at [/docs/v1.2/](/docs/v1.2/).

## Licensing moves to attested bootstrap

In 1.x the SDK activated with a pasted `licenseKey`. In 2.0 it proves the app's identity with a platform attestation (Apple App Attest, Android key attestation) and the backend mints the license. You register your app once instead of embedding a key. See [Attested bootstrap](/docs/v3.0/concepts/attested-bootstrap/) for the model and [Prerequisites](/docs/v3.0/getting-started/prerequisites/) for setup.

New `LicenseError` cases accompany this: `bootstrapFailed(reason:)` carries a `BootstrapReason` naming the cause. See [License Types](/docs/v3.0/api-reference/license-types/).

## Breaking changes

- **iOS: `confidence.flags` JSON values are now `UPPER_SNAKE`.** `toJson()` / `toJsonl()` on iOS previously emitted Swift case names (`vpnActive`). They now emit `VPN_ACTIVE`, matching Android. This affects only code that parses the JSON on iOS. The typed `ConfidenceSummary.flags` and `toStr()` are unchanged. See [Serialization](/docs/v3.0/api-reference/serialization/).
- **Region resolution can now return `regionUnresolved`.** A country or subdivision predicate that cannot resolve the device's region at the required confidence returns `INDETERMINATE / REGION_UNRESOLVED` instead of silently coarsening to an `earth()` claim. Code that treated every `INDETERMINATE` the same should read the reason. See [Verdicts](/docs/v3.0/concepts/verdicts/).

## Behavior changes

- **Proof emission is semantic-binding v2.** Proofs now bind city and earth geometry and a `location_verdict`. Verify proofs with `octet-verify` 1.5.0 or later, or on-device with [`Octet.verify`](/docs/v3.0/api-reference/octet-verify/). Both still accept 1.x proofs.
- **New adversarial reason codes.** A detected spoof now carries `spoofingDetected` or `tampering`, distinct from the benign "couldn't measure" reasons. See the [reason-code taxonomy](/docs/v3.0/concepts/verdicts/).

## New in 2.0

- **`OctetSdk.close()`** ends the session and stops the Android location foreground service. Call it when your proof flow finishes. See [Session Lifecycle](/docs/v3.0/concepts/lifecycle/).
- **On-device verification** with [`Octet.verify`](/docs/v3.0/api-reference/octet-verify/).
- **Decision binding and force-fresh** on the predicates: `decisionRef` and `forceFresh`. See [Proof Binding](/docs/v3.0/concepts/proof-binding/).

## Version coordinates

Pin `3.0.0`. iOS Swift Package Manager `exact: "3.0.0"`, Android Gradle `com.octetproof:sdk:3.0.0`. See the [iOS](/docs/v3.0/getting-started/ios-quickstart/) and [Android](/docs/v3.0/getting-started/android-quickstart/) quick starts.
