Skip to main content
PPDF123

PDF API recipes

Copy-and-run examples for the PDF jobs developers ask for most. Each one is shown as curl, as a pdfx command and as a Node program, and each states the limit that applies and the error to expect.

On this page

Anonymous calls need no API key. The examples use the hosted service at https://pdf123.xyz; point PDFX_API_BASE or the baseUrl option of the SDK at your own server to run them there. Install pdfx and the SDK as described in the command line and SDK guides, and see Limits for the upload limits.

How do I convert a PDF to Markdown from code?

PDF to Markdown reads the text layer of a PDF and returns Markdown with its headings, lists and tables. Use it to feed a document to a language model or a search index.

curl
curl -X POST "https://pdf123.xyz/api/v1/convert/pdf/markdown" \
  -F "[email protected]" \
  -o report.md
pdfx
pdfx pdf-to-markdown report.pdf -o report.md
Node, @pdf123/sdk
import { Pdf123Client } from "@pdf123/sdk";
import { readFileInput, saveResult } from "@pdf123/sdk/node";

const client = new Pdf123Client();
const result = await client.run("pdf-to-markdown", {
  input: [await readFileInput("report.pdf")],
});
await saveResult(result, { output: "report.md" });
  • In our test on text PDFs, headings, bullet and numbered lists, tables, bold and italic text survived. A fenced code block lost its fence, a link lost its address, and images were dropped.
  • A page that is only a picture comes back as an empty file with HTTP 200, not as an error.

The PDF is a scan: An empty result means the file has no text this tool can read. Use OCR PDF with its Markdown output, which is the default, to get the words of a scan.

How do I make a scanned PDF searchable from code?

OCR PDF with the Searchable PDF output lays the recognized text over each original page, so the result can be searched, selected and copied. The page count stays the same.

curl
curl -X POST "https://pdf123.xyz/api/v1/misc/ocr-pdf" \
  -F "[email protected]" \
  -F "outputFormat=pdf" \
  -F "languages=eng" \
  -o searchable.pdf
pdfx
pdfx ocr scan.pdf --outputFormat pdf --languages eng -o searchable.pdf
Node, @pdf123/sdk
import { Pdf123Client } from "@pdf123/sdk";
import { readFileInput, saveResult } from "@pdf123/sdk/node";

const client = new Pdf123Client();
const result = await client.run("ocr", {
  input: [await readFileInput("scan.pdf")],
  params: { outputFormat: "pdf", languages: "eng" },
});
await saveResult(result, { output: "searchable.pdf" });
  • Recognition uses Tesseract on pages rendered at 300 dpi, in one of 12 languages. The API takes up to four joined by a plus sign, such as eng+fra.
  • Each request recognizes at most 50 pages that need it; GET /api/v1/info/status reports the current limit as maxOcrPages and the installed languages as ocrLanguages.
  • Every page is rendered again, so the searchable PDF can be much larger than the scan.

How do I merge PDFs from code?

Merge joins the files in the order you list them and keeps the text selectable. It copies the original pages instead of printing them to images.

curl
curl -X POST "https://pdf123.xyz/api/v1/general/merge-pdfs" \
  -F "[email protected]" \
  -F "[email protected]" \
  -o merged.pdf
pdfx
pdfx merge a.pdf b.pdf -o merged.pdf
Node, @pdf123/sdk
import { Pdf123Client } from "@pdf123/sdk";
import { readFileInput, saveResult } from "@pdf123/sdk/node";

const client = new Pdf123Client();
const result = await client.run("merge", {
  input: [await readFileInput("a.pdf"), await readFileInput("b.pdf")],
});
await saveResult(result, { output: "merged.pdf" });
  • The order of the input files is the order of the pages in the result.

An input is encrypted: The request stops with password_required. Pass the password (--input-password in pdfx, the password option in the SDK) or run Unlock on the file first.

How do I compress a PDF to a size limit from code?

Compress takes a target size in megabytes and lowers image quality level by level until the file fits. Text, fonts and page count are never changed.

curl
curl -X POST "https://pdf123.xyz/api/v1/misc/compress-pdf" \
  -F "[email protected]" \
  -F "targetSizeMb=1" \
  -o small.pdf
pdfx
pdfx compress report.pdf --targetSizeMb 1 -o small.pdf
Node, @pdf123/sdk
import { Pdf123Client } from "@pdf123/sdk";
import { readFileInput, saveResult } from "@pdf123/sdk/node";

