> This is a page from the ElevenLabs documentation. For a complete page index, fetch https://elevenlabs.io/docs/llms.txt. For the full documentation in a single file, fetch https://elevenlabs.io/docs/llms-full.txt.

# Kotlin SDK

> **Info**
>
> Raadpleeg het [ElevenAgents-overzicht](/docs/nl/eleven-agents/overview) voor een uitleg over hoe
> ElevenAgents werkt.

## Installatie

Voeg de ElevenLabs SDK toe aan je Android-project door de volgende dependency op te nemen in het `build.gradle`-bestand op appniveau:

**`build.gradle.kts`**

```kotlin build.gradle.kts
dependencies {
    // ElevenLabs Agents SDK (Android)
    implementation("io.elevenlabs:elevenlabs-android:<latest>")

    // Kotlin coroutines, AndroidX, etc., as needed by your app
}
```

> **Tip**
>
> Een voorbeeld-Android-app die deze SDK gebruikt, vind je
> [hier](https://github.com/elevenlabs/elevenlabs-android/tree/main/example-app)

## Vereisten

* Android API-niveau 21 (Android 5.0) of hoger
* Internettoestemming voor API-calls
* Microfoontoestemming voor spraakinvoer
* Netwerkbeveiligingsconfiguratie voor HTTPS-calls

## Configuratie

### Manifestconfiguratie

Voeg de benodigde toestemmingen toe aan je `AndroidManifest.xml`:

```xml
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
```

### Runtime-toestemmingen

Voor Android 6.0 (API-niveau 23) en hoger moet je microfoontoestemming tijdens runtime aanvragen:

```kotlin
import android.Manifest
import android.content.pm.PackageManager
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat

private fun requestMicrophonePermission() {
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)
        != PackageManager.PERMISSION_GRANTED) {

        if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.RECORD_AUDIO)) {
            // Show explanation to the user
            showPermissionExplanationDialog()
        } else {
            ActivityCompat.requestPermissions(
                this,
                arrayOf(Manifest.permission.RECORD_AUDIO),
                MICROPHONE_PERMISSION_REQUEST_CODE
            )
        }
    }
}
```

## Gebruik

Initialiseer de ElevenLabs SDK in je `Application`-klasse of hoofdactiviteit:

Start een conversatiesessie met een van de volgende opties:

* Openbare agent: geef `agentId` door
* Private agent: geef `conversationToken` door dat door je backend is verstrekt (stel je API-sleutel nooit bloot aan de client).

```kotlin
import io.elevenlabs.ConversationClient
import io.elevenlabs.ConversationConfig
import io.elevenlabs.ConversationSession
import io.elevenlabs.ClientTool
import io.elevenlabs.ClientToolResult

// Start a public agent session (token generated for you)
val config = ConversationConfig(
    agentId = "<your_public_agent_id>", // OR conversationToken = "<token>"
    userId = "your-user-id",
    // Optional callbacks
    onConnect = { conversationId ->
        // Called when the conversation is connected and returns the conversation ID. You can access conversationId via session.getId() too
    },
    onMessage = { source, messageJson ->
        // Raw JSON messages from data channel; useful for logging/telemetry
    },
    onModeChange = { mode ->
        // "speaking" | "listening" — drive UI indicators
    },
    onStatusChange = { status ->
        // "connected" | "connecting" | "disconnected"
    },
    onCanSendFeedbackChange = { canSend ->
        // Enable/disable thumbs up/down buttons for feedback reporting
    },
    onUnhandledClientToolCall = { call ->
        // Agent requested a client tool not registered on the device
    },
    onVadScore = { score ->
        // Voice Activity Detection score, range from 0 to 1 where higher values indicate higher confidence of speech
    },
    onAudioAlignment = { alignment ->
        // Character-level timing data for synchronized text display
        val chars = alignment["chars"] as? List<*>
        val startTimes = alignment["char_start_times_ms"] as? List<*>
        val durations = alignment["char_durations_ms"] as? List<*>
        Log.d("ExampleApp", "Audio alignment: $chars")
    },
    // List of client tools the agent can invoke
    clientTools = mapOf(
        "logMessage" to object : ClientTool {
            override suspend fun execute(parameters: Map<String, Any>): ClientToolResult {
                val message = parameters["message"] as? String

                Log.d("ExampleApp", "[INFO] Client Tool Log: $message")
                return ClientToolResult.success("Message logged successfully")
            }
        }
    ),
)

// In an Activity context
val session: ConversationSession = ConversationClient.startSession(config, this)
```

Houd er rekening mee dat ElevenAgents microfoontoegang vereist. Overweeg om in de UI van je app uit te leggen waarom toestemming nodig is en deze aan te vragen voordat de conversatie begint, vooral op Android 6.0+ waar runtime-toestemmingen vereist zijn.

> **Note**
>
> Als een tool op de server is geconfigureerd met `expects_response=false`, retourneer dan `null` vanuit `execute`
> om het terugsturen van een toolresultaat naar de agent over te slaan.

## Openbare versus private agents

* **Openbare agents** (geen authenticatie): Initialiseer met `agentId` in `ConversationConfig`. De SDK vraagt een conversatietoken aan bij ElevenLabs zonder dat een API-sleutel op het apparaat nodig is.
* **Private agents** (authenticatie): Initialiseer met `conversationToken` in `ConversationConfig`. Je server vraagt een conversatietoken aan bij ElevenLabs met je ElevenLabs API-sleutel.

> **Error**
>
> Sluit API-sleutels nooit in clients in. Ze kunnen eenvoudig worden geëxtraheerd en kwaadwillig worden gebruikt.

## Clienttools

Registreer clienttools zodat de agent lokale mogelijkheden op het apparaat kan aanroepen.

```kotlin
val config = ConversationConfig(
    agentId = "<public_agent>",
    clientTools = mapOf(
        "logMessage" to object : io.elevenlabs.ClientTool {
            override suspend fun execute(parameters: Map<String, Any>): io.elevenlabs.ClientToolResult? {
                val message = parameters["message"] as? String ?: return io.elevenlabs.ClientToolResult.failure("Missing 'message'")

                android.util.Log.d("ClientTool", "Log: $message")
                return null // No response needed for fire-and-forget tools
            }
        }
    )
)
```

Wanneer de agent een `client_tool_call` uitvoert, voert de SDK de overeenkomende tool uit en antwoordt deze met een `client_tool_result`. Als de tool niet is geregistreerd, wordt `onUnhandledClientToolCall` aangeroepen en wordt een foutresultaat naar de agent teruggestuurd (als een antwoord wordt verwacht).

### Overzicht van callbacks

* **onConnect** - Wordt aangeroepen wanneer de WebRTC-verbinding tot stand is gebracht. Retourneert de conversatie-ID.
* **onMessage** - Wordt aangeroepen wanneer een nieuw bericht wordt ontvangen. Dit kunnen voorlopige of definitieve transcripties van de stem van de gebruiker zijn, antwoorden die door een LLM zijn geproduceerd, of debugberichten. Geeft de bron (`"ai"` of `"user"`) en het onbewerkte JSON-bericht.
* **onModeChange** - Wordt aangeroepen wanneer de conversatiemodus verandert. Dit is nuttig om aan te geven of de agent spreekt (`"speaking"`) of luistert (`"listening"`).
* **onStatusChange** - Wordt aangeroepen wanneer de conversatiestatus verandert (`"connected"`, `"connecting"` of `"disconnected"`).
* **onCanSendFeedbackChange** - Wordt aangeroepen wanneer de mogelijkheid om feedback te versturen verandert. Schakelt feedbackknoppen in of uit.
* **onUnhandledClientToolCall** - Wordt aangeroepen wanneer de agent een clienttool aanvraagt die niet op het apparaat is geregistreerd.
* **onVadScore** - Wordt aangeroepen wanneer de score voor spraakactiviteitsdetectie verandert. Bereik van 0 tot 1, waarbij hogere waarden een grotere zekerheid van spraak aangeven.
* **onAudioAlignment** - Wordt aangeroepen wanneer audio-uitlijningsgegevens worden ontvangen en timinginformatie op tekenniveau voor spraak van de agent biedt.

> **Warning**
>
> Niet alle clientevents zijn standaard ingeschakeld voor een agent. Als je een callback hebt ingeschakeld maar
> geen events ontvangt, controleer dan of voor je ElevenLabs-agent het bijbehorende event
> is ingeschakeld. Dit kun je doen op het tabblad "Advanced" in de agentinstellingen in het ElevenLabs-dashboard.

### Methoden

#### startSession

De methode `startSession` start de WebRTC-verbinding en gebruikt de microfoon om met de ElevenLabs Agents-agent te communiceren.

##### Openbare agents

Voor openbare agents (dat wil zeggen: agents waarvoor authenticatie niet is ingeschakeld) is alleen de `agentId` vereist. Je kunt de agent-ID ophalen via de [ElevenLabs-UI](https://elevenlabs.io/app/agents).

```kotlin
val session = ConversationClient.startSession(
    config = ConversationConfig(
        agentId = "your-agent-id"
    ),
    context = this
)
```

##### Private agents

Voor private agents moet je een `conversationToken` doorgeven dat je via de ElevenLabs API hebt verkregen. Voor het genereren van dit token is een ElevenLabs API-sleutel vereist.

> **Tip**
>
> De `conversationToken` is 10 minuten geldig.

```typescript maxLines=0
// Server-side token generation (Node.js example)

app.get("/conversation-token", yourAuthMiddleware, async (req, res) => {
  const response = await fetch(
    `https://api.elevenlabs.io/v1/convai/conversation/token?agent_id=${process.env.AGENT_ID}`,
    {
      headers: {
        // Requesting a conversation token requires your ElevenLabs API key
        // Do NOT expose your API key to the client!
        "xi-api-key": process.env.ELEVENLABS_API_KEY,
      },
    }
  );

  if (!response.ok) {
    return res.status(500).send("Failed to get conversation token");
  }

  const body = await response.json();
  res.send(body.token);
});
```

Geef het token vervolgens door aan de methode `startSession`. Houd er rekening mee dat voor private agents alleen de `conversationToken` vereist is.

```kotlin

