Merge, split, compress
Work on PDFs — yours, by address, or printed in the same request.
curl https://api.reflowpdf.com/v1/pdf/merge \
-H "Authorization: Bearer $REFLOWPDF_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"filename": "Invoice with terms",
"parts": [
{ "template_id": "invoice" },
{ "pdf_url": "https://example.com/terms.pdf", "pages": "1-2" }
]
}' -o invoice-with-terms.pdfconst pdf = await reflow.pdf.merge({
filename: 'Invoice with terms',
parts: [
{ template_id: 'invoice' }, // the template with its own sample data
{ pdf: await readFile('terms.pdf'), pages: '1-2' }, // bytes are sent in base64 for you
],
})pdf = client.pdf.merge(
filename="Invoice with terms",
parts=[
{"template_id": "invoice"},
{"pdf": open("terms.pdf", "rb").read(), "pages": "1-2"},
],
)A PDF, from anywhere#
| Field | The PDF |
|---|---|
file | one of yours stored for a link: the id in a print's or an operation's JSON response (24 hours) |
pdf | its bytes in base64 (within the 15 MB of a request; the SDKs encode bytes for you) |
pdf_url | a public http(s) address of one — fetched as url pages are (ports 80 and 443, public addresses, redirects checked), up to 100 MB and 60 s |
html, url, template_id | a document printed first, exactly as POST /v1/pdf prints it — with data, options and filename; its pages count as a print's |
With pages, a part gives some of its pages in the order written — "3,1", "2-" (to the end), "1-3,7". An encrypted PDF opens with its password.
Merge#
POST /v1/pdf/merge with parts (1 to 50): their pages one after another in a new PDF, filename naming it. The PDF itself by default; with Accept: application/json, its link (24 hours) and facts, like a print's.
- Each page keeps its content, its links and its form fields.
- The merged file is a new document: the parts' outlines, tags (their structure tree) and standard claims (PDF/A, PDF/UA) do not carry over, so it claims none it no longer keeps. To deliver PDF/UA, print the whole document as one: one HTML, its parts as sections.
- Up to 100 MB a part, 200 MB together, 10,000 pages.
Split#
POST /v1/pdf/split with a PDF and ranges (each a new file), or every (a new file every so many pages). The response is the files' links and, when there are several, a ZIP of them, all kept 24 hours:
{
"id": "spl_N3wq8sHkT2xV9mRp4LcB1a",
"object": "split",
"files": [
{
"id": "Hq8vR2cT9xKmL4pW",
"pages": "1",
"page_count": 1,
"url": "https://api.reflowpdf.com/v1/files/Hq8vR2cT9xKmL4pW/report-pages-1.pdf",
"filename": "report-pages-1.pdf",
"bytes": 48213
},
{
"id": "Tx2mB7cL1pQ9wE4r",
"pages": "2-",
"page_count": 11,
"url": "https://api.reflowpdf.com/v1/files/Tx2mB7cL1pQ9wE4r/report-pages-2-.pdf",
"filename": "report-pages-2-.pdf",
"bytes": 402117
}
],
"archive": {
"url": "https://api.reflowpdf.com/v1/files/Zk3nP8vR2cT9xKmL/report-split.zip",
"filename": "report-split.zip",
"bytes": 450566
},
"expires_at": "2026-11-03T10:22:31.000Z"
}Compress#
POST /v1/pdf/compress with a PDF: written again losslessly, its streams compressed anew at the highest level, its objects packed in object streams, resources no page uses removed. It is never larger than it was (ReflowPDF-Bytes-Before says its size before; the JSON response, bytes_before), unless linearize: true asks for fast web view, its first page shown before the rest has arrived: that adds its hint tables, a few KB. Its images stay as they are, pixel for pixel; an encrypted PDF keeps its encryption.
Errors#
| Code | When |
|---|---|
invalid_pdf 422 | a part is not a PDF, or one that cannot be read; detail names the part |
pdf_encrypted 422 | an encrypted part without its password, or with a wrong one |
unfulfillable 422 | pages names a page the part does not have |
file_not_found 404 | file is not a PDF of this account stored for a link |
document_unreachable 422 | pdf_url could not be fetched |