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

# FastAPI

> Proxy seguro desde una API Python.

# FastAPI

```python theme={null}
import httpx
from fastapi import FastAPI, UploadFile
from fastapi.responses import Response

app = FastAPI()

FLASH_MD_URL = "https://api.markpdf.tech"
FLASH_MD_KEY = "TU_API_KEY"


@app.post("/ai/read-document")
async def read_document(file: UploadFile):
    content = await file.read()
    async with httpx.AsyncClient(timeout=300) as client:
        res = await client.post(
            f"{FLASH_MD_URL}/convert/raw",
            params={"filename": file.filename, "mode": "fast"},
            headers={
                "x-api-key": FLASH_MD_KEY,
                "content-type": file.content_type or "application/octet-stream",
            },
            content=content,
        )

    return Response(
        content=res.content,
        status_code=res.status_code,
        media_type=res.headers.get("content-type", "text/markdown"),
    )
```

Para produccion, valida tamano antes de leer todo en memoria.

## Manejo de 202 (auto-async)

Si la API devuelve `202`, pollea hasta obtener el resultado:

```python theme={null}
import httpx
import asyncio
from fastapi import FastAPI, UploadFile
from fastapi.responses import PlainTextResponse, JSONResponse

app = FastAPI()

FLASH_MD_URL = "https://api.markpdf.tech"
FLASH_MD_KEY = "TU_API_KEY"


async def poll_job(client: httpx.AsyncClient, job_id: str) -> str:
    while True:
        await asyncio.sleep(5)
        res = await client.get(
            f"{FLASH_MD_URL}/jobs/{job_id}",
            headers={"x-api-key": FLASH_MD_KEY},
        )
        data = res.json()
        if data["status"] == "completed":
            return data["body"]
        if data["status"] == "failed":
            raise Exception(data.get("error", "Job failed"))


@app.post("/ai/read-document")
async def read_document(file: UploadFile):
    content = await file.read()
    async with httpx.AsyncClient(timeout=300) as client:
        res = await client.post(
            f"{FLASH_MD_URL}/convert/raw",
            params={"filename": file.filename, "mode": "fast"},
            headers={
                "x-api-key": FLASH_MD_KEY,
                "content-type": file.content_type or "application/octet-stream",
            },
            content=content,
        )

        if res.status_code == 200:
            return PlainTextResponse(res.text, media_type="text/markdown")

        if res.status_code == 202:
            job = res.json()
            markdown = await poll_job(client, job["job_id"])
            return PlainTextResponse(markdown, media_type="text/markdown")

        return JSONResponse(
            content={"error": res.text}, status_code=res.status_code
        )
```
