Claude API Kotlin Example

Working Kotlin code to call the Claude API in 2026. No official SDK — use OkHttp or Ktor. Covers streaming SSE, suspend functions, Android integration, and Spring Boot backend.

💥 50p impulse-buy: Power Prompts PDF (first 10 buyers) 30 battle-tested Claude Code prompts · 8-page PDF · paste into CLAUDE.md and never re-type a prompt again · 50p impulse-buy, no commitment

Anthropic has no official Kotlin SDK as of 2026, but calling the Claude REST API from Kotlin is straightforward using OkHttp, Ktor, or the built-in Java HttpClient. All examples use idiomatic Kotlin: data classes, coroutines, and string templates.

Minimal example — OkHttp (JVM + Android backend)

// build.gradle.kts
// implementation("com.squareup.okhttp3:okhttp:4.12.0")
// implementation("org.json:json:20240303")

import okhttp3.*
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.toRequestBody
import org.json.JSONObject

val client = OkHttpClient()
val apiKey = System.getenv("ANTHROPIC_API_KEY")

fun askClaude(prompt: String): String {
    val body = JSONObject().apply {
        put("model", "claude-sonnet-4-6")
        put("max_tokens", 1024)
        put("messages", listOf(mapOf("role" to "user", "content" to prompt)))
    }.toString()

    val request = Request.Builder()
        .url("https://api.anthropic.com/v1/messages")
        .addHeader("x-api-key", apiKey)
        .addHeader("anthropic-version", "2023-06-01")
        .addHeader("content-type", "application/json")
        .post(body.toRequestBody("application/json".toMediaType()))
        .build()

    client.newCall(request).execute().use { response ->
        val json = JSONObject(response.body!!.string())
        return json.getJSONArray("content").getJSONObject(0).getString("text")
    }
}

fun main() {
    println(askClaude("Explain Kotlin coroutines in one paragraph."))
}

Idiomatic Kotlin with coroutines — Ktor (suspend)

// implementation("io.ktor:ktor-client-core:2.3.12")
// implementation("io.ktor:ktor-client-cio:2.3.12")
// implementation("io.ktor:ktor-client-content-negotiation:2.3.12")
// implementation("io.ktor:ktor-serialization-kotlinx-json:2.3.12")

import io.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.engine.cio.*
import io.ktor.client.plugins.contentnegotiation.*
import io.ktor.client.request.*
import io.ktor.http.*
import io.ktor.serialization.kotlinx.json.*
import kotlinx.coroutines.runBlocking
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.*

@Serializable
data class ClaudeRequest(
    val model: String,
    val max_tokens: Int,
    val messages: List<Map<String, String>>
)

@Serializable
data class ClaudeResponse(
    val content: List<Map<String, String>>
)

val httpClient = HttpClient(CIO) {
    install(ContentNegotiation) { json() }
}

suspend fun askClaudeAsync(prompt: String): String {
    val response: ClaudeResponse = httpClient.post("https://api.anthropic.com/v1/messages") {
        header("x-api-key", System.getenv("ANTHROPIC_API_KEY"))
        header("anthropic-version", "2023-06-01")
        contentType(ContentType.Application.Json)
        setBody(ClaudeRequest(
            model = "claude-sonnet-4-6",
            max_tokens = 1024,
            messages = listOf(mapOf("role" to "user", "content" to prompt))
        ))
    }.body()
    return response.content.first()["text"] ?: ""
}

fun main() = runBlocking {
    println(askClaudeAsync("What is the capital of France?"))
}

Streaming SSE — OkHttp line-by-line

import okhttp3.*
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.toRequestBody
import org.json.JSONObject

fun streamClaude(prompt: String) {
    val body = JSONObject().apply {
        put("model", "claude-sonnet-4-6")
        put("max_tokens", 1024)
        put("stream", true)
        put("messages", listOf(mapOf("role" to "user", "content" to prompt)))
    }.toString()

    val request = Request.Builder()
        .url("https://api.anthropic.com/v1/messages")
        .addHeader("x-api-key", System.getenv("ANTHROPIC_API_KEY"))
        .addHeader("anthropic-version", "2023-06-01")
        .addHeader("content-type", "application/json")
        .post(body.toRequestBody("application/json".toMediaType()))
        .build()

    OkHttpClient().newCall(request).execute().use { response ->
        response.body?.byteStream()?.bufferedReader()?.lines()?.forEach { line ->
            if (line.startsWith("data: ") && line != "data: [DONE]") {
                val data = JSONObject(line.removePrefix("data: "))
                if (data.getString("type") == "content_block_delta") {
                    val delta = data.getJSONObject("delta")
                    if (delta.getString("type") == "text_delta") {
                        print(delta.getString("text"))
                        System.out.flush()
                    }
                }
            }
        }
    }
    println()
}

fun main() = streamClaude("Write a haiku about Kotlin.")

Spring Boot backend (Kotlin DSL)

// Proxies Claude requests from a mobile app — API key stays server-side
@RestController
@RequestMapping("/api")
class ClaudeController {

    private val okHttp = OkHttpClient()

    @PostMapping("/chat")
    fun chat(@RequestBody req: Map<String, String>): ResponseEntity<String> {
        val prompt = req["message"] ?: return ResponseEntity.badRequest().build()
        val reply = askClaude(prompt)  // reuse helper from minimal example above
        return ResponseEntity.ok(reply)
    }
}

OkHttp vs Ktor vs Java HttpClient

LibraryCoroutinesAndroidExtra dep?Best for
OkHttpCallbacks / enqueueYesYes (~700 KB)Android backends, existing OkHttp users
Ktor HttpClientNative suspendVia Android engineYes (~2 MB full)Idiomatic Kotlin, multi-platform
Java HttpClientCompletableFutureNo (API 26+)None (JDK 11+)Zero-dep JVM services

Estimate the token cost of your Kotlin-Claude integration with the Claude API Cost Calculator. For the Java equivalent, see the Java example. For MCP server patterns, see the Python MCP server guide.

Frequently asked questions

Is there an official Anthropic Kotlin SDK?
Not as of mid-2026. The official SDKs are Python, Node.js/TypeScript, and Java. For Kotlin, use the Java HTTP client, OkHttp, or Ktor's HttpClient — all work on JVM and Android.
How do I call the Claude API from an Android app?
Never call the Anthropic API directly from Android — your API key would be visible in the APK. Instead, create a backend (e.g. Cloud Run + Ktor) that proxies requests, then call your backend from the Android app.
Does the Java Claude API example work in Kotlin?
Yes. All Java code compiles and runs in Kotlin. Kotlin also offers idiomatic improvements: data classes, coroutines (suspend + async), and string templates. The examples below use idiomatic Kotlin style.
What Kotlin HTTP library should I use for the Claude API?
OkHttp is the most widely used for Android and JVM. Ktor is idiomatic Kotlin with coroutine-native suspend functions. The Java HttpClient (built-in since Java 11) works too and requires no extra dependency.
How do I stream Claude responses in Kotlin?
Use OkHttp's `enqueue` callback with `response.body?.byteStream()` and read lines. For Ktor use `client.preparePost { ... }.execute { response -> response.bodyAsChannel() }`. Both give you SSE lines to parse.

Free tools

Cost Calculator → API Cookbook → Diff Summarizer → Skills Browser →

More examples

Claude API Python QuickstartClaude API Node.js / TypeScript QuickstartClaude API Streaming in PythonClaude API Streaming in Node.js / TypeScriptClaude API Tool Use in PythonClaude API Tool Use in Node.js / TypeScript