Tutorial de Python

Convertir PDF a Markdown en Python

Un tutorial paso a paso usando la API REST: consigue una clave, crea un trabajo, consulta y descarga Markdown limpio, con un ejemplo completo y copiable y manejo de errores como es debido.

Respuesta breve

Una clave, tres llamadas

Para convertir un PDF a Markdown en Python llamas a una pequeña API REST con una clave bearer: POST /api/v2/jobs para crear un trabajo, GET /api/v2/jobs/{id} para consultar hasta que esté listo, y luego GET /api/v2/jobs/{id}/download para el Markdown. No hay nada que alojar ni una librería pesada que instalar, solo requests. El mismo ciclo de vida se expone como un MCP alojado para agentes, y la salida es el mismo Markdown que producen la extensión y la app web, así puedes prototipar en el navegador y luego automatizar con confianza.

Cómo

Configúralo en cuatro pasos

1

Consigue una clave de API

Inicia sesión con una cuenta de Google gratuita y crea una clave de API en tu cuenta; se muestra una sola vez. Envíala como Authorization: Bearer p2m_your_key.

2

Crea un trabajo

Haz POST de la URL del PDF (o los bytes subidos) a /api/v2/jobs. Obtienes un id de trabajo y un estado.

3

Consulta hasta ready

Haz GET /api/v2/jobs/{id} hasta que status sea ready o error.

4

Descarga el Markdown

Haz GET /api/v2/jobs/{id}/download para el texto Markdown. Respeta truncated y pages.

Ejemplo completo

El script de Python completo

Librería estándar más requests. Crea desde una URL de PDF, consulta y luego guarda el Markdown.

# pip install requests
import requests, time
API = "https://pdf2md.dev/api/v2"
H = {"Authorization": "Bearer p2m_your_key"}
# 1) crear un trabajo desde una URL de PDF
r = requests.post(f"{API}/jobs", headers={**H, "Idempotency-Key": "report-2026-01"},
                  json={"url": "https://example.com/report.pdf"})
r.raise_for_status()
jid = r.json()["job_id"]
# 2) consultar hasta ready o error
while True:
    job = requests.get(f"{API}/jobs/{jid}", headers=H).json()
    if job["status"] in ("ready", "error"):
        break
    time.sleep(3)
if job["status"] == "error":
    raise SystemExit(f"conversion failed: {job.get('error_code')} {job.get('error_message')}")
# 3) descargar el Markdown
md = requests.get(f"{API}/jobs/{jid}/download", headers=H).text
if job.get("truncated"):
    print("nota: resultado parcial (alcanzó el límite de tiempo)")
open("report.md", "w").write(md)

¿Subir un archivo local en vez de una URL? Haz POST de los bytes como multipart/form-data con un campo file al mismo endpoint. Las formas completas de la petición y la respuesta están en la especificación OpenAPI.

Para convertir muchos PDF, crea un trabajo por archivo y consúltalos en paralelo hasta tu límite de espacios (3 en el plan gratuito, más en los de pago). Mantén un Idempotency-Key distinto por archivo para que los reintentos nunca dupliquen trabajo, y espera ante un 429 usando la cabecera Retry-After.

Hazlo robusto

Errores, reintentos y webhooks

Lee el código de error

Un trabajo fallido devuelve status: error con un error_code legible por máquina (processing_timeout o conversion_failed) y un error_message seguro: ramifica según el código, no el texto.

Maneja truncated

Un documento largo puede volver ready con truncated=true. Comprueba la marca y divide el archivo o usa un presupuesto de pago mayor.

Idempotency-Key

Envía una cabecera Idempotency-Key para que un create reintentado devuelva el mismo trabajo en vez de duplicar trabajo.

Webhooks en vez de consulta

En planes de pago, registra un webhook o pasa callback_url y recibe un POST en ready/error en vez de consultar.

Respeta el 429

Ante un 429, espera los segundos de Retry-After antes de reintentar; no satures la cola.

Guarda las claves en el servidor

La clave es un secreto: guárdala en el servidor, envíala por TLS, y rótala o revócala cuando quieras.

Otros lenguajes

¿No usas Python? Las mismas tres llamadas

Es una API HTTPS simple, así que cualquier lenguaje funciona. El mismo crear / consultar / descargar en Node:

// Node 18+ (fetch global)
const API = "https://pdf2md.dev/api/v2";
const H = { Authorization: "Bearer p2m_your_key" };
let r = await fetch(`${API}/jobs`, { method: "POST",
  headers: { ...H, "Content-Type": "application/json" },
  body: JSON.stringify({ url: "https://example.com/report.pdf" }) });
let { job_id } = await r.json();
let job;
do { await new Promise(s => setTimeout(s, 3000));
     job = await (await fetch(`${API}/jobs/${job_id}`, { headers: H })).json();
} while (!["ready", "error"].includes(job.status));
const md = await (await fetch(`${API}/jobs/${job_id}/download`, { headers: H })).text();

¿Prefieres herramientas de agente o RAG?

El mismo ciclo de vida es un MCP alojado para ChatGPT, Claude y frameworks de agentes. Para ingesta y chunking, consulta la guía de RAG.

Preguntas frecuentes

Preguntas habituales

¿Cómo convierto un PDF a Markdown en Python?

Llama a la API REST con una clave bearer: haz POST del PDF a /api/v2/jobs, consulta GET /api/v2/jobs/{id} hasta ready, y luego haz GET de /download para el Markdown. El ejemplo completo con requests está arriba.

¿Necesito una clave de API?

Sí para la API. Una cuenta de Google gratuita te permite crear una clave y usar el MCP alojado. La extensión del navegador y la app web siguen siendo anónimas y no necesitan clave.

¿Cómo manejo los errores y tiempos de espera?

Un trabajo fallido devuelve status: error con un error_code legible por máquina (processing_timeout o conversion_failed) y un error_message seguro. Un documento largo puede volver ready con truncated=true; comprueba esa marca.

¿Puedo evitar la consulta?

En planes de pago, registra un webhook o pasa callback_url al crear el trabajo, y el servicio te hace POST en ready o error para que no consultes.

¿Funciona desde Node u otros lenguajes?

Sí. Es una API HTTPS simple, así que cualquier lenguaje funciona. Arriba hay un ejemplo corto en Node, y el contrato completo está en la especificación OpenAPI.

¿Cómo convierto un archivo local en vez de una URL?

Haz POST de los bytes del archivo como multipart/form-data con un campo file a /api/v2/jobs, en vez de un cuerpo JSON con url. Los pasos de consultar y descargar son idénticos.

¿Puedo convertir muchos PDF a la vez?

Crea un trabajo por archivo y consúltalos en paralelo hasta tu límite de espacios (3 en el plan gratuito, más en los de pago). Los planes de pago añaden un endpoint de creación por lotes y webhooks para que no consultes nada.

¿La salida es la misma que la de la extensión y la app web?

Sí. Cada superficie usa el mismo motor de conversión, así que la API devuelve el mismo Markdown que obtendrías en el navegador.

¿Es gratis?

El plan gratuito ofrece 3 espacios, archivos de 10 MB, un presupuesto de tiempo de 15 minutos y retención de 1 hora. Los planes de pago amplían cada límite y añaden webhooks y creación por lotes.