Convertir PDF a Markdown en Node.js
Tres llamadas y listo: crea un trabajo, consulta hasta que esté listo y descarga Markdown limpio. El ejemplo de abajo es Node 18+ con el fetch global, sin dependencias, sin GPU, solo la API REST.
Crear, consultar, descargar
La API de PDF a Markdown es una pequeña API de trabajos. Haces POST de un PDF (una URL o un archivo subido) a /api/v2/jobs con tu clave de API, recibes un job_id, consultas /api/v2/jobs/{job_id} hasta que el estado sea ready, y luego descargas el Markdown de /api/v2/jobs/{job_id}/download. El OCR, las tablas y las fórmulas se manejan en el servidor, así que no hay nada que instalar en tu app de Node.
El ejemplo completo
Guárdalo como convert.mjs y ejecuta node convert.mjs. Cambia la clave y la URL del PDF.
// Node 18+ tiene un fetch global, así que no se necesitan dependencias.
const API = "https://pdf2md.dev/api/v2";
const H = { Authorization: "Bearer p2m_your_key" };
// 1) crear un trabajo desde una URL de PDF
const created = await fetch(`${API}/jobs`, {
method: "POST",
headers: { ...H, "Content-Type": "application/json", "Idempotency-Key": "report-2026-01" },
body: JSON.stringify({ url: "https://example.com/report.pdf" }),
});
if (!created.ok) throw new Error(`create failed: ${created.status}`);
const { job_id } = await created.json();
// 2) consultar hasta ready o error
let job;
do {
await new Promise((r) => setTimeout(r, 3000));
job = await (await fetch(`${API}/jobs/${job_id}`, { headers: H })).json();
} while (!["ready", "error"].includes(job.status));
if (job.status === "error") {
throw new Error(`conversion failed: ${job.error_code} ${job.error_message}`);
}
// 3) descargar el Markdown
const md = await (await fetch(`${API}/jobs/${job_id}/download`, { headers: H })).text();
if (job.truncated) console.warn("nota: resultado parcial (alcanzó el límite de tiempo)");
const fs = await import("node:fs/promises");
await fs.writeFile("report.md", md);
console.log("guardado report.md");
El Idempotency-Key hace seguro un create reintentado: si se envía la misma clave dos veces, recibes el mismo trabajo en vez de una conversión duplicada.
Qué hace cada llamada
Crea un trabajo
POST /api/v2/jobs con la clave de API como token bearer y un cuerpo JSON de { "url": "..." }. Para convertir un archivo local, envía multipart/form-data con un campo file. La respuesta da un job_id.
Consulta hasta ready
GET /api/v2/jobs/{job_id} devuelve un status de queued, processing, ready o error. Consulta cada pocos segundos hasta que se asiente.
Descarga el Markdown
GET /api/v2/jobs/{job_id}/download devuelve el texto Markdown. Escríbelo en un archivo .md, pásalo a un LLM, o guárdalo para un pipeline RAG.
Errores, reintentos y archivos grandes
Maneja los fallos
processing_timeout, conversion_failed); error_message es seguro de registrar.ready significa un resultado parcial que alcanzó el límite de tiempo en un documento muy largo.Escálalo
Para convertir muchos PDF, ejecuta las mismas tres llamadas por archivo con un pequeño límite de concurrencia, o cambia de la consulta a webhooks para que te avisen cuando cada trabajo esté listo. El contrato es idéntico en TypeScript; tipa la respuesta job y listo.
¿Prefieres Python o la shell? Consulta el tutorial de Python y la receta de cURL.
¿Construyes un agente o pipeline?
La misma conversión está disponible como un endpoint MCP alojado, así que un agente de IA puede convertir PDF sin configuración. Consulta el hub para desarrolladores para la referencia completa de la API y la especificación OpenAPI.
Preguntas habituales
¿Necesito una clave de API para convertir PDF en Node.js?
Sí, para la API REST pasas una clave de API como token bearer. También puedes convertir de forma anónima en el navegador o la app web sin clave; la clave de API es para el uso programático y automatizado.
¿Qué versión de Node.js necesito?
Node 18 o superior, que incluye un fetch global, así el ejemplo no necesita dependencias extra. En versiones anteriores, instala un polyfill de fetch o usa una librería de peticiones.
¿Cómo convierto un archivo PDF local en vez de una URL?
Envía un POST multipart/form-data a /api/v2/jobs con el campo file apuntando al PDF, usando FormData y un Blob, en vez de un cuerpo JSON con url. El resto del flujo (consultar, descargar) es igual.
¿Cómo manejo los errores y tiempos de espera?
Cuando status es error, lee error_code (por ejemplo processing_timeout o conversion_failed) y error_message. Un documento largo puede terminar ready con truncated en true, lo que significa un resultado parcial que alcanzó el límite de tiempo.
¿Puedo usar webhooks en vez de consulta?
Sí. La consulta es lo más sencillo para empezar, pero la API también admite webhooks para que te avisen cuando un trabajo esté listo en vez de consultar. Consulta el hub para desarrolladores para la configuración del webhook.