PDF to Markdown

Servidor MCP alojado que convierte PDFs en Markdown limpio y listo para LLM, con tablas, fórmulas (LaTeX) y OCR. Motores propios (MinerU + Docling), no un envoltorio de LLM.

Documentación

Dos superficies, un mismo motor

Elige la integración que mejor se adapte. Ambas utilizan el mismo motor de conversión y respetan las mismas ranuras, límites y retención.

API REST

Endpoints HTTPS con una clave de API tipo bearer. DTOs estables, errores predecibles, creación idempotente.

Consulta el ciclo de vida

MCP alojado

Un endpoint de Model Context Protocol gestionado que expone la conversión como herramientas de agente: una capa delgada sobre la misma API.

Conectar MCP

Acciones de GPT personalizadas

Importa una especificación OpenAPI reducida en un ChatGPT Custom GPT para que pueda convertir PDFs como una herramienta integrada.

Configurar la acción

Claves de API bearer sobre HTTPS

La API y MCP utilizan claves de API bearer, distintas de la ruta firmada por dispositivo que usa la extensión de Chrome. Se requiere una cuenta gratuita de Google para generar claves.

Obtener una clave

  • Inicia sesión con Google (cuenta gratuita).
  • Genera una clave de API en tu cuenta; se muestra una sola vez.
  • Envíala como Authorization: Bearer p2m_… en cada solicitud.
  • Las claves son secretos: guárdalas en el servidor, rota y revoca en cualquier momento.

Valores predeterminados honestos

Claves, no contraseñas. La extensión permanece anónima y firmada por dispositivo; las claves de API/MCP son una credencial separada vinculada a la cuenta.

Solo HTTPS. Envía siempre las claves a través de TLS; nunca incrustes una clave en código de cliente distribuido a los usuarios.

Creación idempotente. Un Idempotency-Key opcional en la creación te permite reintentar de forma segura sin trabajos duplicados.

Ámbitos. Cada clave de API lleva ámbitos: jobs:create, jobs:read, jobs:download, jobs:delete (los predeterminados), además de settings:read / settings:write. Emite claves con privilegios mínimos; tanto la API REST como las herramientas MCP aplican los ámbitos de la clave.

Crear un trabajo, esperar, obtener Markdown, limpiar la ranura

Un ciclo de vida predecible, dos formas de manejarlo: llama a la API REST desde tu propio código o usa las herramientas equivalentes de MCP alojado. Nunca reclames un resultado antes de status=ready.

API REST MCP alojado

1

Crear el trabajo

Envía por POST una URL de PDF o sube bytes. Obtén un id de trabajo y una ranura. Idempotency-Key se respeta pero es opcional.

POST /api/v2/jobsmcp · pdf_to_markdown_create_job_from_url

2

Comprobar el estado

Consulta el trabajo hasta que esté en ready o error, o registra un webhook firmado en los planes de pago en lugar de consultar.

GET /api/v2/jobs/{id}mcp · pdf_to_markdown_get_job

3

Obtener el Markdown

Descarga el resultado una vez que esté listo. Lee truncated y pages para saber si un documento largo se devolvió parcialmente.

GET /api/v2/jobs/{id}/downloadmcp · pdf_to_markdown_get_markdown

4

Eliminar / limpiar la ranura

Libera una ranura cuando termines. Eliminar trabajos en cola o en proceso es destructivo: confírmalo en los clientes orientados al usuario.

DELETE /api/v2/jobs/{id}mcp · pdf_to_markdown_delete_job

# 1. create a job from a PDF URL
curl -X POST https://pdf2md.dev/api/v2/jobs \
  -H "Authorization: Bearer p2m_…" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/report.pdf"}'
# → { "job_id": "job_9f3c…", "status": "queued" }

# 2. poll status
curl https://pdf2md.dev/api/v2/jobs/job_9f3c… \
  -H "Authorization: Bearer p2m_…"
# → { "status": "ready", "pages": 24, "truncated": false }

# 3. fetch the Markdown
curl https://pdf2md.dev/api/v2/jobs/job_9f3c…/download \
  -H "Authorization: Bearer p2m_…"

# 4. free the slot
curl -X DELETE https://pdf2md.dev/api/v2/jobs/job_9f3c… \
  -H "Authorization: Bearer p2m_…"

Errores. Las respuestas usan formas estables y códigos HTTP predecibles (400 entrada incorrecta, 401 autenticación, 404 trabajo desconocido, 409 sin ranura libre / slots_full, 413 demasiado grande, 429 límite de velocidad superado). El esquema completo está en la especificación OpenAPI.

