Splitting a PDF and handling the output
Call a split action, choose ZIP, JSON, or multipart via the Accept header, and unpack every output part in code.
A split action turns one PDF into several. Unlike every other action, the
response is a set of documents rather than a single PDF, and you choose how they
are packaged with the Accept request header: a ZIP archive (the default), a
JSON envelope of base64-encoded documents, or a multipart/mixed body. This
guide picks a split action, requests each format, and unpacks the parts in code.
Pick a split action
Four actions split a document in different ways. They share the same output contract, so the unpacking code below works for all of them.
| Action | Splits by | Key field |
|---|---|---|
Split by page count (split_by_page_count) |
fixed number of pages per part | page_count |
Split at page (split_at_page) |
one boundary into two parts | page |
Split by file size (split_by_size) |
a maximum byte size per part | maximum_bytes |
Split into page groups (split_by_groups) |
explicit groups you define | groups |
The examples use split_by_page_count with page_count=10. Swap the route and
field to use any other split action.
Choose an output format
Set the Accept header to request a format. Output documents are always named
00001.pdf, 00002.pdf, and so on, in order.
Accept |
Response body | How to read it |
|---|---|---|
application/zip (default) |
A ZIP archive, one entry per document | Unzip the archive |
application/json |
A JSON envelope with a base64 documents[] array |
Decode each content |
multipart/mixed |
One application/pdf part per document |
Read parts in order |
Omit Accept entirely and you get the ZIP. An Accept header that matches none
of these three is answered with 406 Not Acceptable. See Response
formats for the full contract.
Get a ZIP (the default)
With no Accept header, the response is a ZIP archive. Save it, then iterate its
entries.
curl https://api.pdfblocks.com/v1/split_by_page_count \
-H 'X-API-Key: your_api_key' \
-F file=@input.pdf \
-F page_count=10 \
-o parts.zip
unzip parts.zip -d parts/
# parts/00001.pdf parts/00002.pdf parts/00003.pdf …# pip install requests
import io
import zipfile
import requests
with open('input.pdf', 'rb') as file:
response = requests.post(
'https://api.pdfblocks.com/v1/split_by_page_count',
headers={'X-API-Key': 'your_api_key'}, # no Accept → ZIP
files={'file': file},
data={'page_count': 10},
)
response.raise_for_status()
with zipfile.ZipFile(io.BytesIO(response.content)) as archive:
print(archive.namelist()) # ['00001.pdf', '00002.pdf', …]
archive.extractall('parts')package main
import (
"archive/zip"
"bytes"
"io"
"mime/multipart"
"net/http"
"os"
"path/filepath"
)
func main() {
var buf bytes.Buffer
form := multipart.NewWriter(&buf)
file, _ := os.Open("input.pdf")
defer file.Close()
part, _ := form.CreateFormFile("file", "input.pdf")
io.Copy(part, file)
form.WriteField("page_count", "10")
form.Close()
req, _ := http.NewRequest("POST",
"https://api.pdfblocks.com/v1/split_by_page_count", &buf)
req.Header.Set("Content-Type", form.FormDataContentType())
req.Header.Set("X-API-Key", "your_api_key")
// No Accept header → ZIP.
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
archive, _ := zip.NewReader(bytes.NewReader(body), int64(len(body)))
os.MkdirAll("parts", 0755)
for _, entry := range archive.File {
in, _ := entry.Open()
out, _ := os.Create(filepath.Join("parts", entry.Name))
io.Copy(out, in)
out.Close()
in.Close()
}
}Get JSON
Set Accept: application/json to receive an envelope instead. Each document
carries its name, base64-encoded content, and content_type:
{
"documents": [
{ "name": "00001.pdf", "content": "JVBERi0xLjcK…", "content_type": "application/pdf" },
{ "name": "00002.pdf", "content": "JVBERi0xLjcK…", "content_type": "application/pdf" }
]
}JSON is convenient when the caller wants the document names alongside the bytes,
or when a transport is easier to handle as text than as a binary archive. Decode
each content from base64 to recover the PDF.
curl https://api.pdfblocks.com/v1/split_by_page_count \
-H 'X-API-Key: your_api_key' \
-H 'Accept: application/json' \
-F file=@input.pdf \
-F page_count=10 \
-o parts.json# pip install requests
import base64
import requests
with open('input.pdf', 'rb') as file:
response = requests.post(
'https://api.pdfblocks.com/v1/split_by_page_count',
headers={'X-API-Key': 'your_api_key', 'Accept': 'application/json'},
files={'file': file},
data={'page_count': 10},
)
response.raise_for_status()
for document in response.json()['documents']:
with open(document['name'], 'wb') as out:
out.write(base64.b64decode(document['content']))// Node.js 18+
import { readFile, writeFile } from 'node:fs/promises';
const body = new FormData();
body.set('file', new Blob([await readFile('input.pdf')]), 'input.pdf');
body.set('page_count', '10');
const response = await fetch('https://api.pdfblocks.com/v1/split_by_page_count', {
method: 'POST',
headers: { 'X-API-Key': 'your_api_key', Accept: 'application/json' },
body,
});
if (!response.ok) throw new Error(`Request failed: ${response.status}`);
const { documents } = await response.json();
for (const document of documents) {
await writeFile(document.name, Buffer.from(document.content, 'base64'));
}Get multipart/mixed
Set Accept: multipart/mixed to stream one application/pdf part per document,
each with a Content-Disposition naming it 00001.pdf, 00002.pdf, and so on.
Prefer this when you want to handle each part as it arrives rather than hold a
whole archive in memory. Most languages have a multipart parser — for Python,
requests-toolbelt decodes the response directly:
curl https://api.pdfblocks.com/v1/split_by_page_count \
-H 'X-API-Key: your_api_key' \
-H 'Accept: multipart/mixed' \
-F file=@input.pdf \
-F page_count=10 \
-o parts.multipart# pip install requests requests-toolbelt
import requests
from requests_toolbelt.multipart.decoder import MultipartDecoder
with open('input.pdf', 'rb') as file:
response = requests.post(
'https://api.pdfblocks.com/v1/split_by_page_count',
headers={'X-API-Key': 'your_api_key', 'Accept': 'multipart/mixed'},
files={'file': file},
data={'page_count': 10},
)
response.raise_for_status()
for index, part in enumerate(MultipartDecoder.from_response(response).parts, start=1):
with open(f'{index:05d}.pdf', 'wb') as out:
out.write(part.content)Pitfalls
- A
406means yourAcceptdidn’t match. Send exactlyapplication/zip,application/json, ormultipart/mixed(or noAcceptat all). A strayapplication/pdfor*/*from an HTTP client’s defaults is a common cause — set the header explicitly. - Large splits produce large responses. A big document split into many parts
can be a sizeable archive. Stream the response to disk instead of holding it in
memory, or use
multipart/mixedto process each part as it arrives. See Working with large files. - A single oversize page. With Split by
file size, a page larger than
maximum_byteson its own is returned as its own part that exceeds the limit — it can’t be split further. Expect the occasional part to be bigger than the cap.