// Get conversation token from your server
val conversationToken = fetchConversationTokenFromServer()

// For private agents, pass in the conversation token
val session = ConversationClient.startSession(
    config = ConversationConfig(
        conversationToken = conversationToken
    ),
    context = this
)
```

Je kunt optioneel een gebruikers-ID doorgeven om de gebruiker in de conversatie te identificeren. Dit kan je eigen klant-ID zijn. Deze wordt opgenomen in de gegevens voor het starten van de conversatie die naar de server worden gestuurd.

```kotlin
val session = ConversationClient.startSession(
    config = ConversationConfig(
        agentId = "your-agent-id",
        userId = "your-user-id"
    ),
    context = this
)
```

#### endSession

Een methode om de conversatie handmatig te beëindigen. De methode verbreekt de verbinding en beëindigt de conversatie.

```kotlin
session.endSession()
```

#### sendUserMessage

Stuur een tekstbericht naar de agent tijdens een actieve conversatie. Hiermee wordt een antwoord van de agent geactiveerd.

```kotlin
session.sendUserMessage("Hello, how can you help me?")
```

#### sendContextualUpdate

Stuurt contextuele informatie naar de agent die geen antwoord activeert.

```kotlin
session.sendContextualUpdate(
    "User navigated to the profile page. Consider this for next response."
)
```

#### sendFeedback

Geef feedback over de kwaliteit van de conversatie. Dit helpt de prestaties van de agent te verbeteren. Gebruik `onCanSendFeedbackChange` om je UI voor duim omhoog/omlaag in te schakelen wanneer feedback is toegestaan.

```kotlin
// Positive feedback
session.sendFeedback(true)

