> ## 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 Python SDK use cases: uploads, large PDFs, BYOS, RAG and ZIPs.

# Ejemplos

## Convert a user upload (FastAPI)

```python theme={null}
from fastapi import FastAPI, UploadFile
import markpdf

app = FastAPI()
client = markpdf.AsyncClient(api_key="YOUR_API_KEY")

@app.post("/upload")
async def upload(file: UploadFile):
    content = await file.read()
    markdown = await client.convert_raw_bytes(
        content,
        filename=file.filename,
        mode="fast",
    )
    return {"markdown": markdown}
```

<Note>
  `convert_raw_bytes(data, filename=..., **params)` is the variant of `convert_file` for when you already have the content in memory (for example, a FastAPI `UploadFile`) and you don't want to write it to disk first.
</Note>

## PDF large with page range

```python theme={null}
markdown = client.convert_from_url(
    "https://bucket.example.com/manual-800-papages.pdf?sig=...",
    pages="120-145",
    mode="fast",
)
```

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

## BYOS: upload the result directly to your storage

```python theme={null}
result = client.convert_from_url(
    pdf_url,
    output_url=presigned_put_url,       # pre-signed PUT to your bucket
    output_head_url=presigned_head_url,  # optional: detect cache hits
)

print(result.cached)      # True si ya existía y no se reprocesó
print(result.output_url)  # URL final del Markdown subido
```

With `output_url`, API uploads the Markdown directly to your storage (S3, R2, Supabase Storage, GCS) and returns a lightweight JSON instead of the full body — useful for batch pipelines where you don't want the Markdown to go through your own backend. See [Compression](/docs/concepts/compression) for values ​​of `output_encoding`.

## Pipeline RAG with `/pdf/index`

```python theme={null}
import markpdf

client = markpdf.Client(api_key="YOUR_API_KEY")
PDF = "https://bucket.example.com/informe-anual.pdf?sig=..."

# 1. Index without converting the entire document
spine = client.pdf_index(PDF)
print(f"{spine.page_count} pápages, ~{spine.estimated_tokens_full} full tokens")

# 2. The agent decides which section he is interested in
target = next(s for s in spine.sections if "Resultados" in s.text)
following = next((s for s in spine.sections if s.page > target.page), None)
end_page = (following.page - 1) if following else spine.page_count

# 3. Bring Markdown only from that section
markdown = client.convert_from_url(PDF, pages=f"{target.page}-{end_page}", mode="fast")
```

This flow avoids paying the cost (tokens + latency) of converting 500 pages when the agent only needs 12. See [PDF Index for IA agents](/docs/concepts/pdf-index-for-ai-agents).

## Process a ZIP

```python theme={null}
result = client.convert_file(
    "documents.zip",
    input_format="zip",
    response_format="json",
)

print(result.markdown)  # Markdown concatenated from the supported documents inside the ZIP
```

<Warning>
  File size and quantity limits within ZIP are documented in [Limits](/docs/concepts/limits). An out-of-range ZIP returns `413`, which SDK converts to `MarkpdfPayloadTooLargeError`.
</Warning>

## Convert many files in parallel (async)

```python theme={null}
import asyncio
import markpdf

async def convert_all(paths: list[str]) -> list[str]:
    async with markpdf.AsyncClient(api_key="YOUR_API_KEY", max_retries=3) as client:
        tasks = [client.convert_file(p, mode="fast") for p in paths]
        return await asyncio.gather(*tasks, return_exceptions=True)

results = asyncio.run(convert_all(["a.pdf", "b.docx", "c.pdf"]))
for path, result in zip(["a.pdf", "b.docx", "c.pdf"], results):
    if isinstance(result, Exception):
        print(f"{path} falló: {result}")
    else:
        print(f"{path}: {len(result)} caracteres")
```

<Tip>
  `AsyncClient` reuses a single underlying HTTP/2 connection, so launching parallel conversions with `asyncio.gather` is more efficient than opening a synchronous `Client` per file.
</Tip>
