PDF Blocks
PricingSupport
Start Free
Go to Page

Reorder the pages of a PDF

Rearrange a PDF's pages into any order you specify with page_order — pages come out exactly as listed, repeats duplicate, and omissions drop.

Rearrange the pages of a PDF into any order you specify with the page_order parameter. Because page_order uses ordered page syntax, this action doubles as a combined extract-and-reorder: pages left out are dropped and a page listed twice is repeated. The API is stateless: your document is processed in-region and never stored.

Endpoint

POST
/v1/reorder_pages

Available in every region. See Regions & data residency for routing and data residency.

Region URL
Global https://api.pdfblocks.com/v1/reorder_pages
United States https://us.api.pdfblocks.com/v1/reorder_pages
US HIPAA https://hipaa.api.pdfblocks.com/v1/reorder_pages
European Union https://eu.api.pdfblocks.com/v1/reorder_pages
United Kingdom https://uk.api.pdfblocks.com/v1/reorder_pages
Canada https://ca.api.pdfblocks.com/v1/reorder_pages
Australia https://au.api.pdfblocks.com/v1/reorder_pages
Japan https://jp.api.pdfblocks.com/v1/reorder_pages
India https://in.api.pdfblocks.com/v1/reorder_pages
Brazil https://br.api.pdfblocks.com/v1/reorder_pages

Authentication

Authenticate every request with your secret API key in the X-API-Key header, over HTTPS. Create and manage keys from the dashboard. See Authentication for details.

Request

The endpoint accepts a multipart/form-data request body.

filefilerequired

The input PDF document.

page_orderstringrequired

The desired page order, written in the ordered page syntax such as 3,1,2. Pages left out are dropped, and a page listed more than once is repeated. Maximum 1000 characters.

Page order

page_order is read as an ordered list, not a set: the pages come out exactly as listed. A page named twice is emitted twice, and any page you leave out is dropped. A range may even run backwards — 10..5 walks from page 10 down to page 5.

Numbers are 1-based, and a negative index counts from the end, so -1 is the last page.

page_order Produces
3,1,2 Pages 3, 1, then 2
2.. Page 2 through the last page, in order
-1,1..-2 The last page, then every page before it
1,1,2.. Page 1 twice, then page 2 onward
10..5 Pages 10 down to 5, in reverse

See Selecting pages for the complete reference, including how ordered page_order differs from the set-based pages field.

Examples

Put page 3 first, then pages 1 and 2:

cURLbash
curl https://api.pdfblocks.com/v1/reorder_pages \
  -H 'X-API-Key: your_api_key' \
  -F file=@input.pdf \
  -F page_order='3,1,2' \
  -o reordered.pdf
Pythonpython
# pip install requests
import requests

with open('input.pdf', 'rb') as file:
    response = requests.post(
        'https://api.pdfblocks.com/v1/reorder_pages',
        headers={'X-API-Key': 'your_api_key'},
        files={'file': file},
        data={'page_order': '3,1,2'},
    )

response.raise_for_status()
with open('reordered.pdf', 'wb') as output:
    output.write(response.content)
Node.jsjavascript
// 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_order', '3,1,2');

const response = await fetch('https://api.pdfblocks.com/v1/reorder_pages', {
  method: 'POST',
  headers: { 'X-API-Key': 'your_api_key' },
  body,
});

if (!response.ok) throw new Error(`Request failed: ${response.status}`);
await writeFile('reordered.pdf', Buffer.from(await response.arrayBuffer()));
PHPphp
<?php
$ch = curl_init('https://api.pdfblocks.com/v1/reorder_pages');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ['X-API-Key: your_api_key'],
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => [
        'file' => new CURLFile('input.pdf', 'application/pdf'),
        'page_order' => '3,1,2',
    ],
]);

$pdf = curl_exec($ch);
if (curl_getinfo($ch, CURLINFO_HTTP_CODE) === 200) {
    file_put_contents('reordered.pdf', $pdf);
}
Rubyruby
# gem install http
require 'http'

