calle-android-sdk is the native Kotlin SDK for integrating CALL-E AI voice call agents into Android and Wear OS applications.
Fully updated and compliant with the CALL-E V2 API specification (/v2/calls) and SDK 1.0.
All SDK sources are located under src/main/kotlin/com/calle/sdk for seamless Gradle dependency integration or direct copy-paste into any Android project.
- CALL-E V2 API Support: Migrated to
POST /v2/calls(HTTP 202 Accepted). - Mandatory Idempotency: Built-in automatic
Idempotency-Keygeneration and replay protection. - Structured Scalar Schemas (
ResultSchema): Closed JSON schema extraction (string,boolean,integer,number) with zero-config defaults. - Accurate Readiness Rule: Reactive
pollCallStatuspolling adheres strictly toresult_status != PENDING. - Top-level Transcripts: Read conversation turns directly from the root
transcriptarray. - Lifecycle Events Streaming: Track live progress (
call.ringing,call.connected,call.speech,call.asr) viapollCallEvents. - Early Cancellation: Support for
cancelCall(callId)prior to provider submission. - Security Modernization: Migrated to modern AndroidX
MasterKey.Builderwith hardware Keystore AES-256 encryption.
src/main/kotlin/com/calle/sdk/
βββ CallEClient.kt # Core CALL-E V2 Client, Reactive Status & Event Flows
βββ GroqClient.kt # Groq Cloud LLM Prompt Refinement
βββ data/
β βββ SmartCallResolver.kt # SerpApi Google Search + Groq Intent Resolver
β βββ SerpApiClient.kt # Google Business & Phone Lookup
β βββ DeviceContactResolver.kt # Local Device Contacts Provider
β βββ CallEPreferences.kt # AndroidX AES-256 Encrypted Keystore Storage
βββ models/
β βββ CallEModels.kt # V2 ResultSchema, CallResponse, Events & Enums
βββ ui/
βββ CallEStatusBadge.kt # Animated Jetpack Compose UI Status Badge
flowchart TD
subgraph Client ["π± Client Application (Android / Wear OS)"]
UI["Compose UI / Wear OS Companion"]
Resolver["SmartCallResolver"]
SDK["CallEClient (Ktor V2 Engine)"]
end
subgraph Intelligence ["π§ Intelligence & Resolution"]
Serp["SerpApi (Google Business & Phone Lookup)"]
Groq["Groq Cloud (Llama 3.3 Prompt & Intent Refinement)"]
end
subgraph Infrastructure ["βοΈ CALL-E Cloud & Telephony"]
CalleAPI["CALL-E V2 API (/v2/calls)"]
Agent["Autonomous AI Voice Call Agent"]
PhoneNetwork["PSTN / Cellular Telephone Network"]
end
UI -->|Natural language request| Resolver
Resolver -->|Query business telephone| Serp
Resolver -->|Refine goal & scalar schema| Groq
Resolver -->|Construct CallRequest| SDK
SDK -->|Idempotent POST /v2/calls| CalleAPI
CalleAPI --> Agent
Agent -->|Live autonomous voice call| PhoneNetwork
CalleAPI -.->|pollCallEvents & pollCallStatus Flow| SDK
SDK -.->|Reactive state updates & transcript| UI
Add JitPack to your settings.gradle.kts:
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven { url = uri("https://jitpack.io") }
}
}Add the dependency to your app module's build.gradle.kts:
dependencies {
implementation("com.github.tensormind-tech:calle-android-sdk:2.1.0")
}- Copy the
src/main/kotlin/com/calle/sdkdirectory from this repository into your project (app/src/main/java/com/calle/sdk). - Add Ktor and Serialization dependencies to your app's
build.gradle.kts:
dependencies {
implementation("io.ktor:ktor-client-core:2.3.12")
implementation("io.ktor:ktor-client-android:2.3.12")
implementation("io.ktor:ktor-client-content-negotiation:2.3.12")
implementation("io.ktor:ktor-serialization-kotlinx-json:2.3.12")
implementation("io.ktor:ktor-client-logging:2.3.12")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
implementation("androidx.security:security-crypto:1.1.0-alpha06")
}Add network access to your app/src/main/AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Required: for CALL-E V2 API, Groq LLM, and SerpApi network calls -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- Optional: Only if using DeviceContactResolver for device contact lookup -->
<uses-permission android:name="android.permission.READ_CONTACTS" />
</manifest>import com.calle.sdk.CallEClient
import com.calle.sdk.models.CallRequest
// Initialize with production key or "DEMO_KEY" for offline testing
val client = CallEClient(apiKey = "YOUR_CALLE_API_KEY")
lifecycleScope.launch {
val request = CallRequest(
toPhoneNumber = "+15550199000",
promptInstructions = "Ask opening hours tonight and vegetarian menu items."
)
val result = client.dispatchCall(request)
result.onSuccess { response ->
println("Call Accepted! ID: ${response.id}, Billing Call ID: ${response.billingCallId}")
}
}Track call lifecycle transitions in real-time until the business result is finalized:
lifecycleScope.launch {
client.pollCallStatus(callId = "call_123456", pollIntervalMs = 2000L)
.collect { response ->
println("Status: ${response.status}, Outcome: ${response.callOutcome}, Result Status: ${response.resultStatus}")
if (response.isResultReady) {
println("Final Summary: ${response.bestSummary}")
println("Structured Result: ${response.result}")
}
}
}lifecycleScope.launch {
client.pollCallEvents(callId = "call_123456")
.collect { event ->
println("[${event.type}] ${event.message}")
}
}If your user only types or speaks a business name, use SmartCallResolver to look up the business phone number automatically on Google via SerpApi and refine the prompt via Groq:
import com.calle.sdk.data.SmartCallResolver
val resolver = SmartCallResolver(
serpApiKey = "YOUR_SERPAPI_KEY",
groqApiKey = "YOUR_GROQ_API_KEY"
)
lifecycleScope.launch {
val resolvedInfo = resolver.resolveCall("Call Cattleack Barbeque in Farmers Branch to check hours")
println("Found Phone: ${resolvedInfo.phone}") // +19726440167
println("Refined Task: ${resolvedInfo.task}") // Ask Cattleack Barbeque in Farmers Branch...
val request = CallRequest(
toPhoneNumber = resolvedInfo.phone,
promptInstructions = resolvedInfo.task
)
client.dispatchCall(request)
}lifecycleScope.launch {
val transcriptResult = client.getTranscript(callId = "call_123456")
transcriptResult.onSuccess { transcriptText ->
println(transcriptText)
/*
Output:
[AGENT]: Hello! Calling to check opening hours tonight.
[RECIPIENT]: We are open until 10 PM.
*/
}
}import com.calle.sdk.ui.CallEStatusBadge
@Composable
fun CallStatusScreen(callResponse: CallResponse) {
// Pass CallResponse directly: automatically reflects dual telephone & extraction status
CallEStatusBadge(response = callResponse, compact = false)
}For complete class specifications, data models, error handling, and Wear OS guidelines, check out CALLE-ANDROID-SDK.md.
Have questions, ideas for new features, or need help integrating the SDK?
Join our community on GitHub Discussions!
- π’ SDK v2.1 Announcement β Read about the latest features, schema validation, and lifecycle streaming.
- π‘ Feature Ideas & Requests β Suggest new integrations or capabilities.
- π Q&A β Get help with Android, Wear OS, or CALL-E API setup.
Zero Telemetry Β· Zero Data Collection Β· Full Developer Control
This SDK operates with zero telemetry and zero data collection. All API credentials are stored locally on-device only β no user data, analytics, device identifiers, or usage metrics are ever collected, transmitted, or processed by this SDK.
π Full Privacy Policy Β· π Full Terms of Use
Copyright Β© 2026 TensorMind Technologies. All rights reserved.
Licensed under the MIT License.
