How to Redact PDF Text in .NET with C#

Learn how to redact text on a PDF document with C# using pdfRest Redact PDF API tool.
Share this page

Permanently Redact PDF Text with C# and .NET

PDF redaction must remove sensitive text, not simply cover it visually. The pdfRest Redact PDF API Tool uses two endpoints to make that distinction explicit. /pdf-with-redacted-text-preview identifies and marks the text selected by your rules, while /pdf-with-redacted-text-applied permanently removes the approved content. The workflow helps .NET teams automate recurring redaction work with clear visibility into matches before the source information is removed.

This tutorial uses both endpoints in one C# workflow. The example immediately applies the preview so developers can see how to chain the calls. A production process can also insert an authorized approval rule between them when that step is part of the organization's redaction policy.

For example, a .NET customer-support archive can remove email addresses and phone numbers from case attachments before the documents are supplied to an analytics team. The application can use maintained presets to find common data formats, route preview files for approval, and release only the permanently redacted results.

Create Redaction Rules in C#

The preview endpoint expects redactions as a JSON array. Each entry can use:

  • A literal value for an exact word, phrase, name, or identifier
  • A regex value for an organization-specific pattern
  • A preset value for a common type of sensitive data

Current presets cover formats such as email addresses, phone numbers, dates, U.S. Social Security numbers, credit-card numbers, bank-routing numbers, IBANs, SWIFT/BIC numbers, URLs, and IPv4 or IPv6 addresses. These maintained patterns reduce the amount of matching logic your team must write for common data, while custom regular expressions and literals handle values unique to your organization. One request can combine all three methods.

The C# sample uses Newtonsoft.Json JArray and JObject instances to build the array safely before serializing it into the multipart request. Replace the demonstration pattern with rules designed and tested for the documents your application processes.

C# Preview-and-Apply Example

Set the PDFREST_API_KEY environment variable and pass the input PDF path on the command line. The optional PDFREST_URL variable can select the EU service instead of the default US Cloud API.

/*
 * What this sample does:
 * - Previews redactions and then applies them using the preview output.
 * - Routed from Program.cs as: `dotnet run -- redact-preview-and-finalize `.
 *
 * Setup (environment):
 * - Copy .env.example to .env
 * - Set PDFREST_API_KEY=your_api_key_here
 * - Optional: set PDFREST_URL to override the API region. For EU/GDPR compliance and proximity, use:
 *     PDFREST_URL=https://eu-api.pdfrest.com
 *   For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work
 *
 * Usage:
 *   dotnet run -- redact-preview-and-finalize /path/to/input.pdf
 *
 * Output:
 * - Prints JSON responses for preview and finalize steps.
 */

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Text;

namespace Samples.ComplexFlowExamples
{
    public static class RedactPreviewAndFinalize
    {
        public static async Task Execute(string[] args)
        {
            if (args == null || args.Length < 1)
            {
                Console.Error.WriteLine("redact-preview-and-finalize requires ");
                Environment.Exit(1);
                return;
            }
            var inputPath = args[0];
            if (!File.Exists(inputPath))
            {
                Console.Error.WriteLine($"File not found: {inputPath}");
                Environment.Exit(1);
                return;
            }
            var apiKey = Environment.GetEnvironmentVariable("PDFREST_API_KEY");
            if (string.IsNullOrWhiteSpace(apiKey))
            {
                Console.Error.WriteLine("Missing required environment variable: PDFREST_API_KEY");
                Environment.Exit(1);
                return;
            }
            var baseUrl = Environment.GetEnvironmentVariable("PDFREST_URL") ?? "https://api.pdfrest.com";

            using (var httpClient = new HttpClient { BaseAddress = new Uri(baseUrl) })
            {
                // Preview redaction
                using var previewRequest = new HttpRequestMessage(HttpMethod.Post, "pdf-with-redacted-text-preview");
                previewRequest.Headers.TryAddWithoutValidation("Api-Key", apiKey);
                previewRequest.Headers.Accept.Add(new("application/json"));
                var previewMultipartContent = new MultipartFormDataContent();
                var byteArray = File.ReadAllBytes(inputPath);
                var byteAryContent = new ByteArrayContent(byteArray);
                previewMultipartContent.Add(byteAryContent, "file", Path.GetFileName(inputPath));
                byteAryContent.Headers.TryAddWithoutValidation("Content-Type", "application/octet-stream");
                var redactionArray = new JArray
                {
                    new JObject { ["type"] = "regex", ["value"] = "[Tt]he" }
                };
                var byteArrayRedOption = new ByteArrayContent(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(redactionArray)));
                previewMultipartContent.Add(byteArrayRedOption, "redactions");
                previewRequest.Content = previewMultipartContent;
                var pdfResponse = await httpClient.SendAsync(previewRequest);
                var pdfResult = await pdfResponse.Content.ReadAsStringAsync();
                Console.WriteLine("Redaction preview response received.");
                Console.WriteLine(pdfResult);
                dynamic responseData = JObject.Parse(pdfResult);
                string pdfID = responseData.outputId;

                // Apply finalization
                using var finalizeRequest = new HttpRequestMessage(HttpMethod.Post, "pdf-with-redacted-text-applied");
                finalizeRequest.Headers.TryAddWithoutValidation("Api-Key", apiKey);
                finalizeRequest.Headers.Accept.Add(new("application/json"));
                var finalMultipartContent = new MultipartFormDataContent();
                var byteArrayIdOption = new ByteArrayContent(Encoding.UTF8.GetBytes(pdfID));
                finalMultipartContent.Add(byteArrayIdOption, "id");
                finalizeRequest.Content = finalMultipartContent;
                var response = await httpClient.SendAsync(finalizeRequest);
                var apiResult = await response.Content.ReadAsStringAsync();
                Console.WriteLine("Finalized redaction response received.");
                Console.WriteLine(apiResult);
            }
        }
    }
}

Source: pdfRest Redact PDF C# complex-flow sample on GitHub

Chain the Preview into the Applied Redaction

The first HttpRequestMessage uploads the PDF and serialized redaction array to pdf-with-redacted-text-preview. The response contains an outputId for the preview PDF. The sample parses that response with JObject, reads the ID, and adds it to a second multipart request for pdf-with-redacted-text-applied. Resource-based chaining keeps the intermediate file on the processing service, so the .NET application does not need to download and upload it again between the two stages.

Only the second response represents the permanently redacted PDF. An application that displays or stores the first response as its final document would leave the targeted text in place beneath the preview markings.

For a production .NET integration, verify IsSuccessStatusCode before parsing either response, handle invalid or missing JSON fields, set an appropriate timeout, and pass a CancellationToken. Do not send the apply request when the preview request fails or does not return a valid output ID. If the application needs a non-black final appearance, add the optional rgb_color field to the applied request.

Apply Approved Redactions at Scale

The preview endpoint makes each match visible, while the apply endpoint permanently removes the approved content instead of hiding it behind a visual overlay. Once an organization establishes its rules and approval path, the same C# workflow can apply them consistently across recurring document sets.

Protect the original, preview, and final files with appropriate access controls and retention rules. Preview files remain inside the controlled workflow, while permanently redacted outputs can move into the organization's approved distribution process.

Redact PDF combines flexible matching, maintained sensitive-data presets, a visible review stage, and permanent removal in one chainable API workflow. See the Redact PDF API reference for the current request fields, presets, and responses. If the source already exists as a pdfRest resource, both stages can use JSON payloads; see the redaction preview JSON-payload sample and the applied redaction JSON-payload sample.

Generate a self-service API Key now!
Create your FREE API Key to start processing PDFs in seconds, only possible with pdfRest.