> ## 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

> Tích hợp Dodo Payments vào các ứng dụng Kotlin của bạn với coroutines hiện đại và tính năng an toàn với null

SDK Kotlin cung cấp quyền truy cập thuận tiện vào API REST Dodo Payments từ các ứng dụng viết bằng Kotlin. Nó có các giá trị có thể null, Sequence, các hàm suspend và các tính năng đặc trưng khác của Kotlin để sử dụng một cách dễ dàng.

## Cài đặt

### Gradle (Kotlin DSL)

Thêm phụ thuộc vào `build.gradle.kts`:

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

### Maven

Thêm phụ thuộc vào `pom.xml`:

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

<Tip>
  Luôn sử dụng phiên bản SDK mới nhất để truy cập các tính năng mới nhất của Dodo Payments. Kiểm tra [Maven Central](https://central.sonatype.com/artifact/com.dodopayments.api/dodo-payments-kotlin) để biết phiên bản mới nhất.
</Tip>

<Info>
  SDK yêu cầu Java 8 trở lên và tương thích với cả nền tảng JVM và Android.
</Info>

## Bắt đầu nhanh

Khởi tạo client và tạo một phiên giao dịch thanh toán:

```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>
  Luôn lưu trữ khóa API một cách an toàn bằng cách sử dụng biến môi trường hoặc cấu hình được mã hóa. Tuyệt đối không cam kết chúng vào hệ thống kiểm soát phiên bản.
</Warning>

## Tính năng chính

<CardGroup cols={2}>
  <Card title="Coroutines" icon="bolt">
    Hỗ trợ đầy đủ cho coroutine Kotlin cho các tác vụ bất đồng bộ
  </Card>

  <Card title="Null Safety" icon="shield-check">
    Tận dụng tính an toàn null của Kotlin để xử lý lỗi mạnh mẽ
  </Card>

  <Card title="Extension Functions" icon="code">
    Các phần mở rộng Kotlin đúng chuẩn để tăng cường tính năng
  </Card>

  <Card title="Data Classes" icon="layer-group">
    Các lớp dữ liệu kiểu an toàn với hỗ trợ sao chép và giải cấu trúc
  </Card>
</CardGroup>

## Cấu hình

### Từ biến môi trường

Khởi tạo từ biến môi trường hoặc thuộc tính hệ thống:

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

### Cấu hình thủ công

Cấu hình thủ công với tất cả các tùy chọn:

```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()
```

### Chế độ thử nghiệm

Cấu hình cho môi trường thử nghiệm/sandbox:

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

### Thời gian chờ và thử lại

Cấu hình toàn cục hoặc theo yêu cầu:

```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()
)
```

## Các hoạt động thông thường

### Tạo một phiên giao dịch thanh toán

Tạo một phiên giao dịch thanh toán:

```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()}")
```

### Tạo một sản phẩm

Tạo sản phẩm với cấu hình chi tiết:

```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()}")
```

### Kích hoạt khóa bản quyền

Kích hoạt các khóa bản quyền cho khách hàng:

```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}")
}
```

### Xử Lý Đăng Ký

Tạo và quản lý đăng ký định kỳ:

```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` yêu cầu ít nhất mã ISO hai chữ cái `country`. Dùng `AttachExistingCustomer` để đính kèm khách hàng hiện có, hoặc `NewCustomer` để tạo một khách hàng mới. `productPrice` thể hiện ở đơn vị nhỏ nhất của tiền tệ.
</Info>

## Thanh Toán Dựa Trên Sử Dụng

### Ghi Lại Sự Kiện Sử Dụng

Theo dõi sử dụng cho 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")
```

## Hoạt Động Bất Đồng Bộ

### Async Client

Sử dụng async client cho các hoạt động dựa trên 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()}")
}
```

## Xử Lý Lỗi

Xử lý lỗi với quản lý ngoại lệ của 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}")
}
```

### Xử Lý Lỗi Chức Năng

Sử dụng `Result` để xử lý lỗi chức năng:

```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>
  Sử dụng Kotlin's `runCatching` cho cách tiếp cận chức năng hơn đến xử lý lỗi với các kiểu Result.
</Tip>

## Tích Hợp Android

Sử dụng với ứng dụng 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)
            }
        }
    }
}
```

## Xác Thực Phản Hồi

Kích hoạt xác thực phản hồi:

```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()
```

## Tính Năng Nâng Cao

### Cấu Hình Proxy

Cấu hình cài đặt 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()
```

### Cấu Hình Tạm Thời

Thay đổi cấu hình client tạm thời:

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

## Tích Hợp Ktor

Tích hợp với ứng dụng 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))
            }
        }
    }
}
```

## Tài Nguyên

<CardGroup cols={2}>
  <Card title="GitHub Repository" icon="github" href="https://github.com/dodopayments/dodopayments-kotlin">
    Xem mã nguồn và đóng góp
  </Card>

  <Card title="API Reference" icon="book" href="/api-reference/introduction">
    Hoàn thành tài liệu API
  </Card>

  <Card title="Discord Community" icon="discord" href="https://discord.gg/bYqAp4ayYh">
    Nhận trợ giúp và kết nối với nhà phát triển
  </Card>

  <Card title="Report Issues" icon="bug" href="https://github.com/dodopayments/dodopayments-kotlin/issues">
    Báo cáo lỗi hoặc yêu cầu tính năng
  </Card>
</CardGroup>

## Hỗ Trợ

Cần trợ giúp với Kotlin SDK?

* **Discord**: Tham gia [máy chủ cộng đồng](https://discord.gg/bYqAp4ayYh) của chúng tôi để được hỗ trợ thời gian thực
* **Email**: Liên hệ với chúng tôi tại [support@dodopayments.com](mailto:support@dodopayments.com)
* **GitHub**: Mở một vấn đề trên [repository](https://github.com/dodopayments/dodopayments-kotlin)

## Đóng Góp

Chúng tôi hoan nghênh đóng góp! Kiểm tra [hướng dẫn đóng góp](https://github.com/dodopayments/dodopayments-kotlin/blob/main/CONTRIBUTING.md) để bắt đầu.
