Split PDF API
POST a PDF to /v2/convert/pdf/to/split and each page comes back as its own PDF, named statements-1.pdf, statements-2.pdf and so on. SplitByPages puts more pages in each part, and PageRange splits only the pages you list.
- Endpoint
- POST /v2/
convert/ pdf/ to/ split - Accepts
- Sample timing
- 3 ms median of 5 runsHow we measure
- Request size
- Up to 10 MB on the Free plan or 100 MB on paid plans, all files together
Request and response
Every sample below ran against the API before this page was published. Set PDFCONVERSIONAPI_KEY to your key and run it as is.
curl -sS -X POST \
https://api.pdfconversionapi.com/v2/convert/pdf/to/split \
-H "Authorization: Bearer $PDFCONVERSIONAPI_KEY" \
-F File=@statements.pdf \
--form-string SplitByPages=2 \
-o response.json
# FileData is base64. Save the first file in converted/,
# or print the JSON error.
if jq -e '.Files' response.json > /dev/null; then
mkdir -p converted
name=$(jq -r '.Files[0].FileName' response.json)
jq -r '.Files[0].FileData' response.json \
| base64 --decode > "converted/$name"
else
cat response.json
fiimport base64
import os
import requests
key = os.environ["PDFCONVERSIONAPI_KEY"]
response = requests.post(
"https://api.pdfconversionapi.com/v2/convert/pdf/to/split",
headers={"Authorization": f"Bearer {key}"},
files=[("File", open("statements.pdf", "rb"))],
data={
"SplitByPages": "2",
},
timeout=180,
)
result = response.json()
if not response.ok:
raise SystemExit(f"{result['Code']}: {result['Message']}")
os.makedirs("converted", exist_ok=True)
for file in result["Files"]:
path = os.path.join("converted", file["FileName"])
with open(path, "wb") as out:
out.write(base64.b64decode(file["FileData"]))
print(path, file["FileSize"], "bytes")
import { mkdir, readFile, writeFile } from "node:fs/promises";
import { join } from "node:path";
const form = new FormData();
const file = "statements.pdf";
form.append("File", new Blob([await readFile(file)]), file);
form.append("SplitByPages", "2");
const url = "https://api.pdfconversionapi.com/v2/convert/pdf/to/split";
const key = process.env.PDFCONVERSIONAPI_KEY;
const response = await fetch(url, {
method: "POST",
headers: { Authorization: `Bearer ${key}` },
body: form,
});
const result = await response.json();
if (!response.ok) {
throw new Error(`${result.Code}: ${result.Message}`);
}
await mkdir("converted", { recursive: true });
for (const file of result.Files) {
const path = join("converted", file.FileName);
await writeFile(path, Buffer.from(file.FileData, "base64"));
console.log(path, file.FileSize, "bytes");
}
{
"ConversionCost": 1,
"ConversionTime": 0.003,
"Files": [
{
"FileName": "statements-1.pdf",
"FileExt": "pdf",
"FileSize": 39231,
"FileData": "JVBERi0xLjcKJbutwN4KMSAw…"
},
{
"FileName": "statements-2.pdf",
"FileExt": "pdf",
"FileSize": 38854,
"FileData": "JVBERi0xLjcKJbutwN4KMSAw…"
},
{
"FileName": "statements-3.pdf",
"FileExt": "pdf",
"FileSize": 38759,
"FileData": "JVBERi0xLjcKJbutwN4KMSAw…"
}
]
}Response from our test run on 2026-11-03. ConversionTime shows the median of 5 runs. FileData is shortened here; the real response carries the whole file as base64.
The sample and the result
The same file the code sends. Download the input and the output and compare them yourself.

