JavaScript PDF to Markdown

Validated JavaScript examples for URL, Base64 and raw PDF conversion.

Node.js 18+; save each example as convert.mjs. Set PDFTOMARKDOWN_API_KEY and save a unique PDFTOMARKDOWN_IDEMPOTENCY_KEY before submission. Reuse that identity only with identical document bytes and options.

Allow up to 11 minutes for a synchronous request. Stopping the client or reaching its timeout stops waiting; processing and charging may continue. Measure elapsed time locally; optional provider timing headers do not measure total request time.

JavaScript URL

javascriptUrl
import { readFileSync } from "node:fs";

const key = process.env.PDFTOMARKDOWN_API_KEY;
const identity = process.env.PDFTOMARKDOWN_IDEMPOTENCY_KEY;
try {
  if (!key || !identity) throw new Error("Set PDFTOMARKDOWN_API_KEY and a saved PDFTOMARKDOWN_IDEMPOTENCY_KEY");
  const body = JSON.stringify({ input: { pdf_url: "https://pdftomarkdown.dev/samples/invoice.pdf" } });
  // One transport retry; retain exactly the same bytes, options and identity.
  const signal = AbortSignal.timeout(660_000);
  let response;
  for (let attempt = 0; attempt < 2; attempt++) {
    try {
      response = await fetch("https://pdftomarkdown.dev/v1/convert", {
        method: "POST", signal,
        headers: { Authorization: `Bearer ${key}`, "Idempotency-Key": identity,
          "Content-Type": "application/json" },
        body,
      });
      break;
    } catch (error) {
      if (attempt === 1 || signal.aborted) throw error;
    }
  }
  if (!response || response.status !== 200) throw new Error(`HTTP ${response?.status}; keep the identity for recovery`);
  const result = await response.json();
  if (result?.complete !== true || typeof result.markdown !== "string"
      || !Number.isSafeInteger(result.pages) || result.pages < 0
      || typeof result.request_id !== "string" || !result.request_id.trim()) {
    throw new Error("Incomplete or invalid conversion response");
  }
  process.stdout.write(result.markdown);
} catch (error) {
  console.error(error instanceof Error ? error.message : "Conversion failed");
  process.exitCode = 1;
}

Local PDF as Base64

javascriptBase64
import { readFileSync } from "node:fs";

const key = process.env.PDFTOMARKDOWN_API_KEY;
const identity = process.env.PDFTOMARKDOWN_IDEMPOTENCY_KEY;
try {
  if (!key || !identity) throw new Error("Set PDFTOMARKDOWN_API_KEY and a saved PDFTOMARKDOWN_IDEMPOTENCY_KEY");
  const body = JSON.stringify({ input: { pdf_base64: readFileSync("document.pdf").toString("base64") } });
  // One transport retry; retain exactly the same bytes, options and identity.
  const signal = AbortSignal.timeout(660_000);
  let response;
  for (let attempt = 0; attempt < 2; attempt++) {
    try {
      response = await fetch("https://pdftomarkdown.dev/v1/convert", {
        method: "POST", signal,
        headers: { Authorization: `Bearer ${key}`, "Idempotency-Key": identity,
          "Content-Type": "application/json" },
        body,
      });
      break;
    } catch (error) {
      if (attempt === 1 || signal.aborted) throw error;
    }
  }
  if (!response || response.status !== 200) throw new Error(`HTTP ${response?.status}; keep the identity for recovery`);
  const result = await response.json();
  if (result?.complete !== true || typeof result.markdown !== "string"
      || !Number.isSafeInteger(result.pages) || result.pages < 0
      || typeof result.request_id !== "string" || !result.request_id.trim()) {
    throw new Error("Incomplete or invalid conversion response");
  }
  process.stdout.write(result.markdown);
} catch (error) {
  console.error(error instanceof Error ? error.message : "Conversion failed");
  process.exitCode = 1;
}

Raw PDF upload

javascriptRaw
import { readFileSync } from "node:fs";

const key = process.env.PDFTOMARKDOWN_API_KEY;
const identity = process.env.PDFTOMARKDOWN_IDEMPOTENCY_KEY;
try {
  if (!key || !identity) throw new Error("Set PDFTOMARKDOWN_API_KEY and a saved PDFTOMARKDOWN_IDEMPOTENCY_KEY");
  const body = readFileSync("document.pdf");
  // One transport retry; retain exactly the same bytes, options and identity.
  const signal = AbortSignal.timeout(660_000);
  let response;
  for (let attempt = 0; attempt < 2; attempt++) {
    try {
      response = await fetch("https://pdftomarkdown.dev/v1/convert", {
        method: "POST", signal,
        headers: { Authorization: `Bearer ${key}`, "Idempotency-Key": identity,
          "Content-Type": "application/pdf" },
        body,
      });
      break;
    } catch (error) {
      if (attempt === 1 || signal.aborted) throw error;
    }
  }
  if (!response || response.status !== 200) throw new Error(`HTTP ${response?.status}; keep the identity for recovery`);
  const result = await response.json();
  if (result?.complete !== true || typeof result.markdown !== "string"
      || !Number.isSafeInteger(result.pages) || result.pages < 0
      || typeof result.request_id !== "string" || !result.request_id.trim()) {
    throw new Error("Incomplete or invalid conversion response");
  }
  process.stdout.write(result.markdown);
} catch (error) {
  console.error(error instanceof Error ? error.message : "Conversion failed");
  process.exitCode = 1;
}

Only a complete, typed success writes Markdown. For pending work, rate limits or an uncertain connection, follow the API’s retry guidance using the same saved identity and input. Never replace the identity automatically. Completed account results replay for 24 hours; demo requests have no paid replay guarantee.

API reference: limits, authentication and errors · Document processing and retention