// Negative feedback
session.sendFeedback(false)
```

#### sendUserActivity

Meldt gebruikersactiviteit aan de agent om onderbrekingen te voorkomen. Handig wanneer de gebruiker de app actief gebruikt en de agent moet pauzeren met spreken, bijvoorbeeld wanneer de gebruiker in een chat typt.

De agent pauzeert ongeveer 2 seconden met spreken nadat dit signaal is ontvangen.

```kotlin
session.sendUserActivity()
```

#### getId

Haal de conversatie-ID op.

```kotlin
val conversationId = session.getId()
Log.d("Conversation", "Conversation ID: $conversationId")
// e.g., "conv_123"
```

#### Dempen/dempen opheffen

```kotlin
session.toggleMute()
session.setMicMuted(true)   // mute
session.setMicMuted(false)  // unmute
```

Controleer `session.isMuted` om het UI-label bij te werken tussen "Dempen" en "Dempen opheffen".

### Eigenschappen

#### status

Haal de huidige status van de conversatie op.

```kotlin
val status = session.status
Log.d("Conversation", "Current status: $status")
// Values: DISCONNECTED, CONNECTING, CONNECTED
```

## ProGuard / R8

Als je verkleint/obfusceert, zorg er dan voor dat Gson-modellen en LiveKit behouden blijven. Voorbeeldregels (pas ze waar nodig aan):

```proguard
-keep class io.elevenlabs.** { *; }
-keep class io.livekit.** { *; }
-keepattributes *Annotation*
```

## Problemen oplossen

* Zorg dat tijdens runtime microfoontoestemming is verleend
* Als opnieuw verbinden vastloopt, controleer dan of je app `session.endSession()` aanroept en of je een nieuwe sessie-instantie start voordat je opnieuw verbinding maakt
* Controleer bij emulators of audio-invoer-/uitvoerroutes werken; fysieke apparaten werken doorgaans betrouwbaarder

## Voorbeeldimplementatie

Bekijk voor een voorbeeldimplementatie de voorbeeldapp in de [ElevenLabs Android SDK-repository](https://github.com/elevenlabs/elevenlabs-android/tree/main/example-app). De app toont:

* Verbinden/verbreken met één tik
* Indicator voor spreken/luisteren
* Feedbackknoppen met UI in-/uitschakelen
* Typindicator via `sendUserActivity()`
* Contextuele berichten en gebruikersberichten vanuit een invoerveld
* Knop voor microfoon dempen/dempen opheffen