- Input
- statements.pdf (94 KB)
- Output
- statements-1.pdf (38 KB)statements-2.pdf (38 KB)statements-3.pdf (38 KB)
- Source
- Written for this site (fictional company); PDF saved by a word processor (CC0-1.0). How it was made
- Made by
- 2026-11-04, API build
9eeeb0640aba
Parameters
Send these as form fields next to the file. Names are case-insensitive. If you set one of the documented options below that we don't support yet, the request fails with a 400 that names it instead of returning a file made without it.
| Parameter | What it does |
|---|---|
SplitByPagesinteger, default 1 | Pages per output file. The last file holds whatever is left over: our 6-page sample with SplitByPages=4 came back as a 4-page file and a 2-page file.Values: 1–10000 |
PageRangestring | Split only these pages; without it every page is used. The list is sorted and each page used once, so 2,1,2 means pages 1 and 2. An open end such as 4- or 4-last runs to the last page, and last on its own is the last page. A range that ends past the last page stops there, but a page or range start past it returns 400, for example "PageRange asks for page 9, but the document has 6 pages".Values: for example 1-3,5, 4- or 2-last |
Passwordstring | Opens a PDF that needs a password to open, and the parts come back with no password. The open password is enough when the file restricts nothing; a file from pdf/to/protect with AllowEverything=true counts as unrestricted, since editing includes page assembly. When it also restricts printing, copying or editing, send the owner password; the open password then returns 422 "this PDF has permission restrictions". On a PDF that opens without a password, only the owner password does anything: it lifts the restrictions. |
FileNamestring | Base name for the parts. FileName=statement returns statement-1.pdf, statement-2.pdf and so on; without it the parts take the uploaded file's name. |
StoreFileboolean, default false | Return a separate download URL for each part (Files[].Url) and no file data. Each link expires 3 hours after the request. |
Not supported yet
Setting one of these to anything but its default returns 400.
| Option | What to do instead |
|---|---|
Mode | Splitting is by page count only. Mode=pagecount, the documented default, is accepted; any other mode returns 400. |
Value | Returns 400 with any value. Put the number of pages per file in SplitByPages. |
MergeOutput | Every part comes back as its own entry in Files[]. |
What carries over, and what doesn't
Kept
- Page content, fonts and images, copied rather than redrawn; each page of the three sample parts rendered pixel for pixel like the same page of the input in our check
- Page order inside each part, and parts returned in page order in Files[]
- Each page's size and orientation: splitting our 3-page merge sample gave an 8.5 x 11, an 11 x 8.5 and an 8.5 x 11 in file
- Text you can select and search
- Document properties: every part carries the input's Title, and on a test file the Author, Subject, Keywords, Creator, Producer and dates came through as they were
- Comments and web links on the pages of each part
Lost or not yet supported
- Bookmarks. The sample input has 12; none of the parts has any.
- What the original stored for the whole file beyond its document properties: attachments, page labels, accessibility tags, XMP metadata and the form dictionary. Each part is a new document holding only its pages, so form fields show their values but are no longer fillable.
- Links to a page that ends up in another part. The link is still on the page but its target is not one of the part's pages, and that target page's data is still written into the part, which makes the file larger than it needs to be.
- Size savings you might expect. Fonts and images that pages share are copied into every part, and so is an image a page lists without drawing it. The sample's three parts total 116,844 bytes against 95,949 for the input; a 648,531-byte report with three large JPEG pictures split into parts of 644,398 and 643,729 bytes.
- Encryption. A file that opens without a password and restricts nothing, or one opened with
Password, is split into parts with no encryption; send them to/v2/convert/pdf/to/protectif they need a password again.
Limits
- One PDF per request. Two files return 400 "this conversion takes exactly one file".
- Up to 2,000 output files per request. A 2,001-page file split one page per file returns 413 "splitting would create more than 2,000 files".
- Uploads up to 10 MB on the Free plan or 100 MB on paid plans.
- A digitally signed PDF returns 422 "this PDF is digitally signed, and rewriting it would invalidate the signature", since no part could keep a valid signature.
- A PDF that restricts printing, copying or editing returns 422 "this PDF has permission restrictions; send the owner password in Password, or remove them with /v2/convert/pdf/to/unprotect and the owner password", because the parts would come back without the restrictions. Send the owner password in
Passwordand the split goes ahead, also on a file that opens freely; a wrong password still gets the 422. - Each request uses a single part size, so parts of different lengths need one call per part (see the FAQ below).
Where teams use it
Batch print runs into one file per customer
A billing system often prints every statement into a single PDF. When each statement has the same page count, SplitByPages turns the run into one file per customer to email or archive. The sample does this with three 2-page statements.
Page-by-page processing
Split a long document into single pages and send each one to OCR, a classifier or a reviewer as its own job. The part number in each file name is the page number when you split the whole file one page at a time.
A single section as separate pages
Combine PageRange with the default of one page per file to turn, say, pages 4- of a contract pack into individual exhibits without touching the pages before them.
Questions
How do I get one PDF per page?
Send the file with no other fields. SplitByPages defaults to 1, so a 6-page file comes back as six entries in Files[], named after the upload with -1 to -6 added.
Can I split at chosen pages, like 1-3, 4-9 and 10-12?
Not in one request yet. Call /v2/convert/pdf/to/extract once per part with that part's PageRange (for example PageRange=4-9). Each call returns one PDF with those pages.
Can PageRange change the page order?
No. The pages you list are sorted and duplicates are dropped before the split, so PageRange=5,2 gives page 2 first. With PageRange=1-3,6 and SplitByPages=2, the parts hold pages 1-2 and pages 3 and 6.
Why are the parts bigger than the original divided by the number of parts?
A font or image that several pages use is stored once in the original but has to be in every part that shows it. In the sample, each 2-page part carries the same three embedded Liberation Sans subsets. If a part also holds images its pages never draw, send it to /v2/convert/pdf/to/compress with Preset=lossless, which drops them without touching the others: one of our parts went from 643,729 to 293,168 bytes.
Does it accept ConvertAPI's split parameters?
Partly. Mode=pagecount and MergeOutput=false are accepted because they are the defaults, and Password opens a protected file. Value, MergeOutput=true and other modes return 400 naming the parameter, so a client using them needs to send SplitByPages and PageRange instead.
Convert your first PDF file in a minute.