Más endpoints de trabajos

Crear desde archivo (multipart) POST /api/v2/jobs

Listar tus trabajos GET /api/v2/jobs

Creación por lotes (de pago) POST /api/v2/jobs/batch

La creación acepta un url JSON o un file multipart, además de file_name, external_id, tags y callback_url / callback_secret opcionales para un webhook por trabajo. La creación por lotes es de todo o nada y debe caber en tus ranuras libres.

El objeto de trabajo

job_id cadena

status queued · processing · ready · error

pages · output_size entero

truncated booleano

error_code · error_message motivo (cuando hay error)

download_url cadena (cuando está listo)

external_id · tags tus metadatos

slot_usage · tier contexto de cuota

Cuenta y uso. Consulta tu nivel, límites y uso en tiempo de ejecución con GET /api/v2/me, /api/v2/limits y /api/v2/usage; gestiona claves en /api/v2/api-keys y webhooks en /api/v2/webhooks.

Convertir un PDF a Markdown en Python

Las mismas cuatro llamadas desde cualquier lenguaje. Aquí se muestra con requests. Para un tutorial completo paso a paso con manejo de errores, consulta el tutorial de Python.

# pip install requests
import time, requests

API = "https://pdf2md.dev/api/v2"
H = {"Authorization": "Bearer p2m_…"}

# 1. create a job from a PDF URL (or post a file with files={"file": ...})
job = requests.post(f"{API}/jobs", headers=H,
    json={"url": "https://example.com/report.pdf"}).json()
jid = job["job_id"]

# 2. poll until ready (or register a webhook instead)
while True:
    j = requests.get(f"{API}/jobs/{jid}", headers=H).json()
    if j["status"] in ("ready", "error"):
        break
    time.sleep(3)

# 3. download the Markdown
md = requests.get(f"{API}/jobs/{jid}/download", headers=H).text
print(md)

Más recetas: subida de archivos y Node

Crear desde un archivo local (curl)

# multipart upload of a local PDF
curl -X POST https://pdf2md.dev/api/v2/jobs \
  -H "Authorization: Bearer p2m_…" \
  -F "[email protected]" \
  -F "file_name=document.pdf"

Node 18+ (fetch global)

// create from URL, poll, download
const API = "https://pdf2md.dev/api/v2";
const H = { Authorization: "Bearer p2m_…" };

