Code Examples

Kotlin and Android with the CurrencyCore SDK

Use the official Kotlin SDK on Android, keep the key out of source, call convert from coroutines, and handle ClientException.


The official Kotlin SDK is generated from the OpenAPI contract and works on Android and the JVM. It configures bearer auth, returns typed models, and exposes convert, ratesByBase, history, and the analytics methods. Wrap its blocking calls in Dispatchers.IO.

The key belongs in local.properties during development and reaches code through BuildConfig. Add buildFeatures { buildConfig = true } for Android Gradle Plugin 8 and later, where build config generation is off by default. Do not commit local.properties.

// app/build.gradle.kts
import java.util.Properties

val local = Properties().apply {
    val file = rootProject.file("local.properties")
    if (file.exists()) file.inputStream().use { load(it) }
}

android {
    defaultConfig {
        minSdk = 26
        buildConfigField(
            "String",
            "CURRENCYCORE_API_KEY",
            "\"${local.getProperty("CURRENCYCORE_API_KEY") ?: ""}\"",
        )
    }
    buildFeatures { buildConfig = true }
}

dependencies {
    implementation("com.github.CurrencyCore:currencycore-kotlin:0.1.2")
}
import com.currencycore.sdk.CurrencyCore
import com.currencycore.sdk.infrastructure.ClientException
import com.currencycore.sdk.infrastructure.ServerException
import java.math.BigDecimal
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

class CurrencyCoreException(
    val status: Int,
    val code: String,
    override val message: String,
) : Exception(message)

class CurrencyRepository(
    private val apiKey: String = BuildConfig.CURRENCYCORE_API_KEY,
) {
    private val api = CurrencyCore.client(apiKey = apiKey)

    suspend fun convert(from: String, to: String, amount: Double) =
        withContext(Dispatchers.IO) {
            require(apiKey.isNotBlank()) {
                "Set CURRENCYCORE_API_KEY in local.properties"
            }

            try {
                api.convert(
                    from = from,
                    to = to,
                    amount = BigDecimal.valueOf(amount),
                )
            } catch (error: ClientException) {
                throw CurrencyCoreException(
                    error.statusCode,
                    "client_error",
                    error.message ?: "Request failed",
                )
            } catch (error: ServerException) {
                throw CurrencyCoreException(
                    error.statusCode,
                    "server_error",
                    error.message ?: "Server error",
                )
            }
        }
}

The SDK returns the API shape, with one entry per target:

{
  "from": "USD",
  "amount": 250,
  "date": "2026-11-10",
  "results": [{ "to": "JPY", "result": 38750.0, "rate": 155.0 }]
}

ClientException covers 4xx responses and ServerException covers 5xx. Both expose statusCode. Branch on the status: 400 is input, 401 is auth, 403 is a plan or history window, and 429 is a limit. On a 429, read Retry-After before retrying.

Production notes

  • A shipped APK exposes compiled constants, including BuildConfig fields. Obfuscation raises the effort but does not make the key secret. Use a backend proxy when the key must stay private.
  • Rates are central-bank reference rates polled hourly, and the underlying fixings are daily. They are reference values, not executable quotes.
  • A 403 can mean a plan gate or a date outside the Free 30-day history window.
  • Cache by date and base, and retry only 429 and 5xx with backoff and jitter.

Next steps