> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dodopayments.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Kotlin

> Integrasikan <Tip> ke dalam aplikasi Kotlin Anda dengan coroutines modern dan null-safety

Kotlin SDK menyediakan akses praktis ke REST API Dodo Payments dari aplikasi yang ditulis dalam Kotlin. SDK ini mendukung nilai nullable, Sequence, fungsi suspend, dan fitur khusus Kotlin lainnya untuk penggunaan yang ergonomis.

## Instalasi

### Gradle (Kotlin DSL)

Tambahkan dependensi ke `build.gradle.kts` Anda:

```kotlin build.gradle.kts theme={null}
implementation("com.dodopayments.api:dodo-payments-kotlin:1.97.1")
```

### Maven

Tambahkan dependensi ke `pom.xml` Anda:

```xml pom.xml theme={null}
<dependency>
  <groupId>com.dodopayments.api</groupId>
  <artifactId>dodo-payments-kotlin</artifactId>
  <version>1.97.1</version>
</dependency>
```

<Tip>
  Selalu gunakan versi SDK terbaru untuk mengakses fitur terbaru dari Dodo Payments. Periksa [Maven Central](https://central.sonatype.com/artifact/com.dodopayments.api/dodo-payments-kotlin) untuk mendapatkan versi terbaru.
</Tip>

<Info>
  SDK ini memerlukan Java 8 atau yang lebih baru dan kompatibel dengan platform JVM dan Android.
</Info>

## Mulai Cepat

Inisialisasi client dan buat checkout session:

```kotlin theme={null}
import com.dodopayments.api.client.DodoPaymentsClient
import com.dodopayments.api.client.okhttp.DodoPaymentsOkHttpClient
import com.dodopayments.api.models.checkoutsessions.CheckoutSessionCreateParams
import com.dodopayments.api.models.checkoutsessions.CheckoutSessionRequest
import com.dodopayments.api.models.checkoutsessions.ProductItemReq

// Configure using environment variables (DODO_PAYMENTS_API_KEY, DODO_PAYMENTS_BASE_URL)
// Or system properties (dodopayments.apiKey, dodopayments.baseUrl)
val client: DodoPaymentsClient = DodoPaymentsOkHttpClient.fromEnv()

val params: CheckoutSessionRequest = CheckoutSessionRequest.builder()
    .addProductCart(ProductItemReq.builder()
        .productId("product_id")
        .quantity(1)
        .build())
    .build()
    
val checkoutSessionResponse: CheckoutSessionResponse = client.checkoutSessions().create(params)
println(checkoutSessionResponse.sessionId())
```

<Warning>
  Selalu simpan API keys Anda dengan aman menggunakan environment variables atau konfigurasi terenkripsi. Jangan pernah memasukkannya ke version control.
</Warning>

## Fitur Utama

<CardGroup cols={2}>
  <Card title="Coroutines" icon="bolt">
    Dukungan penuh untuk Kotlin coroutines dalam operasi asinkron
  </Card>

  <Card title="Null Safety" icon="shield-check">
    Manfaatkan null safety Kotlin untuk penanganan error yang andal
  </Card>

  <Card title="Extension Functions" icon="code">
    Ekstensi Kotlin idiomatis untuk fungsionalitas yang lebih baik
  </Card>

  <Card title="Data Classes" icon="layer-group">
    Data classes yang type-safe dengan dukungan copy dan destructuring
  </Card>
</CardGroup>

## Konfigurasi

### Dari Environment Variables

Inisialisasi dari environment variables atau system properties:

```kotlin theme={null}
val client: DodoPaymentsClient = DodoPaymentsOkHttpClient.fromEnv()
```

### Konfigurasi Manual

Konfigurasikan secara manual dengan semua opsi:

```kotlin theme={null}
import java.time.Duration

val client = DodoPaymentsOkHttpClient.builder()
    .bearerToken("your_api_key_here")
    .baseUrl("https://live.dodopayments.com")
    .maxRetries(3)
    .timeout(Duration.ofSeconds(30))
    .build()
```

### Test Mode

Konfigurasikan untuk lingkungan test/sandbox:

```kotlin theme={null}
val testClient = DodoPaymentsOkHttpClient.builder()
    .fromEnv()
    .testMode()
    .build()
```

### Timeout dan Retry

Konfigurasikan secara global atau per-request:

```kotlin theme={null}
import com.dodopayments.api.core.RequestOptions

// Global configuration
val client = DodoPaymentsOkHttpClient.builder()
    .fromEnv()
    .timeout(Duration.ofSeconds(45))
    .maxRetries(3)
    .build()

// Per-request timeout override
val product = client.products().retrieve(
    "prod_123",
    RequestOptions.builder()
        .timeout(Duration.ofSeconds(10))
        .build()
)
```

## Operasi Umum

### Buat Checkout Session

Buat checkout session:

```kotlin theme={null}
val params = CheckoutSessionRequest.builder()
    .addProductCart(ProductItemReq.builder()
        .productId("prod_123")
        .quantity(1)
        .build())
    .returnUrl("https://yourdomain.com/return")
    .build()

val session = client.checkoutSessions().create(params)
println("Checkout URL: ${session.checkoutUrl()}")
```

### Buat Product

Buat product dengan konfigurasi terperinci:

```kotlin theme={null}
import com.dodopayments.api.models.products.Product
import com.dodopayments.api.models.products.ProductCreateParams
import com.dodopayments.api.models.misc.Currency
import com.dodopayments.api.models.misc.TaxCategory

val createParams = ProductCreateParams.builder()
    .name("Premium Subscription")
    .description("Monthly subscription with all features")
    .price(
        ProductCreateParams.RecurringPrice.builder()
            .currency(Currency.USD)
            .preTaxAmount(2999) // $29.99 in cents
            .paymentFrequencyInterval(ProductCreateParams.RecurringPrice.TimeInterval.MONTH)
            .paymentFrequencyCount(1)
            .build()
    )
    .taxCategory(TaxCategory.DIGITAL_PRODUCTS)
    .build()

val product: Product = client.products().create(createParams)
println("Created product ID: ${product.productId()}")
```

### Aktifkan License Key

Aktifkan license keys untuk customer:

```kotlin theme={null}
import com.dodopayments.api.models.licenses.LicenseActivateParams
import com.dodopayments.api.models.licenses.LicenseActivateResponse

val activateParams = LicenseActivateParams.builder()
    .licenseKey("XXXX-XXXX-XXXX-XXXX")
    .instanceName("user-laptop-01")
    .build()

try {
    val activationResult: LicenseActivateResponse = client.licenses()
        .activate(activateParams)

    println("License activated successfully")
    println("Instance ID: ${activationResult.instanceId()}")
    println("Expires at: ${activationResult.expiresAt()}")
} catch (e: UnprocessableEntityException) {
    println("License activation failed: ${e.message}")
}
```

### Tangani Subscription

Buat dan kelola recurring subscriptions:

```kotlin theme={null}
import com.dodopayments.api.models.payments.AttachExistingCustomer
import com.dodopayments.api.models.payments.BillingAddress
import com.dodopayments.api.models.payments.CountryCode
import com.dodopayments.api.models.subscriptions.SubscriptionChargeParams
import com.dodopayments.api.models.subscriptions.SubscriptionCreateParams

// Create a subscription
val subscriptionParams = SubscriptionCreateParams.builder()
    .billing(BillingAddress.builder()
        .city("San Francisco")
        .country(CountryCode.US)
        .state("CA")
        .street("1 Market St")
        .zipcode("94105")
        .build())
    .customer(AttachExistingCustomer.builder()
        .customerId("cus_123")
        .build())
    .productId("pdt_456")
    .quantity(1)
    .build()

val subscription = client.subscriptions().create(subscriptionParams)
println("Subscription ID: ${subscription.subscriptionId()}")

// Charge an on-demand subscription
// productPrice is in the lowest currency denomination (e.g., 2500 = $25.00 USD)
val chargeParams = SubscriptionChargeParams.builder()
    .subscriptionId(subscription.subscriptionId())
    .productPrice(2500)
    .build()

val chargeResponse = client.subscriptions().charge(chargeParams)
println("Payment ID: ${chargeResponse.paymentId()}")
```

<Info>
  `billing` memerlukan setidaknya kode `country` ISO dua huruf. Gunakan `AttachExistingCustomer` untuk melampirkan customer yang sudah ada, atau `NewCustomer` untuk membuat customer baru. `productPrice` dinyatakan dalam denominasi mata uang terendah.
</Info>

## Usage-Based Billing

### Catat Usage Events

Lacak penggunaan untuk meters:

```kotlin theme={null}
import com.dodopayments.api.models.usageevents.EventInput
import com.dodopayments.api.models.usageevents.UsageEventIngestParams

val usageParams = UsageEventIngestParams.builder()
    .addEvent(EventInput.builder()
        .customerId("cust_456")
        .eventId("event_123")
        .eventName("api_call")
        .build())
    .build()

client.usageEvents().ingest(usageParams)
println("Usage event recorded")
```

## Operasi Asinkron

### Async Client

Gunakan async client untuk operasi berbasis coroutine:

```kotlin theme={null}
import com.dodopayments.api.client.DodoPaymentsClientAsync
import com.dodopayments.api.client.okhttp.DodoPaymentsOkHttpClientAsync
import kotlinx.coroutines.runBlocking

val asyncClient: DodoPaymentsClientAsync = DodoPaymentsOkHttpClientAsync.fromEnv()

runBlocking {
    val customer = asyncClient.customers().retrieve("cust_123")
    println("Customer email: ${customer.email()}")
}
```

## Penanganan Error

Tangani error dengan exception handling Kotlin:

```kotlin theme={null}
import com.dodopayments.api.errors.*

try {
    val payment = client.payments().create(params)
    println("Success: ${payment.id()}")
} catch (e: AuthenticationException) {
    println("Authentication failed: ${e.message}")
} catch (e: InvalidRequestException) {
    println("Invalid request: ${e.message}")
    e.parameter?.let { println("Parameter: $it") }
} catch (e: RateLimitException) {
    println("Rate limit exceeded, retry after: ${e.retryAfter}")
} catch (e: DodoPaymentsServiceException) {
    println("API error: ${e.statusCode()} - ${e.message}")
}
```

### Penanganan Error Fungsional

Gunakan `Result` untuk penanganan error fungsional:

```kotlin theme={null}
fun safeCreatePayment(client: DodoPaymentsClient): Result<Payment> = runCatching {
    client.payments().create(params)
}

// Usage
safeCreatePayment(client)
    .onSuccess { payment -> println("Created: ${payment.id()}") }
    .onFailure { error -> println("Error: ${error.message}") }
```

<Tip>
  Gunakan `runCatching` Kotlin untuk pendekatan yang lebih fungsional terhadap penanganan error dengan tipe Result.
</Tip>

## Integrasi Android

Gunakan dengan aplikasi Android:

```kotlin theme={null}
import android.app.Application
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.dodopayments.api.client.DodoPaymentsClient
import kotlinx.coroutines.launch

class PaymentViewModel(application: Application) : ViewModel() {
    private val client = DodoPaymentsOkHttpClient.builder()
        .bearerToken(BuildConfig.DODO_API_KEY)
        .build()
    
    fun createCheckout(productId: String) {
        viewModelScope.launch {
            try {
                val session = client.async().checkoutSessions().create(params)
                // Open checkout URL in browser or WebView
                openUrl(session.checkoutUrl())
            } catch (e: Exception) {
                handleError(e)
            }
        }
    }
}
```

## Validasi Response

Aktifkan validasi response:

```kotlin theme={null}
import com.dodopayments.api.core.RequestOptions

// Per-request validation
val product = client.products().retrieve(
    "prod_123",
    RequestOptions.builder()
        .responseValidation(true)
        .build()
)

// Or validate explicitly
val validatedProduct = product.validate()
```

## Fitur Lanjutan

### Konfigurasi Proxy

Konfigurasikan pengaturan proxy:

```kotlin theme={null}
import java.net.InetSocketAddress
import java.net.Proxy

val client = DodoPaymentsOkHttpClient.builder()
    .fromEnv()
    .proxy(
        Proxy(
            Proxy.Type.HTTP,
            InetSocketAddress("proxy.example.com", 8080)
        )
    )
    .build()
```

### Konfigurasi Sementara

Ubah konfigurasi client untuk sementara:

```kotlin theme={null}
val customClient = client.withOptions {
    it.baseUrl("https://example.com")
    it.maxRetries(5)
}
```

## Integrasi Ktor

Integrasikan dengan aplikasi server Ktor:

```kotlin theme={null}
import io.ktor.server.application.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.routing.*

fun Application.configureRouting() {
    val client = DodoPaymentsOkHttpClient.builder()
        .bearerToken(environment.config.property("dodo.apiKey").getString())
        .build()
    
    routing {
        post("/create-checkout") {
            try {
                val request = call.receive<CheckoutRequest>()
                val session = client.checkoutSessions().create(params)
                call.respond(mapOf("checkout_url" to session.checkoutUrl()))
            } catch (e: DodoPaymentsServiceException) {
                call.respond(HttpStatusCode.BadRequest, mapOf("error" to e.message))
            }
        }
    }
}
```

## Resources

<CardGroup cols={2}>
  <Card title="GitHub Repository" icon="github" href="https://github.com/dodopayments/dodopayments-kotlin">
    Lihat source code dan berkontribusi
  </Card>

  <Card title="API Reference" icon="book" href="/api-reference/introduction">
    Dokumentasi API lengkap
  </Card>

  <Card title="Discord Community" icon="discord" href="https://discord.gg/bYqAp4ayYh">
    Dapatkan bantuan dan terhubung dengan developer
  </Card>

  <Card title="Report Issues" icon="bug" href="https://github.com/dodopayments/dodopayments-kotlin/issues">
    Laporkan bug atau ajukan fitur
  </Card>
</CardGroup>

## Dukungan

Butuh bantuan dengan Kotlin SDK?

* **Discord**: Bergabunglah dengan [server komunitas kami](https://discord.gg/bYqAp4ayYh) untuk mendapatkan dukungan secara real-time
* **Email**: Hubungi kami di [support@dodopayments.com](mailto:support@dodopayments.com)
* **GitHub**: Buka issue di [repository](https://github.com/dodopayments/dodopayments-kotlin)

## Berkontribusi

Kami menyambut kontribusi! Lihat [panduan kontribusi](https://github.com/dodopayments/dodopayments-kotlin/blob/main/CONTRIBUTING.md) untuk memulai.
