import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# `Octet.start(...)`

The single bring-up call. Verifies the license key locally, activates against the Octet backend if needed, brings up the proof pipeline, and returns a fully-usable `OctetSdk` handle.

## Signature

<Tabs groupId="platform">
  <TabItem value="swift" label="Swift (iOS)">

```swift
public enum Octet {
    public static let sdkVersion: String  // "1.1.0"

    public static func start(
        config: OctetConfig,
        startPosition: Position? = nil
    ) async throws -> OctetSdk
}
```

  </TabItem>
  <TabItem value="kotlin" label="Kotlin (Android)">

```kotlin
object Octet {
    const val SDK_VERSION: String  // "1.1.0"

    suspend fun start(
        context: Context,
        config: OctetConfig,
        startPosition: Position? = null,
    ): OctetSdk
}
```

  </TabItem>
</Tabs>

`startPosition` is an optional hint used internally during pipeline bring-up. Most integrators omit it.

## What it does, in order

1. Loads (or generates) a per-install UUID from secure storage (Keychain on iOS, `EncryptedSharedPreferences` on Android).
2. Auto-detects the app id from the bundle (`Bundle.main.bundleIdentifier` / `context.packageName`).
3. Verifies the license key's PASETO signature locally against the SDK's embedded public keys.
4. Validates the cached activation token if present. Otherwise calls `POST /v1/activate` to acquire one.
5. Brings up the internal proof pipeline.
6. Attaches the resulting `LicenseStatus` to the returned `OctetSdk`.

## `OctetConfig`

<Tabs groupId="platform">
  <TabItem value="swift" label="Swift (iOS)">

```swift
public struct OctetConfig: Sendable {
    public let licenseKey: String
    public var proofUploadUrl: String?       // opt-in proof upload; nil disables (default)
    public var telemetryEnabled: Bool        // aggregate usage counters; default true
    public var advanced: AdvancedConfig

    public init(
        licenseKey: String,
        proofUploadUrl: String? = nil,
        telemetryEnabled: Bool = true,
        advanced: AdvancedConfig = AdvancedConfig()
    )

    public static let defaultActivationServerUrl: String  // "https://api.octetproof.com"
}
```

  </TabItem>
  <TabItem value="kotlin" label="Kotlin (Android)">

```kotlin
data class OctetConfig(
    val licenseKey: String,
    val proofUploadUrl: String? = null,      // opt-in proof upload; null disables (default)
    val telemetryEnabled: Boolean = true,    // aggregate usage counters; default true
    val advanced: AdvancedConfig = AdvancedConfig(),
) {
    companion object {
        const val DEFAULT_ACTIVATION_SERVER_URL: String  // "https://api.octetproof.com"
    }
}
```

  </TabItem>
</Tabs>

`licenseKey` is the only required field. It is a PASETO v4.public token in the wire form `octet_live_v4.public....` (prod) or `octet_test_...` (staging).

## `AdvancedConfig`

Still small. Battery profile, sensor tuning, and ML knobs stay internal. What is
public: the activation server, log level, [device-attestation](/docs/concepts/device-attestation/)
cadence, and the per-platform attestation knobs.

<Tabs groupId="platform">
  <TabItem value="swift" label="Swift (iOS)">

```swift
public struct AdvancedConfig: Sendable {
    public var activationServerUrl: String        // default: production
    public var logLevel: LogLevel                 // default: .info
    public var enableCertPinning: Bool            // default: false
    public var attestationCadence: AttestationCadence  // default: .periodic(interval: 300)

    public init(
        activationServerUrl: String = OctetConfig.defaultActivationServerUrl,
        logLevel: LogLevel = .info,
        enableCertPinning: Bool = false,
        attestationCadence: AttestationCadence = .periodic(interval: 300)
    )
}

public enum LogLevel { case verbose, debug, info, warn, error }

public enum AttestationCadence: Sendable {
    case perSession
    case periodic(interval: TimeInterval)   // default; 5 minutes
    case perProof
}
```

  </TabItem>
  <TabItem value="kotlin" label="Kotlin (Android)">

```kotlin
data class AdvancedConfig(
    val activationServerUrl: String = OctetConfig.DEFAULT_ACTIVATION_SERVER_URL,
    val logLevel: LogLevel = LogLevel.INFO,
    // Google Cloud project NUMBER for Play Integrity; null uses the Play-Console-linked project.
    val playIntegrityCloudProjectNumber: Long? = null,
    val attestationCadence: AttestationCadence = AttestationCadence.Periodic(intervalSeconds = 300),
)

enum class LogLevel { VERBOSE, DEBUG, INFO, WARN, ERROR }

sealed class AttestationCadence {
    object PerSession : AttestationCadence()
    data class Periodic(val intervalSeconds: Int) : AttestationCadence()  // default; 5 minutes
    object PerProof : AttestationCadence()
}
```

  </TabItem>
</Tabs>

Override `activationServerUrl` only when pointing at a staging or local backend.
`attestationCadence` and the Android `playIntegrityCloudProjectNumber` are covered
in [Device Attestation](/docs/concepts/device-attestation/). `enableCertPinning` opts
into the bundled certificate pin set for `api.octetproof.com`. The Play Integrity
cloud-project knob is Android-only: App Attest on iOS has no equivalent.

## Example

<Tabs groupId="platform">
  <TabItem value="swift" label="Swift (iOS)">

```swift
let config = OctetConfig(
    licenseKey: "octet_live_v4.public...."
    // advanced left to defaults
)
let sdk = try await Octet.start(config: config)
```

  </TabItem>
  <TabItem value="kotlin" label="Kotlin (Android)">

```kotlin
lifecycleScope.launch {
    val sdk = Octet.start(
        context = applicationContext,
        config = OctetConfig(licenseKey = "octet_live_v4.public....")
    )
}
```

  </TabItem>
</Tabs>

## Failure modes

`Octet.start(...)` throws a typed [`LicenseError`](/docs/api-reference/license-types/) for every license-related failure. Other failures propagate as their native error types. The SDK does **not** throw a raw `Error` / `Exception` for license reasons.

| `LicenseError` case | Meaning |
|---|---|
| `MalformedKey` | The key isn't a valid signed token. |
| `NoActivation` | No cached activation, offline. |
| `Expired` | Cached activation past the offline grace with the backend unreachable to refresh. |
| `ActivationWindowClosed` | Fresh device trying to activate after day 90. |
| `Revoked` | Admin revoke. |
| `Network(message)` / `Network(cause)` | Transient network failure during activation. |
| `ServerRejected(httpStatus, reason)` | Backend rejected for another reason (e.g., `app_blocked`). |

## See also

- [License & Activation](/docs/concepts/license-activation/) for the timeline model and activation flow.
- [`OctetSdk`](/docs/api-reference/octet-sdk/) for what `start` returns.
- [License Types](/docs/api-reference/license-types/) for the full `LicenseError` reference.