const client = new Pdf123Client();
const result = await client.run("compress", {
  input: [await readFileInput("report.pdf")],
  params: { targetSizeMb: "1" },
});
await saveResult(result, { output: "small.pdf" });
  • The target is a goal. If the strongest level still does not fit, you get the smallest result it reached and the response header X-Target-Met is false; the SDK exposes it as result.headers["x-target-met"], and pdfx prints a note on standard error.
  • 1 MB counts as 1,048,576 bytes, so a portal that counts 1 MB as 1,000,000 bytes needs a slightly lower value.

How do I split a PDF into parts under a size limit from code?

Split by Page Count with splitType 0 cuts a PDF into parts of at most maxSizeMb megabytes and returns them in a ZIP. Cuts fall between pages, and each part is as large as the limit allows.

curl
curl -X POST "https://pdf123.xyz/api/v1/general/split-by-size-or-count" \
  -F "[email protected]" \
  -F "splitType=0" \
  -F "maxSizeMb=10" \
  -o parts.zip
pdfx
pdfx split-by-size report.pdf --splitType 0 --maxSizeMb 10 -o parts.zip
Node, @pdf123/sdk
import { Pdf123Client } from "@pdf123/sdk";
import { readFileInput, saveResult } from "@pdf123/sdk/node";

const client = new Pdf123Client();
const result = await client.run("split-by-size", {
  input: [await readFileInput("report.pdf")],
  params: { splitType: "0", maxSizeMb: "10" },
});
await saveResult(result, { output: "parts.zip" });
  • A page that is larger than the limit by itself becomes a part on its own; the response header X-Oversized-Parts counts those parts (result.headers["x-oversized-parts"] in the SDK; pdfx prints a note). Compress the original first if that matters.
  • Fonts and images shared by several pages are stored in every part that uses them, so the parts add up to more than the original.

maxSizeMb is outside 0.05 to 1024, or too small for a long file: The request is rejected with invalid_parameter (HTTP 400). Raise the limit or split by page count.

How do I remove print and copy restrictions from a PDF from code?

A PDF that opens without a password but blocks printing or copying has only an owner password. Unlock needs no password for it: leave the field out and download a copy without the restrictions.

curl
curl -X POST "https://pdf123.xyz/api/v1/security/remove-password" \
  -F "[email protected]" \
  -o open.pdf
pdfx
pdfx unlock restricted.pdf -o open.pdf
Node, @pdf123/sdk
import { Pdf123Client } from "@pdf123/sdk";
import { readFileInput, saveResult } from "@pdf123/sdk/node";

const client = new Pdf123Client();
const result = await client.run("unlock", {
  input: [await readFileInput("restricted.pdf")],
});
await saveResult(result, { output: "open.pdf" });
  • Use it only on files you are allowed to change. It does not guess or recover passwords.

The PDF asks for a password to open: The request stops with password_required (HTTP 400) until you send that password.

How do I turn HTML into a PDF from code?

HTML to PDF renders a page with WeasyPrint. Send one HTML file, or a ZIP with the HTML and the stylesheets and images it uses.

curl
curl -X POST "https://pdf123.xyz/api/v1/convert/html/pdf" \
  -F "[email protected]" \
  -o page.pdf
pdfx
pdfx html-to-pdf page.html -o page.pdf
Node, @pdf123/sdk
import { Pdf123Client } from "@pdf123/sdk";
import { readFileInput, saveResult } from "@pdf123/sdk/node";

const client = new Pdf123Client();
const result = await client.run("html-to-pdf", {
  input: [await readFileInput("page.html")],
});
await saveResult(result, { output: "page.pdf" });
  • No JavaScript runs and there is no headless browser, so layouts that depend on scripts can collapse.
  • Page size and margins come from your own CSS, for example an @page rule; nothing is added around the file.

How do I turn Markdown into a PDF from code?

Markdown to PDF parses CommonMark, then prints the result with WeasyPrint on A4 pages with 2 cm margins. Tables, strikethrough and task lists render.

curl
curl -X POST "https://pdf123.xyz/api/v1/convert/markdown/pdf" \
  -F "[email protected]" \
  -o notes.pdf
pdfx
pdfx markdown-to-pdf notes.md -o notes.pdf
Node, @pdf123/sdk
import { Pdf123Client } from "@pdf123/sdk";
import { readFileInput, saveResult } from "@pdf123/sdk/node";

const client = new Pdf123Client();
const result = await client.run("markdown-to-pdf", {
  input: [await readFileInput("notes.md")],
});
await saveResult(result, { output: "notes.pdf" });
  • Footnotes, emoji shortcodes, Mermaid diagrams and math are not converted.
  • Images need a ZIP that holds the Markdown file and the images; the website's file picker takes only .md, while the API also accepts the ZIP.