Nutrient’s PDF redaction API permanently removes sensitive information from documents — names, addresses, account numbers, Social Security numbers, and any custom pattern defined by the caller. Unlike annotation-based tools that overlay black boxes, this API deletes the underlying data from the file so it cannot be recovered.
Redact names, account numbers, addresses, PII, and other confidential information from PDFs with precision, irreversibly and securely.
Automatically redact sensitive text in PDFs using our Zapier integration through a no-code workflow that supports compliance and archival readiness.
Automatically find and redact content using regex, keywords, or custom search criteria for privacy, legal, financial, and regulated document workflows.
This example redacts text in your document, effectively and permanently removing the matching content.
Try it out in three steps
document.pdf to your project folder.result.pdf to see the output.curl -X POST https://api.nutrient.io/processor/redact \ -H "Authorization: Bearer your_api_key_here" \ -o result.pdf \ --fail \ -F file=@document.pdf \ -F data='{ "strategy": "text", "strategyOptions": { "text": "macaque", "caseSensitive": false }, "redactionState": "apply" }'curl -X POST https://api.nutrient.io/processor/redact ^ -H "Authorization: Bearer your_api_key_here" ^ -o result.pdf ^ --fail ^ -F file=@document.pdf ^ -F data="{\"strategy\": \"text\", \"strategyOptions\": {\"text\": \"macaque\", \"caseSensitive\": false}, \"redactionState\": \"apply\"}"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( "file", "document.pdf", RequestBody.create( MediaType.parse("application/pdf"), new File("document.pdf") ) ) .addFormDataPart( "data", new JSONObject() .put("strategy", "text") .put("strategyOptions", new JSONObject() .put("text", "macaque") .put("caseSensitive", false)) .put("redactionState", "apply").toString() ) .build();
final Request request = new Request.Builder() .url("https://api.nutrient.io/processor/redact") .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/processor/redact");
var request = new RestRequest(Method.POST) .AddHeader("Authorization", "Bearer your_api_key_here") .AddFile("file", "document.pdf") .AddParameter("data", new JsonObject { ["strategy"] = "text", ["strategyOptions"] = new JsonObject { ["text"] = "macaque", ["caseSensitive"] = false }, ["redactionState"] = "apply" }.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('data', JSON.stringify({ strategy: "text", strategyOptions: { text: "macaque", caseSensitive: false }, redactionState: "apply"}))formData.append('file', fs.createReadStream('document.pdf'))
;(async () => { try { const response = await axios.post('https://api.nutrient.io/processor/redact', 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/processor/redact', headers = { 'Authorization': 'Bearer your_api_key_here' }, files = { 'file': open('document.pdf', 'rb') }, data = { 'data': json.dumps({ 'strategy': 'text', 'strategyOptions': { 'text': 'macaque', 'caseSensitive': False }, 'redactionState': 'apply' }) }, 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/processor/redact', CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => '', CURLOPT_POSTFIELDS => array( 'data' => '{ "strategy": "text", "strategyOptions": { "text": "macaque", "caseSensitive": false }, "redactionState": "apply" }', 'file' => 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/processor/redact HTTP/1.1Content-Type: multipart/form-data; boundary=--customboundaryAuthorization: Bearer your_api_key_here
--customboundaryContent-Disposition: form-data; name="data"Content-Type: application/json
{ "strategy": "text", "strategyOptions": { "text": "macaque", "caseSensitive": false }, "redactionState": "apply"}--customboundaryContent-Disposition: form-data; name="file"; filename="document.pdf"Content-Type: application/pdf
(file data)--customboundary--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" } ], "actions": [ { "type": "createRedactions", "strategy": "text", "strategyOptions": { "text": "macaque", "includeAnnotations": true, "caseSensitive": false } }, { "type": "applyRedactions" } ] }'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\"}], \"actions\": [{\"type\": \"createRedactions\", \"strategy\": \"text\", \"strategyOptions\": {\"text\": \"macaque\", \"includeAnnotations\": true, \"caseSensitive\": false}}, {\"type\": \"applyRedactions\"}]}"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("actions", new JSONArray() .put(new JSONObject() .put("type", "createRedactions") .put("strategy", "text") .put("strategyOptions", new JSONObject() .put("text", "macaque") .put("includeAnnotations", true) .put("caseSensitive", false) ) ) .put(new JSONObject() .put("type", "applyRedactions") ) ).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" } }, ["actions"] = new JsonArray { new JsonObject { ["type"] = "createRedactions", ["strategy"] = "text", ["strategyOptions"] = new JsonObject { ["text"] = "macaque", ["includeAnnotations"] = true, ["caseSensitive"] = false } }, new JsonObject { ["type"] = "applyRedactions" } } }.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" } ], actions: [ { type: "createRedactions", strategy: "text", strategyOptions: { text: "macaque", includeAnnotations: true, caseSensitive: false } }, { type: "applyRedactions" } ]}))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' } ], 'actions': [ { 'type': 'createRedactions', 'strategy': 'text', 'strategyOptions': { 'text': 'macaque', 'includeAnnotations': True, 'caseSensitive': False } }, { 'type': 'applyRedactions' } ] }) }, 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" } ], "actions": [ { "type": "createRedactions", "strategy": "text", "strategyOptions": { "text": "macaque", "includeAnnotations": true, "caseSensitive": false } }, { "type": "applyRedactions" } ] }', '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" } ], "actions": [ { "type": "createRedactions", "strategy": "text", "strategyOptions": { "text": "macaque", "includeAnnotations": true, "caseSensitive": false } }, { "type": "applyRedactions" } ]}--customboundaryContent-Disposition: form-data; name="document"; filename="document.pdf"Content-Type: application/pdf
(document data)--customboundary--A streamlined API designed for fast, secure redaction — perfect for 90 percent of use cases.
FEATURES
Maximum flexibility and advanced features for complex workflows.
FEATURES
The API detects and permanently removes names and addresses, financial data such as account and card numbers, health information (PHI), government IDs and Social Security numbers, email addresses and phone numbers, and any custom pattern defined via regular expressions.
Developers can define redaction rules as regular expressions, targeting custom identifiers alongside built-in presets for common PII types. This pattern-based approach supports GDPR Article 17 (the right to erasure) and HIPAA-driven workflows, where teams need to permanently remove personal data from documents at scale rather than review and redact one file at a time.
An annotation-based tool draws a black box on top of content — the underlying text is still present in the file, recoverable by extracting or inspecting the document’s raw structure. True redaction removes the underlying content itself. Nutrient’s redaction API performs true redaction: It deletes redacted content from the document instead of hiding it behind a mark.
Learn how to use the redaction API’s key features.
Most common next steps
Use the following:
Get started:
Platform resources:
PDF redaction is the permanent removal of sensitive or confidential content from a document. Unlike covering text with a black box, true redaction deletes the underlying data from the file so it cannot be copied, searched, or recovered. Nutrient’s redaction API performs irreversible redaction on PDFs via REST.
Yes. Nutrient’s redaction API permanently removes the selected content from the document — it deletes the data instead of hiding it. Once redacted, the information cannot be recovered by any tool, including those that inspect raw PDF structure.
The API can detect and redact names, addresses, phone numbers, email addresses, Social Security numbers, financial account numbers, dates of birth, and any custom pattern defined via regular expressions. It supports both rule-based and pattern-based detection.
Nutrient’s infrastructure is SOC 2 Type 2 audited and HTTPS-encrypted. The redaction API supports GDPR compliance workflows by enabling permanent erasure of personal data under Article 17 (right to erasure) without requiring manual document review.
The redaction API supports PDF as the primary format. Documents in other formats (Word, images) can be converted to PDF first using the file converter API and then redacted.
Yes. The REST API is designed for batch and high-volume workflows. It integrates into any backend pipeline — Node.js, Python, Java, C#, PHP — to process documents programmatically without manual review of each file.
Adobe Acrobat requires manual selection and review of each document. Nutrient’s redaction API automates detection and removal at scale via REST, making it suitable for compliance pipelines, legal discovery, and enterprise document workflows where manual review is impractical.
Redaction removes specific content — named entities, patterns — from a document while preserving the rest. Sanitization typically refers to removing all metadata, scripts, or hidden data from a file. Nutrient supports both use cases.
Nutrient’s infrastructure is SOC 2 Type 2 audited and GDPR-compliant. See our privacy policy and security documentation for details on data handling.
All communication between your application and Nutrient is done via HTTPS to ensure your data is encrypted when it’s sent to us.
All payments are handled by Paddle. Nutrient DWS Processor API never has direct access to any of your payment data.
Create an account to get your DWS Processor API key and start making API calls.