Skip to content Documentation index for agents (llms.txt)
Glotto Beta
Get started

Kotlin

The Kotlin SDK is a modern, coroutine-first client emitted from the same GlottoIR as every other target. It leans on Kotlin’s defaults — primary-constructor config with default args, nullable String? params — and emits KDoc from the operation prose in the spec.

Quickstart

implementation("com.your-org:petstore:1.0.0")
import com.your_org.petstore.Client
import kotlinx.coroutines.runBlocking

fun main() = runBlocking {
    val client = Client(token = System.getenv("PETSTORE_TOKEN"))

    // methods are suspend functions
    val pet = client.pets.createPet(NewPet(name = "Rex"))

    // paginated methods are Flows
    client.pets.listPets().collect { println(it.name) }
}

Resource sub-clients

Operations hang off resource accessors — client.pets.get(id), client.pets.photos.add(...) — rather than a flat method list, the same service-accessor shape the other engines emit.

Coroutines

Methods are suspend functions (client.pets.get(id) from a coroutine), with streaming and pagination surfaced as a Flow, so the SDK composes with structured concurrency rather than blocking a thread. Cancelling the calling coroutine aborts an active buffered HTTP request, including response-body reads, on JVM and Android. Cancellation propagates as CancellationException and is not retried. The Multiplatform client uses Ktor’s coroutine cancellation support.

Typed errors

Non-2xx responses throw ApiError, a RuntimeException carrying the parsed, typed error body — Kotlin has no checked exceptions, so there is nothing to wrap. Discriminated-union bodies resolve to the right sealed-type variant. See Errors.

Pagination

Paginated list methods expose a Flow that walks every page as you collect it, advancing the cursor for you. See Pagination.

Retries & backoff

Transient failures (5xx, 429, transport errors) retry with exponential backoff and jitter, configurable per client. See Retries & timeouts, Streaming, and Authentication.

Android-native

Opt-in. The Android target is compile-verified against a real Android SDK by the scheduled mobile-compile CI lane — the emitted library (including its OkHttp transport) builds with the real Android Gradle Plugin. The plain-JVM Kotlin SDK above is the default and is unaffected.

Opt in with targets.kotlin.android: true in your glotto.yml to emit an Android library (com.android.library) instead of the plain-JVM package — the same native-mobile integration the React Native SDK ships, adapted to Kotlin:

targets:
  kotlin:
    android: true
  • Secure token storage. The client takes an optional tokenStore: TokenStore?; the bearer token is read from it per request (falling back to the static token). A Keystore-backed implementation is generated for you — androidKeystoreTokenStore(context) encrypts values with an AES-256-GCM key held in the Android Keystore (no third-party crypto dependency).

  • Network-state-aware retries. Pass a ConnectivityMonitor and the retry loop awaits the backoff and re-checks while the device is offline rather than burning the request; the generated AndroidConnectivityMonitor is backed by the system ConnectivityManager.

  • Lifecycle-aware backoff. Pass an AppLifecycle and the backoff pauses (no retry attempt consumed) while the app is backgrounded; the generated AndroidAppLifecycle is backed by ProcessLifecycleOwner.

  • OkHttp transport. The plain-JVM SDK’s HTTP transport is the JDK’s java.net.http.HttpClient, which is absent from android.jar — so the Android variant emits its entire transport (requests, retries, streaming, file upload, OAuth token exchange) on OkHttp instead, preserving the same retry/Retry-After/telemetry/idempotency behavior. OkHttp is added as a dependency automatically.

The emitted build.gradle.kts carries the android {} block (with the Java/Kotlin JVM target pinned to 17) and the androidx.lifecycle / okhttp dependencies, and the AndroidManifest.xml declares the INTERNET and ACCESS_NETWORK_STATE permissions. The interfaces (TokenStore, ConnectivityMonitor, AppLifecycle) are plain Kotlin, so you can supply your own implementations or the bundled androidx-backed ones.

Biometric-gated storage

Opt-in, experimental. targets.kotlin.androidBiometric: true requires targets.kotlin.android: true and is compile-verified on the scheduled mobile-compile lane. The plain Keystore store above stays the default and byte-identical.

For credentials that must be released only after the user authenticates, add targets.kotlin.androidBiometric: true:

targets:
  kotlin:
    android: true
    androidBiometric: true

This additionally emits a BiometricKeystoreTokenStore (via androidBiometricKeystoreTokenStore(activity, promptInfo)) whose AES-256-GCM key is created with setUserAuthenticationRequired(true), so every read and write is authorized through a BiometricPrompt (class-3 / STRONG biometrics) bound to the crypto operation — the plain androidKeystoreTokenStore above stays available. The emitted build.gradle.kts adds the androidx.biometric dependency and the AndroidManifest.xml declares the USE_BIOMETRIC permission.

Unknown response fields

Your API can add a response field without it being a breaking change — but a generated data class has no property to put it in, and Gson discards what it does not recognize. The generated models keep it instead: a field the SDK wasn’t generated from is retained on decode, readable through an accessor, and written back out when the model is re-serialized.

val pet = client.pets.createPet(body)

// A field your API started returning after this SDK was generated.
val species = pet.extraFields()["species"]

