Go to Page

Add restrictions to a PDF

Set the permission flags of a PDF, controlling copying, printing, editing, and form filling, behind an owner password.

Apply permission restrictions to a PDF (limit copying, printing, editing, form-filling, and more), enforced by an owner_password. Restrictions are permission flags, distinct from adding a password, which sets the password required just to open the file; you can also set a user_password here to require both. The API is stateless: your document is processed in-region and never stored.

Endpoint

POST
/v1/add_restrictions

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

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

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.

owner_passwordstringrequired

The owner password. 4–32 printable ASCII characters. Opens the document and changes its permission flags.

user_passwordstring

An optional user password. 4–32 printable ASCII characters. When set, the document can’t be opened without it. Omit it, or leave it empty, to let anyone open the document.

encryption_algorithmstringdefault:AES-128

The encryption algorithm. One of AES-128 or AES-256.

allow_copy_contentbooleandefault:true

Allow copying text and images to the clipboard.

allow_change_contentbooleandefault:true

Allow changing the content of the document.

allow_printbooleandefault:true

Allow printing the document.

allow_print_high_resolutionbooleandefault:true

Allow printing in high resolution.

allow_comment_and_fill_formbooleandefault:true

Allow adding, editing, or modifying annotations and filling form fields.

allow_fill_formbooleandefault:true

Allow filling form fields.

allow_assemble_documentbooleandefault:true

Allow assembling or manipulating the document (insert, delete, rotate pages).

allow_accessibilitybooleandefault:true

Allow accessibility software to read the document’s text and images.

Permission flags

Each flag governs one action a reader can take. Pass the flag as a boolean; set it to false to turn that permission off.

Flag Default Set to false to…
allow_copy_content true block copying text and images to the clipboard
allow_change_content true block changing the content of the document
allow_print true block printing the document
allow_print_high_resolution true block printing in high resolution
allow_comment_and_fill_form true block adding, editing, or modifying annotations and filling form fields
allow_fill_form true block filling form fields
allow_assemble_document true block assembling or manipulating the document (insert, delete, rotate pages)
allow_accessibility true block accessibility software from reading the document

Every flag defaults to true, so nothing is restricted unless you say so. Send only the flags you want to turn off. The restrictions are enforced by the owner_password: a reader who supplies it can change the permissions. Add a user_password only if you also want to require a password just to open the file. For the full lifecycle, see Protecting documents.

Examples

Lock a document so it can’t be copied or printed, keeping it openable by anyone:

cURLbash
curl https://api.pdfblocks.com/v1/add_restrictions \
  -H 'X-API-Key: your_api_key' \
  -F file=@input.pdf \
  -F owner_password='s3cr3t-owner' \
  -F allow_copy_content=false \
  -F allow_print=false \
  -F allow_print_high_resolution=false \
  -o restricted.pdf
Pythonpython
# pip install requests
import requests

with open('input.pdf', 'rb') as file:
    response = requests.post(
        'https://api.pdfblocks.com/v1/add_restrictions',
        headers={'X-API-Key': 'your_api_key'},
        files={'file': file},
        data={
            'owner_password': 's3cr3t-owner',
            'allow_copy_content': 'false',
            'allow_print': 'false',
            'allow_print_high_resolution': 'false',
        },
    )

response.raise_for_status()
with open('restricted.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('owner_password', 's3cr3t-owner');
body.set('allow_copy_content', 'false');
body.set('allow_print', 'false');
body.set('allow_print_high_resolution', 'false');

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

if (!response.ok) throw new Error(`Request failed: ${response.status}`);
await writeFile('restricted.pdf', Buffer.from(await response.arrayBuffer()));
PHPphp
<?php
$ch = curl_init('https://api.pdfblocks.com/v1/add_restrictions');
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'),
        'owner_password' => 's3cr3t-owner',
        'allow_copy_content' => 'false',
        'allow_print' => 'false',
        'allow_print_high_resolution' => 'false',
    ],
]);

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

response = HTTP
  .headers('X-API-Key' => 'your_api_key')
  .post('https://api.pdfblocks.com/v1/add_restrictions', form: {
    file: HTTP::FormData::File.new('input.pdf'),
    owner_password: 's3cr3t-owner',
    allow_copy_content: 'false',
    allow_print: 'false',
    allow_print_high_resolution: 'false',
  })

