> For the complete documentation index, see [llms.txt](https://codemash.gitbook.io/codemash/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://codemash.gitbook.io/codemash/sdks/kotlin.md).

# Kotlin

Write and read records from Kotlin, Java and Android with the Norbix Kotlin SDK.

The Kotlin SDK is [`ai.norbix:norbix-kotlin`](https://central.sonatype.com/artifact/ai.norbix/norbix-kotlin) on Maven Central (source: [github.com/norbix-code/sdk-kotlin](https://github.com/norbix-code/sdk-kotlin)). It needs Java 17 or newer and works from Kotlin 2.0 projects. It has two clients: `NorbixApi` (package `ai.norbix.sdk.api` — your app's data) and `NorbixHub` (package `ai.norbix.sdk.hub` — configuration). Calls are blocking: on Android, call them off the main thread (for example in a coroutine on `Dispatchers.IO`).

This page was run on 2026-10-06 with `norbix-kotlin` **1.9.0**, Gradle 9.7 and Java 21. All the code below is one file, `src/main/kotlin/Main.kt`: put the blocks one after the other.

## Before you start

* A project with a `books` collection — `title` (text, required), `pages` (number, required), `in_stock` (yes / no), `genre`. Create it in Cloud as in step 3 of the [Quickstart](/codemash/get-started/managed-service/quickstart.md).
* A key and your project id in `NORBIX_API_KEY` and `NORBIX_PROJECT_ID` — see [Install a Norbix SDK](/codemash/sdks/install.md). The key needs a role that may write records, for example **Data Editor**.

## Install

`settings.gradle.kts`:

```kotlin
rootProject.name = "quickstart"
```

`build.gradle.kts`:

```kotlin
plugins {
    kotlin("jvm") version "2.2.21"
    application
}

repositories { mavenCentral() }

dependencies {
    implementation("ai.norbix:norbix-kotlin:1.9.0")
}

kotlin { jvmToolchain(21) }
application { mainClass.set("MainKt") }
```

## Create the client

```kotlin
import ai.norbix.sdk.api.NorbixApi
import ai.norbix.sdk.core.NorbixError

fun main() {
    // Reads NORBIX_API_KEY and NORBIX_PROJECT_ID from the environment.
    NorbixApi().use { api ->
```

To pass the values in code instead: `NorbixApi(apiKey = "nbsu_…", projectId = "pr_…")`.

{% hint style="danger" %}
An Android app that you hand out to people must not contain a service user key — anyone can read it from the app. Sign the user in (`api.login(...)`) and call Norbix with the user's token instead.
{% endhint %}

## Write a record

A record goes in as a JSON string in `document`. The answer is a `Map` with the new record's `id`.

```kotlin
        // Write: add one book to the `books` collection.
        val created = api.database.insertOne(mapOf(
            "collectionName" to "books",
            "document" to """{"title":"Dune","pages":412,"genre":"fiction"}""",
        )) as Map<*, *>
        println("Inserted ${created["id"]}")
```

## Read records

`find` returns one page of records in `list.items`. Add `filter`, `sort` or `projection` to the request map as in [Search parameters](/codemash/cloud/concepts/search-parameters.md). Numbers come back as `Double` (`412.0`), so convert them when you need an `Int`.

```kotlin
        // Read: find the books.
        val found = api.database.find(mapOf("collectionName" to "books", "pageSize" to 10)) as Map<*, *>
        val items = (found["list"] as Map<*, *>)["items"] as List<*>
        for (book in items.map { it as Map<*, *> }) {
            println("${book["title"]} — ${(book["pages"] as Number).toInt()} pages")
        }
```

## Handle errors

A failed call throws a `NorbixError` with the gateway's `code` and `message`, the HTTP `status`, and every error in `errors`. Here the schema says `pages` is required:

```kotlin
        // Error handling: the schema requires `pages`, so this insert fails.
        try {
            api.database.insertOne(mapOf(
                "collectionName" to "books",
                "document" to """{"title":"Untitled draft"}""",
            ))
        } catch (err: NorbixError) {
            println("Failed: ${err.code} — ${err.message}")
        }
    }
}
```

## Run it

```sh
gradle run
```

The output (the collection already had *The Hobbit*):

```
Inserted 6ac54bb3212c29912eaddd8f
Dune — 412 pages
The Hobbit — 310 pages
Failed: CM-ERRORS-DATABASE-030 — Field 'pages' is invalid: a value is required
```

## Next steps

* Every operation, with a tab per language: [SDK reference](/codemash/sdks/database.md).
* The same calls from the terminal: [CLI](/codemash/cli/cli.md).