let job = await (await fetch(\`${API}/jobs\`, {
  method: "POST",
  headers: { ...H, "Content-Type": "application/json" },
  body: JSON.stringify({ url: "https://example.com/report.pdf" })
})).json();

while (job.status === "queued" || job.status === "processing") {
  await new Promise(s => setTimeout(s, 2000));
  job = await (await fetch(\`${API}/jobs/${job.job_id}\`, { headers: H })).json();
}

if (job.status === "ready") {
  const md = await (await fetch(\`${API}/jobs/${job.job_id}/download\`, { headers: H })).text();
  console.log(md);
}

La verificación de firma de webhooks está en la sección Webhooks; la configuración del cliente MCP está en la sección MCP. Esquema completo: OpenAPI.

Conversión como herramientas de agente

Conecta un agente compatible a nuestro endpoint MCP gestionado. Las herramientas son una capa delgada sobre la API REST, por lo que cada llamada respeta las mismas ranuras, límites y retención.

1

Apuntar el agente al endpoint

JSON-RPC 2.0 sobre Streamable HTTP con tu clave de API como token bearer. No hay servidor local que ejecutar. Métodos: initialize, tools/list, tools/call, ping.

POST https://pdf2md.dev/api/v2/mcp

2

Llamar a las herramientas

El mismo ciclo de vida más límites, expuesto como siete herramientas. Cada una respeta los ámbitos de la clave; las respuestas de tools/call incluyen slot_usage y tier.

create_job_from_url · create_job_from_upload (jobs:create) list_jobs · get_job (jobs:read) get_markdown (jobs:download) · delete_job (jobs:delete) get_limits

3

Respetar las reglas

Espera a ready antes de usar la salida; confirma antes de eliminar trabajos en cola/en proceso; maneja truncated y 429 Retry-After. (Los nombres de las herramientas llevan el prefijo pdf_to_markdown_.)

// MCP client config (hosted, no local process)
{
  "mcpServers": {
    "pdf2md": {
      "url": "https://pdf2md.dev/api/v2/mcp",
      "headers": {
        "Authorization": "Bearer p2m_…"
      }
    }
  }
}

Importar la especificación, obtener una herramienta integrada

Publicamos dos especificaciones: la OpenAPI completa para desarrolladores y una especificación de acción reducida con el subconjunto seguro y mínimo para clientes de IA y ChatGPT Custom GPT Actions.

OpenAPI completa

El contrato completo: cada endpoint, parámetro, DTO y error. Genera clientes o explórala en tus herramientas.

Abrir la especificación completa

Especificación reducida para Custom GPT

Un subconjunto mínimo de acciones (crear, estado, obtener) para ChatGPT Custom GPT Actions. Importa la URL, configura tu clave de API como autenticación y tu GPT convertirá PDFs de forma nativa.

Abrir la especificación reducida

La especificación reducida es una conveniencia para clientes de IA, no un límite de seguridad: se aplican la misma autenticación, ámbitos y límites que en la API completa.

Límites por nivel, aplicados por igual a API y MCP

Los límites provienen de tu nivel y se aplican de forma idéntica en todas las superficies. Los valores en vivo están en la página de precios.

Nivel gratuito (con cuenta)

Ranuras activas (profundidad de cola) 3

Tamaño máximo de PDF 10 MB

Presupuesto de tiempo por documento 15 min

Retención de resultados listos 1 hora

Los niveles de pago aumentan ranuras, tamaño de archivo, presupuesto de tiempo, retención y límites de velocidad, y añaden webhooks y creación por lotes. Comparar planes →

Límites de velocidad y contrapresión

Límites de velocidad por nivel. Las solicitudes están limitadas por clave; si las superas, obtienes 429 con una cabecera Retry-After: retrocede y reintenta.

Presión de ranuras. Si todas las ranuras están ocupadas, la creación devuelve 409. Libera una ranura con delete o espera a que un trabajo termine.

Prioridad en pago. Los trabajos de pago se ejecutan con mayor prioridad de cola en un grupo de conversión de pago dedicado, por lo que no esperan detrás del backlog gratuito.

Recibe notificaciones en lugar de consultar

En los niveles de pago, registra un webhook firmado (o pasa un callback_url por trabajo) y te enviamos un POST en cada evento terminal notable: job.ready, job.error, job.truncated y job.deleted. El evento es una notificación, no una entrega: no contiene contenido del documento, así que obtén el Markdown a través de la API después de recibirlo.

1

2

Recibir el evento

Enviamos JSON con las cabeceras X-P2M-Event, X-P2M-Timestamp, X-P2M-Delivery y X-P2M-Signature.

3

Verificar y luego actuar

Recalcula la firma, confirma con 2xx y sé idempotente (las entregas pueden reintentarse con retroceso). Luego descarga el Markdown.

# delivery → your endpoint
X-P2M-Event: job.ready
X-P2M-Timestamp: 1718900000
X-P2M-Signature: sha256=9a8b7c…

{
  "event": "job.ready",
  "job": {
    "job_id": "job_9f3c…",
    "status": "ready",
    "pages": 24, "truncated": false,
    "download_url": "/api/v2/jobs/job_9f3c…/download"
  }
}

# verify (Python): signature = sha256= + hex(HMAC(secret, "ts.rawbody"))
import hmac, hashlib
def verify(secret, ts, raw_body, sig):
    expected = "sha256=" + hmac.new(
        secret.encode(), f"{ts}.".encode() + raw_body,
        hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, sig)

Instrucciones portables para agentes

Incorpora estas reglas en el prompt del sistema de un agente para que maneje las herramientas correctamente y nunca invente resultados.

Esperar a ready

Nunca reclames ni resumas un resultado antes de status=ready. Mientras esté en queued o processing, sigue consultando o espera el webhook.

Confirmar eliminaciones

Eliminar un trabajo en queued o processing es destructivo. Pregunta al usuario antes de llamar a pdf_to_markdown_delete_job en un trabajo no finalizado.

Manejar la truncación

Si truncated=true, informa al usuario de que el documento se devolvió parcialmente hasta el presupuesto de tiempo del nivel y ofrece un nivel superior o dividir el archivo.

Respetar 429

En 429, espera Retry-After segundos antes de reintentar. No satures la cola.

Limpiar ranuras

Elimina los trabajos finalizados que ya no necesites para no agotar tus ranuras.

Leer el descubrimiento

Empieza por /llms.txt y la especificación OpenAPI en lugar de adivinar endpoints a partir del texto.