notion-sdk-kmp
1.1.11indexedDemonstrates publishing workflow and a simple Fibonacci generator, with GPG key setup, namespace registration, Gradle publishing plugin configuration, and GitHub Actions CI for Maven Central publication.
Demonstrates publishing workflow and a simple Fibonacci generator, with GPG key setup, namespace registration, Gradle publishing plugin configuration, and GitHub Actions CI for Maven Central publication.
A Kotlin Multiplatform SDK for the Notion API, published on Maven Central. Write your Notion integration once and run it on Android, iOS, JVM, JavaScript, macOS, and Linux — no code duplication, no platform-specific workarounds.
The library is structured in three layers, all written in commonMain:
NotionClient
├── Repository (public API — suspend functions, clean domain types)
│ └── Service (HTTP communication via Ktor)
│ └── NotionHttp (auth injection, base URL, headers)
└── DI modules (Koin — optional, wired automatically)
Add the dependency to your build.gradle.kts:
commonMain.dependencies {
implementation("io.github.tungnk123:notion-sdk-kmp:1.1.11")
}
val client = NotionClientFactory.fromToken(token = "secret_...")
// Retrieve a page
val page = client.pageRepository.retrieve(pageId)
// Query a database
val results = client.databaseRepository.query(
id = databaseId,
req = QueryDatabaseRequest(/* filters, sorts … */)
)
// Full-text search
val pages = client.searchRepository.searchPages(query = "Books")
Useful when the token is stored in your own secure storage or refreshed dynamically:
class MyTokenProvider : TokenProvider {
override fun token(): String = MySecureStorage.read("notion_token")
}
val client = NotionClientFactory.fromTokenProvider(MyTokenProvider())
val repo = AuthRepository(
service = AuthServiceImpl(httpClient),
clientId = "...",
clientSecret = "...",
storage = InMemoryTokenStorage()
)
// 1. Redirect the user
val authorizeUrl = repo.authorizeUrl(redirectUri, state, ownerWorkspace = false)
// 2. Handle the callback
val token = repo.exchangeCodeForTokenAndSaveToken(code, redirectUri)
// 3. Build the client
val client = NotionClientFactory.fromAuthRepository(repo)
val manager = NotionSessionManager(authFactory, tokenStore)
// Observe auth state reactively
manager.state.collect { state ->
when (state) {
is SessionState.SignedOut -> showLoginScreen()
is SessionState.Authorizing -> openBrowser(state.intent.url)
is SessionState.Authorized -> showHome(state.session)
}
}
// Switch between workspaces
manager.switchWorkspace(workspaceId)
// Sign out
manager.disconnectWorkspace(workspaceId)
The project has two test scopes:
commonTest — unit tests using ktor-client-mock, covering all repositories without hitting the real API.jvmTest live tests — integration tests (PageLiveTest, , , …) that run against a real Notion workspace when and related IDs are set.# Unit tests (all platforms)
./gradlew allTests
# JVM live tests (requires credentials in local.properties)
./gradlew jvmTest
Releases are published to Maven Central automatically via GitHub Actions when a GitHub release is created:
.github/workflows/publish.yml
The workflow signs all artifacts with GPG and uploads via the vanniktech/gradle-maven-publish-plugin. Credentials are stored as GitHub repository secrets.
notion-sdk-kmp/
├── library/
│ └── src/
│ ├── commonMain/ # All SDK logic — repositories, services, models, auth
│ ├── androidMain/ # Ktor Android engine
│ ├── jvmMain/ # Ktor CIO engine
│ ├── jsMain/ # Ktor JS engine
│ ├── appleMain/ # Ktor Darwin engine (shared by iOS + macOS)
│ ├── commonTest/ # Mock-based unit tests
│ └── jvmTest/ # Live integration tests
└── sample/
├── NotionClientFromToken.kt # Basic API token usage
├── NotionClientFromProvider.kt # Custom TokenProvider
└── NotionClientFromOAuth.kt # Full OAuth flow with embedded server
| Platform | Target |
|---|
| Android | androidTarget |
| iOS | iosX64, iosArm64, iosSimulatorArm64 |
| JVM (Desktop / Server) | jvm |
| JavaScript (Browser) | js |
| macOS | macosX64, macosArm64 |
| Linux | linuxX64 |
PageRepository, BlockRepository, …).@Serializable DTOs.Authorization header via a pluggable TokenProvider, keeping auth decoupled from transport.CIO on JVM, Android on Android, Darwin on Apple, Js on JS), so the common code never touches platform internals.| Resource | Operations |
|---|
| Page | create, retrieve, update, retrievePropertyItem |
| Block | retrieve, update, delete, listChildren, appendChildren, getAllChildren, getAllChildrenRecursive, updateTodoChecked |
| Database | create, retrieve, update, query |
| DataSource | create, retrieve, update, query |
| User | me, retrieve, list |
| Search | search, searchPages, searchDatabases |
| Library | Role |
|---|
| Ktor Client | HTTP with per-platform engines (CIO / OkHttp / Darwin / Js) |
| kotlinx.serialization | JSON serialization in commonMain |
| kotlinx.coroutines | Structured concurrency, StateFlow for session state |
| kotlinx.datetime | Multiplatform date/time parsing |
| Koin | Dependency injection wiring |
DatabaseLiveTestBlockLiveTestNOTION_TOKENSurfaced from shared tags and platforms — no rankings paid for.