Skip to content

Send a Message Programmatically

Drive the chat from the host app: send a message as the user without going through the input field. Useful for guided flows, in-app actions ("ask Kindly about my order"), or composing a message from contextual UI.

Usage

import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch
import no.kindly.chatsdk.chat.KindlySDK

lifecycleScope.launch {
    try {
        val message = KindlySDK.sendMessage("Hi, I have a question about my order").await()
        println("Sent — server id: ${message.id}")
    } catch (e: Exception) {
        println("Send failed: ${e.message}")
    }
}

If you don't need the reconciled message back, just call it and ignore the Deferred:

KindlySDK.sendMessage("Hi, I have a question about my order")

You can also observe completion without a coroutine via invokeOnCompletion:

KindlySDK.sendMessage("Hi").invokeOnCompletion { error ->
    if (error != null) println("Send failed: $error")
}

With per-call context

Attach key/value context to this message only — overrides any context previously staged via setNewContext(...):

KindlySDK.sendMessage(
    message = "Where is my order?",
    newContext = mapOf("orderId" to "12345", "tier" to "premium"),
)

Important: do not also display the message yourself

The SDK renders the bubble locally with a temporary id the moment you call sendMessage, then reconciles with the server-assigned id when the POST response returns. If you also add the message to a chat log you maintain, you'll see it twice.

The message also fires through the unified event stream:

import no.kindly.chatsdk.chat.models.KindlyEvent

lifecycleScope.launch {
    KindlySDK.events.collect { event ->
        if (event.detail is KindlyEvent.Detail.Message) {
            val msg = (event.detail as KindlyEvent.Detail.Message).newMessage
            println("${msg.sender}: ${msg.text}")
        }
    }
}

Errors

The Deferred completes exceptionally with a KindlySDKError in these cases:

Error Cause
KindlySDKError.SDKNotInitialized KindlySDK.start(...) was never called.
KindlySDKError.ChatNotConnected The chat is not currently connected. Observe KindlySDK.state for isConnected == true before calling, or call launchChat(context) first.
KindlySDKError.InvalidData The message text is empty or only whitespace.
KindlySDKError.ApiError / other Network or server errors are forwarded.

Behaviour summary

  • Trims whitespace; empty input completes exceptionally with KindlySDKError.InvalidData.
  • Optimistic local render — bubble appears immediately with a temp id.
  • POSTs to /message, reconciles temp id → server id on success.
  • Emits KindlyEvent.message for the user's message (consumers of KindlySDK.events see it like any other message).
  • Per-call newContext overrides global setNewContext(...) for this single call.
  • Works whether or not the chat UI is currently displayed — the message is delivered, and when the user opens the chat next, they see it in place.