PDF page manipulation API
Use the PDF page manipulation API to add blank pages, delete pages, duplicate pages, reorder pages, and set page labels in PDF documents. The /build endpoint handles page manipulation with the parts array.
Each parts item contributes pages to the output PDF. Combine file parts, page ranges, and new blank page parts to build a new PDF in the order you need.
For signup, pricing, and task-level examples, refer to these pages:
Add a blank page
The following example inserts one new US Letter page after the first page of document.pdf.
Page indexes are zero-based, so page 0 is the first page. The end value is inclusive, so { "start": 0, "end": 0 } includes only the first page.
curl -X POST https://api.nutrient.io/build \ -H "Authorization: Bearer your_api_key_here" \ -o result.pdf \ --fail \ -F document=@document.pdf \ -F instructions='{ "parts": [ { "file": "document", "pages": { "start": 0, "end": 0 } }, { "page": "new", "pageCount": 1, "layout": { "size": "Letter" } }, { "file": "document", "pages": { "start": 1, "end": -1 } } ] }'curl -X POST https://api.nutrient.io/build ^ -H "Authorization: Bearer your_api_key_here" ^ -o result.pdf ^ --fail ^ -F document=@document.pdf ^ -F instructions="{\"parts\": [{\"file\": \"document\", \"pages\": {\"start\": 0, \"end\": 0}}, {\"page\": \"new\", \"pageCount\": 1, \"layout\": {\"size\": \"Letter\"}}, {\"file\": \"document\", \"pages\": {\"start\": 1, \"end\": -1}}]}"package com.example.pspdfkit;
import java.io.File;import java.io.IOException;import java.nio.file.FileSystems;import java.nio.file.Files;import java.nio.file.StandardCopyOption;
import org.json.JSONArray;import org.json.JSONObject;
import okhttp3.MediaType;import okhttp3.MultipartBody;import okhttp3.OkHttpClient;import okhttp3.Request;import okhttp3.RequestBody;import okhttp3.Response;
public final class PspdfkitApiExample { public static void main(final String[] args) throws IOException { final RequestBody body = new MultipartBody.Builder() .setType(MultipartBody.FORM) .addFormDataPart( "document", "document.pdf", RequestBody.create( MediaType.parse("application/pdf"), new File("document.pdf") ) ) .addFormDataPart( "instructions", new JSONObject() .put("parts", new JSONArray() .put(new JSONObject() .put("file", "document") .put("pages", new JSONObject() .put("start", 0) .put("end", 0) ) ) .put(new JSONObject() .put("page", "new") .put("pageCount", 1) .put("layout", new JSONObject() .put("size", "Letter") ) ) .put(new JSONObject() .put("file", "document") .put("pages", new JSONObject() .put("start", 1) .put("end", -1) ) ) ).toString() ) .build();
final Request request = new Request.Builder() .url("https://api.nutrient.io/build") .method("POST", body) .addHeader("Authorization", "Bearer your_api_key_here") .build();
final OkHttpClient client = new OkHttpClient() .newBuilder() .build();
final Response response = client.newCall(request).execute();
if (response.isSuccessful()) { Files.copy( response.body().byteStream(), FileSystems.getDefault().getPath("result.pdf"), StandardCopyOption.REPLACE_EXISTING ); } else { // Handle the error throw new IOException(response.body().string()); } }}using System;using System.IO;using System.Net;using RestSharp;
namespace PspdfkitApiDemo{ class Program { static void Main(string[] args) { var client = new RestClient("https://api.nutrient.io/build");
var request = new RestRequest(Method.POST) .AddHeader("Authorization", "Bearer your_api_key_here") .AddFile("document", "document.pdf") .AddParameter("instructions", new JsonObject { ["parts"] = new JsonArray { new JsonObject { ["file"] = "document", ["pages"] = new JsonObject { ["start"] = 0, ["end"] = 0 } }, new JsonObject { ["page"] = "new", ["pageCount"] = 1, ["layout"] = new JsonObject { ["size"] = "Letter" } }, new JsonObject { ["file"] = "document", ["pages"] = new JsonObject { ["start"] = 1, ["end"] = -1 } } } }.ToString());
request.AdvancedResponseWriter = (responseStream, response) => { if (response.StatusCode == HttpStatusCode.OK) { using (responseStream) { using var outputFileWriter = File.OpenWrite("result.pdf"); responseStream.CopyTo(outputFileWriter); } } else { var responseStreamReader = new StreamReader(responseStream); Console.Write(responseStreamReader.ReadToEnd()); } };
client.Execute(request); } }}// This code requires Node.js. Do not run this code directly in a web browser.
const axios = require('axios')const FormData = require('form-data')const fs = require('fs')
const formData = new FormData()formData.append('instructions', JSON.stringify({ parts: [ { file: "document", pages: { start: 0, end: 0 } }, { page: "new", pageCount: 1, layout: { size: "Letter" } }, { file: "document", pages: { start: 1, end: -1 } } ]}))formData.append('document', fs.createReadStream('document.pdf'))
;(async () => { try { const response = await axios.post('https://api.nutrient.io/build', formData, { headers: formData.getHeaders({ 'Authorization': 'Bearer your_api_key_here' }), responseType: "stream" })
response.data.pipe(fs.createWriteStream("result.pdf")) } catch (e) { const errorString = await streamToString(e.response.data) console.log(errorString) }})()
function streamToString(stream) { const chunks = [] return new Promise((resolve, reject) => { stream.on("data", (chunk) => chunks.push(Buffer.from(chunk))) stream.on("error", (err) => reject(err)) stream.on("end", () => resolve(Buffer.concat(chunks).toString("utf8"))) })}import requestsimport json
response = requests.request( 'POST', 'https://api.nutrient.io/build', headers = { 'Authorization': 'Bearer your_api_key_here' }, files = { 'document': open('document.pdf', 'rb') }, data = { 'instructions': json.dumps({ 'parts': [ { 'file': 'document', 'pages': { 'start': 0, 'end': 0 } }, { 'page': 'new', 'pageCount': 1, 'layout': { 'size': 'Letter' } }, { 'file': 'document', 'pages': { 'start': 1, 'end': -1 } } ] }) }, stream = True)
if response.ok: with open('result.pdf', 'wb') as fd: for chunk in response.iter_content(chunk_size=8096): fd.write(chunk)else: print(response.text) exit()<?php
$FileHandle = fopen('result.pdf', 'w+');
$curl = curl_init();
curl_setopt_array($curl, array( CURLOPT_URL => 'https://api.nutrient.io/build', CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => '', CURLOPT_POSTFIELDS => array( 'instructions' => '{ "parts": [ { "file": "document", "pages": { "start": 0, "end": 0 } }, { "page": "new", "pageCount": 1, "layout": { "size": "Letter" } }, { "file": "document", "pages": { "start": 1, "end": -1 } } ] }', 'document' => new CURLFILE('document.pdf') ), CURLOPT_HTTPHEADER => array( 'Authorization: Bearer your_api_key_here' ), CURLOPT_FILE => $FileHandle,));
$response = curl_exec($curl);
curl_close($curl);
fclose($FileHandle);POST https://api.nutrient.io/build HTTP/1.1Content-Type: multipart/form-data; boundary=--customboundaryAuthorization: Bearer your_api_key_here
--customboundaryContent-Disposition: form-data; name="instructions"Content-Type: application/json
{ "parts": [ { "file": "document", "pages": { "start": 0, "end": 0 } }, { "page": "new", "pageCount": 1, "layout": { "size": "Letter" } }, { "file": "document", "pages": { "start": 1, "end": -1 } } ]}--customboundaryContent-Disposition: form-data; name="document"; filename="document.pdf"Content-Type: application/pdf
(document data)--customboundary--Add multiple blank pages
Use pageCount to insert more than one blank page. The following example adds three A4 pages to the end of a document:
{ "parts": [ { "file": "document" }, { "page": "new", "pageCount": 3, "layout": { "size": "A4" } } ]}Configure blank page layout
A new blank page part supports the same page layout options used by PDF generation. Set the page size, orientation, and margins with layout.
Use this instructions object to configure a blank page layout:
{ "parts": [ { "file": "document" }, { "page": "new", "pageCount": 1, "layout": { "size": "A4", "orientation": "landscape", "margin": { "top": 20, "right": 20, "bottom": 20, "left": 20 } } } ]}Delete pages
To delete pages, rebuild the output PDF from the page ranges you want to keep. The following example deletes page three from document.pdf by keeping pages zero through two, and then pages four through the end.
Use this instructions object to delete pages:
{ "parts": [ { "file": "document", "pages": { "start": 0, "end": 2 } }, { "file": "document", "pages": { "start": 4, "end": -1 } } ]}Make sure the output keeps at least one page. A request that removes every page won’t produce a valid PDF.
Duplicate a page
To duplicate a page, reference the same source file more than once. The following example prepends a duplicate of the first page before the full original document:
{ "parts": [ { "file": "document", "pages": { "start": 0, "end": 0 } }, { "file": "document" } ]}Use -1 as both start and end to duplicate the last page.
Reorder pages
The order of the parts array controls the page order in the output. The following example moves the last page to the front:
{ "parts": [ { "file": "document", "pages": { "start": -1, "end": -1 } }, { "file": "document", "pages": { "start": 0, "end": -2 } } ]}You can also combine page ranges from multiple PDFs to create a custom packet.
Set page labels
Page labels control the page numbering shown by PDF viewers. They don’t change the physical page order or page count.
The following example sets labels for multiple page ranges:
{ "parts": [ { "file": "document" } ], "output": { "type": "pdf", "labels": [ { "pages": { "start": 0, "end": 0 }, "label": "i" }, { "pages": { "start": 1, "end": 3 }, "label": "intro" }, { "pages": { "start": 4, "end": 5 }, "label": "final" } ] }}For page label examples, refer to the set page label API task page.
Manipulate pages from a URL
For remotely hosted source files, send a JSON request and pass the source URL in parts[].file.url. Use this instructions object:
{ "parts": [ { "file": { "url": "https://example.com/document.pdf" }, "pages": { "start": 0, "end": 0 } }, { "page": "new", "pageCount": 1, "layout": { "size": "Letter" } }, { "file": { "url": "https://example.com/document.pdf" }, "pages": { "start": 1, "end": -1 } } ]}Shell
Run this request to manipulate pages from a URL:
curl -X POST https://api.nutrient.io/build \ -H "Authorization: Bearer $NUTRIENT_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "parts": [ { "file": { "url": "https://example.com/document.pdf" }, "pages": { "start": 0, "end": 0 } }, { "page": "new", "pageCount": 1, "layout": { "size": "Letter" } }, { "file": { "url": "https://example.com/document.pdf" }, "pages": { "start": 1, "end": -1 } } ] }' \ -o result.pdfManipulate password-protected PDFs
If the source PDF is password-protected, include the password on every part that references the protected file. Use this instructions object:
{ "parts": [ { "file": "protected_document", "password": "document-password", "pages": { "start": 0, "end": 0 } }, { "page": "new", "pageCount": 1, "layout": { "size": "Letter" } }, { "file": "protected_document", "password": "document-password", "pages": { "start": 1, "end": -1 } } ]}Nutrient DWS Processor API uses passwords only to open source documents for processing. To set a password on the output PDF, configure output.user_password, output.owner_password, and output.user_permissions.
Combine page manipulation with other actions
The /build endpoint can manipulate pages and then apply additional actions. Actions run after Nutrient DWS Processor API assembles the parts.
The following example inserts a blank page, adds a watermark, and then linearizes the final PDF for web delivery:
{ "parts": [ { "file": "document" }, { "page": "new", "pageCount": 1, "layout": { "size": "Letter" } } ], "actions": [ { "type": "watermark", "text": "APPENDIX", "width": "50%", "height": "20%", "opacity": 0.3, "rotation": 45 } ], "output": { "type": "pdf", "optimize": { "linearize": true } }}For workflows that include cryptographic signing, complete all page manipulation before signing the final PDF.
Reference
Page manipulation uses the Build API parts array. Use FilePart for existing PDF pages and NewPagePart for blank pages:
type PageRange = { // First page to include. Defaults to `0`. // Page indexes are zero-based. Negative values count from the end. start?: number,
// Last page to include. Defaults to `-1`, which means the last page. // The end value is inclusive. end?: number,};
type FilePart = { // Multipart field name, or a remote URL object. file: string | { url: string },
// Optional password for encrypted input PDFs. password?: string,
// Optional page range to include from this input. pages?: PageRange,};
type NewPagePart = { page: "new",
// Number of blank pages to add. Defaults to `1`. pageCount?: number,
layout?: { size?: "A4" | "Letter" | "Legal" | "A3" | "A5" | string, orientation?: "portrait" | "landscape", margin?: { top?: number, right?: number, bottom?: number, left?: number, }, },};
type BuildInstructions = { parts: Array<FilePart | NewPagePart>, actions?: BuildAction[], output?: { type?: "pdf", },};Related API reference operations
- Refer to the build document endpoint API reference to add blank pages, delete pages by omission, duplicate page ranges, reorder pages, set page labels, and apply follow-up actions in a single request.
Related guides
- Refer to the PDF merge API guide.
- Refer to the PDF split API guide.
- Refer to the PDF rotate API guide.
- Refer to the PDF flatten API guide.
- Refer to the PDF watermark API guide.
- Refer to the PDF linearization API guide.
- Refer to the tools and APIs guide.