# Send Your First Message (/sdks/kotlin/tutorials/first-message)



This is your first hands-on lesson with the Kotlin SDK: create a client, send an event, and receive it. Make sure you have the SDK installed (see the [Kotlin SDK overview](/sdks/kotlin)).

## Create a Client [#create-a-client]

The Kotlin SDK provides pattern-specific clients created via DSL builders:

```kotlin title="Connect.kt"
import io.kubemq.sdk.client.KubeMQClient
import kotlinx.coroutines.runBlocking

fun main() = runBlocking {
    val client = KubeMQClient.pubSub {
        address = "localhost:50000"
        clientId = "my-service"
    }

    val info = client.ping()
    println("Connected to ${info.host} v${info.version}")
    client.close()
}
```

| Builder                   | Use For                 |
| ------------------------- | ----------------------- |
| `KubeMQClient.pubSub { }` | Events, Events Store    |
| `KubeMQClient.queues { }` | Queues                  |
| `KubeMQClient.cq { }`     | Commands, Queries (RPC) |

## Send Your First Event [#send-your-first-event]

```kotlin title="SendEvent.kt"
import io.kubemq.sdk.client.KubeMQClient
import io.kubemq.sdk.pubsub.eventMessage
import kotlinx.coroutines.runBlocking

fun main() = runBlocking {
    val client = KubeMQClient.pubSub {
        address = "localhost:50000"
        clientId = "events-sender"
    }

    client.use {
        client.publishEvent(eventMessage {
            channel = "notifications"
            body = "hello kubemq".toByteArray()
            metadata = "greeting"
        })
        println("Event sent")
    }
}
```

## Receive Events [#receive-events]

The Kotlin SDK uses `Flow` for subscriptions, providing natural integration with coroutines:

```kotlin title="ReceiveEvents.kt"
import io.kubemq.sdk.client.KubeMQClient
import kotlinx.coroutines.flow.take
import kotlinx.coroutines.runBlocking

fun main() = runBlocking {
    val client = KubeMQClient.pubSub {
        address = "localhost:50000"
        clientId = "events-receiver"
    }

    client.use {
        client.subscribeToEvents {
            channel = "notifications"
        }.take(10).collect { event ->
            println("Received: ${String(event.body)}")
        }
    }
}
```

## Configuration Options [#configuration-options]

| Parameter             | Type       | Default           | Description                           |
| --------------------- | ---------- | ----------------- | ------------------------------------- |
| `address`             | `String`   | `localhost:50000` | KubeMQ server gRPC address            |
| `clientId`            | `String`   | Auto-generated    | Unique client identifier              |
| `authToken`           | `String`   | `""`              | JWT authentication token              |
| `logLevel`            | `LogLevel` | `INFO`            | Logging verbosity                     |
| `keepAlive`           | `Boolean`  | `true`            | Enable gRPC keep-alive                |
| `pingIntervalSeconds` | `Int`      | `10`              | Keep-alive ping interval              |
| `pingTimeoutSeconds`  | `Int`      | `5`               | Keep-alive ping timeout               |
| `maxReceiveSize`      | `Int`      | `104857600`       | Max inbound message size (100 MB)     |
| `reconnection { }`    | DSL block  | Enabled           | Auto-reconnection with backoff config |
| `tls { }`             | DSL block  | Disabled          | TLS/mTLS configuration                |

## Error Handling [#error-handling]

The SDK uses a sealed exception hierarchy rooted at `KubeMQException`:

```kotlin title="ErrorHandling.kt"
import io.kubemq.sdk.exception.KubeMQException

try {
    client.publishEvent(message)
} catch (e: KubeMQException) {
    when (e) {
        is KubeMQException.Connection ->
            println("Connection failed (retryable): ${e.message}")
        is KubeMQException.Authentication ->
            println("Auth failed: ${e.message}")
        is KubeMQException.Validation ->
            println("Invalid request: ${e.message}")
        is KubeMQException.Timeout ->
            println("Timeout (retryable): ${e.message}")
        else ->
            println("SDK error: ${e.message}")
    }
}
```

| Exception                        | Retryable | When                     |
| -------------------------------- | --------- | ------------------------ |
| `KubeMQException.Connection`     | Yes       | Server unavailable       |
| `KubeMQException.Timeout`        | Yes       | Deadline exceeded        |
| `KubeMQException.Authentication` | No        | Invalid credentials      |
| `KubeMQException.Authorization`  | No        | Insufficient permissions |
| `KubeMQException.Validation`     | No        | Invalid parameters       |

## Next Steps [#next-steps]

* [Kotlin SDK Reference](/sdks/kotlin/reference) -- full API documentation
* [Kotlin SDK Examples](/sdks/kotlin/how-to) -- complete examples for all patterns
* [GitHub Repository](https://github.com/kubemq-io/kubemq-kotlin) -- source code and issues