File.write('restricted.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("owner_password", "s3cr3t-owner")
	form.WriteField("allow_copy_content", "false")
	form.WriteField("allow_print", "false")
	form.WriteField("allow_print_high_resolution", "false")
	form.Close()

	req, _ := http.NewRequest("POST", "https://api.pdfblocks.com/v1/add_restrictions", &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("restricted.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("s3cr3t-owner"), "owner_password" },
    { new StringContent("false"), "allow_copy_content" },
    { new StringContent("false"), "allow_print" },
    { new StringContent("false"), "allow_print_high_resolution" },
};

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

Response

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

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

The output is the same document with the requested permissions applied. Its pages and content are unchanged. 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 a parameter is invalid (for example an owner_password that isn’t 4–32 printable ASCII characters), with the errors object naming each field:

{
  "type": "https://www.pdfblocks.com/docs/api/v1/error/400",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "errors": {
    "owner_password": ["The field owner_password must match the regular expression '^[\\x20-\\x7e]{4,32}$'."]
  }
}

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.

Read-only: block copying, editing, and printing
cURLbash
curl https://api.pdfblocks.com/v1/add_restrictions \
  -H 'X-API-Key: your_api_key' \
  -F file=@input.pdf \
  -F owner_password='s3cr3t-owner' \
  -F allow_copy_content=false \
  -F allow_change_content=false \
  -F allow_print=false \
  -F allow_print_high_resolution=false \
  -o readonly.pdf
Pythonpython
import requests

with open('input.pdf', 'rb') as file:
    response = requests.post(
        'https://api.pdfblocks.com/v1/add_restrictions',
        headers={'X-API-Key': 'your_api_key'},
        files={'file': file},
        data={
            'owner_password': 's3cr3t-owner',
            'allow_copy_content': 'false',
            'allow_change_content': 'false',
            'allow_print': 'false',
            'allow_print_high_resolution': 'false',
        },
    )

response.raise_for_status()
with open('readonly.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('owner_password', 's3cr3t-owner');
body.set('allow_copy_content', 'false');
body.set('allow_change_content', 'false');
body.set('allow_print', 'false');
body.set('allow_print_high_resolution', 'false');

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

if (!response.ok) throw new Error(`Request failed: ${response.status}`);
await writeFile('readonly.pdf', Buffer.from(await response.arrayBuffer()));
PHPphp
<?php
$ch = curl_init('https://api.pdfblocks.com/v1/add_restrictions');
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'),
        'owner_password' => 's3cr3t-owner',
        'allow_copy_content' => 'false',
        'allow_change_content' => 'false',
        'allow_print' => 'false',
        'allow_print_high_resolution' => 'false',
    ],
]);

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

response = HTTP
  .headers('X-API-Key' => 'your_api_key')
  .post('https://api.pdfblocks.com/v1/add_restrictions', form: {
    file: HTTP::FormData::File.new('input.pdf'),
    owner_password: 's3cr3t-owner',
    allow_copy_content: 'false',
    allow_change_content: 'false',
    allow_print: 'false',
    allow_print_high_resolution: 'false',
  })

File.write('readonly.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("owner_password", "s3cr3t-owner")
	form.WriteField("allow_copy_content", "false")
	form.WriteField("allow_change_content", "false")
	form.WriteField("allow_print", "false")
	form.WriteField("allow_print_high_resolution", "false")
	form.Close()

	req, _ := http.NewRequest("POST", "https://api.pdfblocks.com/v1/add_restrictions", &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("readonly.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("s3cr3t-owner"), "owner_password" },
    { new StringContent("false"), "allow_copy_content" },
    { new StringContent("false"), "allow_change_content" },
    { new StringContent("false"), "allow_print" },
    { new StringContent("false"), "allow_print_high_resolution" },
};

var response = await client.PostAsync(
    "https://api.pdfblocks.com/v1/add_restrictions", form);
response.EnsureSuccessStatusCode();
await File.WriteAllBytesAsync(
    "readonly.pdf", await response.Content.ReadAsByteArrayAsync());
Require a password to open, with AES-256
cURLbash
curl https://api.pdfblocks.com/v1/add_restrictions \
  -H 'X-API-Key: your_api_key' \
  -F file=@input.pdf \
  -F owner_password='s3cr3t-owner' \
  -F user_password='open-me-2024' \
  -F encryption_algorithm=AES-256 \
  -o protected.pdf
Pythonpython
import requests

with open('input.pdf', 'rb') as file:
    response = requests.post(
        'https://api.pdfblocks.com/v1/add_restrictions',
        headers={'X-API-Key': 'your_api_key'},
        files={'file': file},
        data={
            'owner_password': 's3cr3t-owner',
            'user_password': 'open-me-2024',
            'encryption_algorithm': 'AES-256',
        },
    )

response.raise_for_status()
with open('protected.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('owner_password', 's3cr3t-owner');
body.set('user_password', 'open-me-2024');
body.set('encryption_algorithm', 'AES-256');

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

if (!response.ok) throw new Error(`Request failed: ${response.status}`);
await writeFile('protected.pdf', Buffer.from(await response.arrayBuffer()));
PHPphp
<?php
$ch = curl_init('https://api.pdfblocks.com/v1/add_restrictions');
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'),
        'owner_password' => 's3cr3t-owner',
        'user_password' => 'open-me-2024',
        'encryption_algorithm' => 'AES-256',
    ],
]);

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

response = HTTP
  .headers('X-API-Key' => 'your_api_key')
  .post('https://api.pdfblocks.com/v1/add_restrictions', form: {
    file: HTTP::FormData::File.new('input.pdf'),
    owner_password: 's3cr3t-owner',
    user_password: 'open-me-2024',
    encryption_algorithm: 'AES-256',
  })

File.write('protected.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("owner_password", "s3cr3t-owner")
	form.WriteField("user_password", "open-me-2024")
	form.WriteField("encryption_algorithm", "AES-256")
	form.Close()

	req, _ := http.NewRequest("POST", "https://api.pdfblocks.com/v1/add_restrictions", &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("protected.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("s3cr3t-owner"), "owner_password" },
    { new StringContent("open-me-2024"), "user_password" },
    { new StringContent("AES-256"), "encryption_algorithm" },
};

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