response = HTTP
  .headers('X-API-Key' => 'your_api_key')
  .post('https://api.pdfblocks.com/v1/reorder_pages', form: {
    file: HTTP::FormData::File.new('input.pdf'),
    page_order: '3,1,2',
  })

File.write('reordered.pdf', response.body) if response.status.success?
Gogo
package main

import (
	"bytes"
	"io"
	"mime/multipart"
	"net/http"
	"os"
)

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_order", "3,1,2")
	form.Close()

	req, _ := http.NewRequest("POST", "https://api.pdfblocks.com/v1/reorder_pages", &buf)
	req.Header.Set("Content-Type", form.FormDataContentType())
	req.Header.Set("X-API-Key", "your_api_key")

	res, _ := http.DefaultClient.Do(req)
	defer res.Body.Close()

	out, _ := os.Create("reordered.pdf")
	defer out.Close()
	io.Copy(out, res.Body)
}
C#csharp
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "your_api_key");

using var form = new MultipartFormDataContent
{
    { new ByteArrayContent(File.ReadAllBytes("input.pdf")), "file", "input.pdf" },
    { new StringContent("3,1,2"), "page_order" },
};

var response = await client.PostAsync(
    "https://api.pdfblocks.com/v1/reorder_pages", form);
response.EnsureSuccessStatusCode();
await File.WriteAllBytesAsync(
    "reordered.pdf", await response.Content.ReadAsByteArrayAsync());

Response

On success, the response is 200 OK with the reordered PDF as the body:

HTTP/1.1 200 OK
Content-Type: application/pdf
Content-Length: 39184

Stream the body straight to a file, as the examples above do; nothing is stored on our side.

Errors

Failed requests return an application/problem+json body. The most common one for this endpoint is a 400, returned when page_order is malformed or names a page the document doesn’t have — the errors object identifies the field:

{
  "type": "https://www.pdfblocks.com/docs/api/v1/error/400",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "errors": {
    "page_order": ["The page_order field references a page that does not exist in the document."]
  }
}

A missing or invalid X-API-Key returns a 401. See Errors for every status code and the full response shape.

Recipes

Common variations. Expand one to see it in every language.

Move the last page to the front
cURLbash
curl https://api.pdfblocks.com/v1/reorder_pages \
  -H 'X-API-Key: your_api_key' \
  -F file=@input.pdf \
  -F page_order='-1,1..-2' \
  -o last-first.pdf
Pythonpython
import requests

with open('input.pdf', 'rb') as file:
    response = requests.post(
        'https://api.pdfblocks.com/v1/reorder_pages',
        headers={'X-API-Key': 'your_api_key'},
        files={'file': file},
        data={'page_order': '-1,1..-2'},
    )

response.raise_for_status()
with open('last-first.pdf', 'wb') as output:
    output.write(response.content)
Node.jsjavascript
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_order', '-1,1..-2');

const response = await fetch('https://api.pdfblocks.com/v1/reorder_pages', {
  method: 'POST',
  headers: { 'X-API-Key': 'your_api_key' },
  body,
});

if (!response.ok) throw new Error(`Request failed: ${response.status}`);
await writeFile('last-first.pdf', Buffer.from(await response.arrayBuffer()));
PHPphp
<?php
$ch = curl_init('https://api.pdfblocks.com/v1/reorder_pages');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ['X-API-Key: your_api_key'],
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => [
        'file' => new CURLFile('input.pdf', 'application/pdf'),
        'page_order' => '-1,1..-2',
    ],
]);

$pdf = curl_exec($ch);
if (curl_getinfo($ch, CURLINFO_HTTP_CODE) === 200) {
    file_put_contents('last-first.pdf', $pdf);
}
Rubyruby
require 'http'

response = HTTP
  .headers('X-API-Key' => 'your_api_key')
  .post('https://api.pdfblocks.com/v1/reorder_pages', form: {
    file: HTTP::FormData::File.new('input.pdf'),
    page_order: '-1,1..-2',
  })

File.write('last-first.pdf', response.body) if response.status.success?
Gogo
package main