// Re-encoding preserves it — a read-modify-write never silently drops it.
val json = client.gson.toJson(pet)

extraFields() returns a read-only Map<String, JsonElement>, so nested objects and arrays survive intact, and retention is recursive.

The Multiplatform target carries the same guarantee through kotlinx.serialization rather than Gson, so a commonMain consumer reads the same accessor. Your existing construction still compiles — the property is a trailing parameter with a default.

The retained fields are read-only by design. To send a field your spec doesn’t model yet, use the per-call extra-body escape hatch rather than writing to the retained bag.

Kotlin Multiplatform (preview)

Opt-in, phased. The entire shared client now lives in commonMain on a Ktor transport — the model layer (kotlinx.serialization, including discriminated unions via a polymorphic serializer), the Client + retry loop, synchronous webhook verification (pure-Kotlin crypto), and the OAuth/PKCE helpers are all platform-agnostic and gson-free, compile-verified on a real toolchain. Every API shape the standard Kotlin SDK supports now also emits under the multiplatform target. Landed: the iOS target (iosX64/iosArm64/iosSimulatorArm64 on the Ktor Darwin/NSURLSession engine, compile-verified on a macOS/Xcode CI runner) including an iOS Keychain-backed secure token store, and the Android targetmultiplatform now composes with android (a declared androidTarget() on the OkHttp engine + an AndroidKeyStore secure token store), plus the opt-in JS / Wasm / watchOS / tvOS targets via targets.kotlin.multiplatformTargets.

Opt in with targets.kotlin.multiplatform: true to emit a Kotlin Multiplatform project instead of the single-module JVM library:

targets:
  kotlin:
    multiplatform: true

The engine emits a kotlin("multiplatform") build.gradle.kts with jvm() and the iOS targets (iosX64 / iosArm64 / iosSimulatorArm64), plus a shared commonMain source set holding the whole portable client: the kotlinx.serialization models (discriminated unions become a sealed interface with a polymorphic KSerializer that dispatches on the discriminator), the Client + retry loop on a Ktor HttpClient (the JVM target binds the OkHttp engine, iOS binds Darwin/NSURLSession; java.net.http is JVM-only and absent from Kotlin/Native), pure-Kotlin SHA-256/HMAC so webhook verification stays synchronous on every platform, and the OAuth/PKCE helpers (a suspend Ktor token exchange + a secure-random expect/actual for the PKCE verifier). The remaining java.* (time, UUID, env, URL-encoding) is handled by kotlin.time / kotlin.uuid / a common encoder plus a small expect/actual shim (JVM-backed by System/SecureRandom, iOS by posix/Foundation) — so the emitted client is gson-free and each platform source set carries only its HTTP engine + the platform actuals. The default (non-multiplatform) JVM SDK is unchanged. The iOS Kotlin/Native build is compile-verified on a scheduled macOS/Xcode CI runner. For secure credentials, the client takes an optional tokenStore: TokenStore? read per request (falling back to the static token); iOS ships a KeychainTokenStore backed by the system Keychain, and you can supply your own TokenStore on any platform. Setting targets.kotlin.android: true alongside multiplatform adds a declared androidTarget() (the OkHttp Ktor engine on androidMain + an AndroidKeyStore-backed KeystoreTokenStore) to the same KMP build — the android target is configured only on a machine with the Android SDK, so the jvm()/iOS build stays buildable without it.

Because the commonMain client is fully platform-agnostic, you can opt into extra targets beyond the default JVM/iOS(+Android) set with targets.kotlin.multiplatformTargets — any of js, wasmJs, watchos, tvos:

targets:
  kotlin:
    multiplatform: true
    multiplatformTargets: [js, wasmJs, watchos, tvos]

js adds a js(IR) target and wasmJs a Kotlin/Wasm target, both on the Ktor JS engine (browser fetch / Node) with a Platform.js.kt / Platform.wasmJs.kt actual over the standard JS APIs (process.env, the JS Date, Web-Crypto getRandomValues); webhook verification stays synchronous there too (the crypto is pure Kotlin). watchos / tvos add the watchOS/tvOS targets, which reuse the iOS Darwin actuals (and Keychain) via a shared appleMain source set. Omit multiplatformTargets (or leave it empty) and the output is exactly the JVM/iOS(+Android) project above, byte-for-byte. JS + Wasm are compile-verified on Linux CI; the Apple targets on the macOS lane.

Publishing works the same as the single-module Kotlin SDK: the generated multiplatform build.gradle.kts applies the com.vanniktech.maven.publish plugin, so publishing the Kotlin target (a single publishAndReleaseToMavenCentral Gradle task) ships the root module + every per-target variant (-jvm, -android, -iosarm64, -js, …) and the Gradle Module Metadata that lets a multiplatform consumer resolve the right artifact per target.

Pages, request controls, and files

Paginated methods also expose manual pages, so you can inspect one response and request its successor explicitly. Request overrides apply to the initial call and to each requested next page; see Retries & timeouts for precedence and cancellation.

Binary downloads return an owned byte response with metadata, a bounded read helper, and incremental consumption. Close the response when you stop early. Your generated README demonstrates these operations with your API’s names and the language’s native calling conventions.