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

# Ejemplos

> Real Kotlin SDK use cases: Ktor, Android, Large PDFs, BYOS, RAG and ZIPs.

# Ejemplos

## Upload endpoint with Ktor

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

fun Route.convertRoutes(client: MarkpdfClient) {
    post("/upload") {
        val multipart = call.receiveMultipart()
        var bytes: ByteArray? = null
        var filename = "document.pdf"

        multipart.forEachPart { part ->
            if (part is PartData.FileItem) {
                bytes = part.streamProvider().readBytes()
                filename = part.originalFileName ?: filename
            }
            part.dispose()
        }

        val result = client.convertBytes(bytes!!, filename, ConvertOptions(mode = ConversionMode.FAST))

        val markdown = when (result) {
            is ConvertResult.Markdown -> result.markdown
            is ConvertResult.Json -> result.result.markdown
            is ConvertResult.Queued -> error("unexpected queued result")
        }

        call.respondText(markdown, contentType = io.ktor.http.ContentType.Text.Plain)
    }
}
```

## Convert a selected attachment on Android

```kotlin theme={null}
class ConvertViewModel(
    private val client: MarkpdfClient,
    private val contentResolver: ContentResolver,
) : ViewModel() {

    private val _state = MutableStateFlow<UiState>(UiState.Idle)
    val state: StateFlow<UiState> = _state

    fun convert(uri: Uri) {
        viewModelScope.launch {
            _state.value = UiState.Loading
            try {
                val bytes = contentResolver.openInputStream(uri)!!.use { it.readBytes() }
                val result = client.convertBytes(bytes, "document.pdf")
                _state.value = when (result) {
                    is ConvertResult.Markdown -> UiState.Success(result.markdown)
                    is ConvertResult.Json -> UiState.Success(result.result.markdown)
                    is ConvertResult.Queued -> UiState.Loading
                }
            } catch (e: MarkpdfException) {
                _state.value = UiState.Error(e.detail)
            }
        }
    }
}
```

## PDF large with page range

```kotlin theme={null}
val result = client.convertFromUrl(
    url = "https://bucket.example.com/manual-800-papages.pdf?sig=...",
    filename = "manual.pdf",
    options = ConvertOptions(pages = "120-145", mode = ConversionMode.FAST),
)
```

Combine it with [`pdfIndex`](/docs/sdks/kotlin/reference#pdfindex) to know what range to order without downloading the entire PDF client-side.

## BYOS: upload the result directly to your storage

```kotlin theme={null}
val result = client.convertFromUrl(
    url = pdfUrl,
    filename = "report.pdf",
    options = ConvertOptions(
        responseFormat = ResponseFormat.JSON,
        outputUrl = presignedPutUrl,      // pre-signed PUT to your bucket
        outputHeadUrl = presignedHeadUrl, // optional: detect cache hits
    ),
)
```

With `outputUrl`, the API uploads the Markdown directly to your storage and returns a lightweight JSON instead of the full body. See [Compression](/docs/concepts/compression) for `outputEncoding`.

## Pipeline RAG with `pdfIndex`

```kotlin theme={null}
val PDF = "https://bucket.example.com/informe-anual.pdf?sig=..."

// 1. Index without converting the entire document
val spine = client.pdfIndex(PDF)
val pageCount = spine["pageCount"]!!.jsonPrimitive.int
println("$pageCount pápages, ~${spine["estimatedTokensFull"]} full tokens")

// 2. Choose the section of interest
val sections = spine["sections"]!!.jsonArray
val target = sections.first { it.jsonObject["text"]!!.jsonPrimitive.content.contains("Resultados") }
val targetPage = target.jsonObject["page"]!!.jsonPrimitive.int

// 3. Bring Markdown only from that section
val result = client.convertFromUrl(
    url = PDF,
    filename = "informe-anual.pdf",
    options = ConvertOptions(pages = "$targetPage-$pageCount", mode = ConversionMode.FAST),
)
```

See [PDF Index for AI agents](/docs/concepts/pdf-index-for-ai-agents).

## Process a ZIP

```kotlin theme={null}
val zipBytes = File("documents.zip").readBytes()

val result = client.convertBytes(
    zipBytes, "documents.zip",
    options = ConvertOptions(
        inputFormat = InputFormat.ZIP,
        responseFormat = ResponseFormat.JSON,
    ),
)

if (result is ConvertResult.Json) {
    println(result.result.markdown) // Markdown concatenated from the documents inside the ZIP
}
```

<Warning>
  The file size and quantity limits within ZIP are in [Limits](/docs/concepts/limits). An out-of-range ZIP casts `MarkpdfException.PayloadTooLargeException`.
</Warning>