import (
	"bytes"
	"io"
	"mime/multipart"
	"net/http"
	"os"
)

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_order", "-1,1..-2")
	form.Close()

	req, _ := http.NewRequest("POST", "https://api.pdfblocks.com/v1/reorder_pages", &buf)
	req.Header.Set("Content-Type", form.FormDataContentType())
	req.Header.Set("X-API-Key", "your_api_key")

	res, _ := http.DefaultClient.Do(req)
	defer res.Body.Close()

	out, _ := os.Create("last-first.pdf")
	defer out.Close()
	io.Copy(out, res.Body)
}
C#csharp
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "your_api_key");

using var form = new MultipartFormDataContent
{
    { new ByteArrayContent(File.ReadAllBytes("input.pdf")), "file", "input.pdf" },
    { new StringContent("-1,1..-2"), "page_order" },
};

var response = await client.PostAsync(
    "https://api.pdfblocks.com/v1/reorder_pages", form);
response.EnsureSuccessStatusCode();
await File.WriteAllBytesAsync(
    "last-first.pdf", await response.Content.ReadAsByteArrayAsync());
Duplicate the cover page
cURLbash
curl https://api.pdfblocks.com/v1/reorder_pages \
  -H 'X-API-Key: your_api_key' \
  -F file=@input.pdf \
  -F page_order='1,1..-1' \
  -o doubled-cover.pdf
Pythonpython
import requests

with open('input.pdf', 'rb') as file:
    response = requests.post(
        'https://api.pdfblocks.com/v1/reorder_pages',
        headers={'X-API-Key': 'your_api_key'},
        files={'file': file},
        data={'page_order': '1,1..-1'},
    )

response.raise_for_status()
with open('doubled-cover.pdf', 'wb') as output:
    output.write(response.content)
Node.jsjavascript
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_order', '1,1..-1');

const response = await fetch('https://api.pdfblocks.com/v1/reorder_pages', {
  method: 'POST',
  headers: { 'X-API-Key': 'your_api_key' },
  body,
});

if (!response.ok) throw new Error(`Request failed: ${response.status}`);
await writeFile('doubled-cover.pdf', Buffer.from(await response.arrayBuffer()));
PHPphp
<?php
$ch = curl_init('https://api.pdfblocks.com/v1/reorder_pages');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ['X-API-Key: your_api_key'],
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => [
        'file' => new CURLFile('input.pdf', 'application/pdf'),
        'page_order' => '1,1..-1',
    ],
]);

$pdf = curl_exec($ch);
if (curl_getinfo($ch, CURLINFO_HTTP_CODE) === 200) {
    file_put_contents('doubled-cover.pdf', $pdf);
}
Rubyruby
require 'http'

response = HTTP
  .headers('X-API-Key' => 'your_api_key')
  .post('https://api.pdfblocks.com/v1/reorder_pages', form: {
    file: HTTP::FormData::File.new('input.pdf'),
    page_order: '1,1..-1',
  })

File.write('doubled-cover.pdf', response.body) if response.status.success?
Gogo
package main

import (
	"bytes"
	"io"
	"mime/multipart"
	"net/http"
	"os"
)

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_order", "1,1..-1")
	form.Close()

	req, _ := http.NewRequest("POST", "https://api.pdfblocks.com/v1/reorder_pages", &buf)
	req.Header.Set("Content-Type", form.FormDataContentType())
	req.Header.Set("X-API-Key", "your_api_key")

	res, _ := http.DefaultClient.Do(req)
	defer res.Body.Close()

	out, _ := os.Create("doubled-cover.pdf")
	defer out.Close()
	io.Copy(out, res.Body)
}
C#csharp
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "your_api_key");

using var form = new MultipartFormDataContent
{
    { new ByteArrayContent(File.ReadAllBytes("input.pdf")), "file", "input.pdf" },
    { new StringContent("1,1..-1"), "page_order" },
};

var response = await client.PostAsync(
    "https://api.pdfblocks.com/v1/reorder_pages", form);
response.EnsureSuccessStatusCode();
await File.WriteAllBytesAsync(
    "doubled-cover.pdf", await response.Content.ReadAsByteArrayAsync());