Split PDFs by Text or Page Numbers in C# Using PDF.co

Use PDF.co’s API to split a PDF at matching text or into specified page ranges. This example accepts either a document URL or a local PDF file.

Step 1: Create a Console Project

Install a supported .NET SDK, then create a project:

dotnet new console -n PdfSplitter
cd PdfSplitter

The example uses built-in .NET libraries and requires no additional packages.

Get your API key from the PDF.co dashboard.

Step 2: Add the Code

Replace the contents of Program.cs with the following code. Replace YOUR_PDFCO_API_KEY with your API key, and keep it out of shared code and source control.

using System;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json.Nodes;
using System.Threading.Tasks;

internal class Program
{
    private const string ApiKey = "YOUR_PDFCO_API_KEY";
    private const string ApiBase = "https://api.pdf.co/v1";
    private static readonly HttpClient Client = new HttpClient();

    private static async Task<int> Main(string[] args)
    {
        if (args.Length != 3 ||
            (args[0] != "text" && args[0] != "pages"))
        {
            Console.WriteLine(
                "Usage: dotnet run -- <text|pages> <URL-or-file> <search-or-pages>");
            return 1;
        }

        try
        {
            string sourceUrl;

            if (Uri.TryCreate(args[1], UriKind.Absolute, out Uri? sourceUri) &&
                (sourceUri.Scheme == "https" || sourceUri.Scheme == "http"))
            {
                sourceUrl = sourceUri.AbsoluteUri;
            }
            else
            {
                sourceUrl = await UploadFileAsync(args[1]);
            }

            var payload = new JsonObject
            {
                ["url"] = sourceUrl,
                ["async"] = false,
                ["inline"] = true
            };

            string endpoint;

            if (args[0] == "text")
            {
                endpoint = "/pdf/split2";
                payload["searchString"] = args[2];
                payload["caseSensitive"] = false;
                payload["regexSearch"] = false;
                payload["excludeKeyPages"] = false;
            }
            else
            {
                endpoint = "/pdf/split";
                payload["pages"] = args[2];
            }

            using var request = new HttpRequestMessage(
                HttpMethod.Post, ApiBase + endpoint);

            request.Content = new StringContent(
                payload.ToJsonString(), Encoding.UTF8, "application/json");

            JsonObject result = await SendApiRequestAsync(request);

            if (result["urls"] is not JsonArray urls || urls.Count == 0)
            {
                throw new InvalidOperationException(
                    "The API returned no split PDF files.");
            }

            int part = 1;

            foreach (JsonNode? item in urls)
            {
                string resultUrl = item?.GetValue<string>()
                    ?? throw new InvalidOperationException("Missing output URL.");

                string localFileName = Path.Combine(
                    Environment.CurrentDirectory,
                    String.Format("part{0}.pdf", part));

                using var download = await Client.GetAsync(
                    resultUrl, HttpCompletionOption.ResponseHeadersRead);

                download.EnsureSuccessStatusCode();

                // CreateNew avoids overwriting an existing output file.
                using var output = new FileStream(
                    localFileName, FileMode.CreateNew, FileAccess.Write);

                await download.Content.CopyToAsync(output);

                Console.WriteLine($"Saved: {localFileName}");
                part++;
            }

            return 0;
        }
        catch (Exception ex)
        {
            Console.Error.WriteLine(ex.Message);
            return 1;
        }
    }

    private static async Task<string> UploadFileAsync(string filePath)
    {
        if (!File.Exists(filePath))
        {
            throw new FileNotFoundException(
                "The source PDF was not found.", filePath);
        }

        string query = ApiBase + "/file/upload/get-presigned-url"
            + "?contenttype=" + Uri.EscapeDataString("application/octet-stream")
            + "&name=" + Uri.EscapeDataString(Path.GetFileName(filePath));

        using var request = new HttpRequestMessage(HttpMethod.Get, query);
        JsonObject uploadInfo = await SendApiRequestAsync(request);

        string uploadUrl = uploadInfo["presignedUrl"]?.GetValue<string>()
            ?? throw new InvalidOperationException("Missing upload URL.");

        string fileUrl = uploadInfo["url"]?.GetValue<string>()
            ?? throw new InvalidOperationException("Missing source URL.");

        using var input = File.OpenRead(filePath);
        using var content = new StreamContent(input);
        content.Headers.ContentType =
            new MediaTypeHeaderValue("application/octet-stream");

        // Upload directly to storage without sending the PDF.co API key.
        using var response = await Client.PutAsync(uploadUrl, content);
        response.EnsureSuccessStatusCode();

        return fileUrl;
    }

    private static async Task<JsonObject> SendApiRequestAsync(
        HttpRequestMessage request)
    {
        request.Headers.Add("x-api-key", ApiKey);

        using var response = await Client.SendAsync(request);
        string body = await response.Content.ReadAsStringAsync();

        if (!response.IsSuccessStatusCode)
        {
            throw new InvalidOperationException(
                $"PDF.co request failed: HTTP {(int)response.StatusCode}");
        }

        JsonObject result = JsonNode.Parse(body) as JsonObject
            ?? throw new InvalidOperationException("Invalid API response.");

        if (result["error"]?.GetValue<bool>() == true)
        {
            throw new InvalidOperationException(
                result["message"]?.ToString() ?? "PDF.co processing failed.");
        }

        return result;
    }
}

Step 3: Split a PDF by Text from a URL

Run the program with text, a direct PDF URL, and the phrase that identifies the start of each document:

dotnet run -- text "https://example.com/invoices.pdf" "invoice number"

Replace the example URL with an accessible PDF.

The program calls /v1/pdf/split2. It searches without case sensitivity and keeps the pages containing the matching phrase. Choose text that marks document boundaries rather than a header repeated on every page.

See the Split PDF by Text Search or Barcode documentation for parameters such as searchString, regexSearch, and excludeKeyPages.

Step 4: Split a Local PDF by Text

Place your PDF in the project folder and run:

dotnet run -- text "multiple-invoices.pdf" "invoice number"

The program uploads the local file to PDF.co’s temporary storage, then uses the uploaded URL for splitting.

You can also supply an absolute file path. Enclose paths containing spaces in quotation marks.

Step 5: Split by Page Numbers

Use pages followed by the source file and the required page ranges:

dotnet run -- pages "multiple-invoices.pdf" "1,2-3"

For a PDF with at least three pages, this creates one file containing page 1 and another containing pages 2–3.

This mode calls /v1/pdf/split, which uses 1-based page numbers. Use "*" to create one PDF per page. See the Split PDF by Pages documentation.

Step 6: Review the Output

The generated files are downloaded as part1.pdf, part2.pdf, and so on in the program’s current working directory. Their full paths appear in the console.

Open the files and confirm the split boundaries. Before running another example, move or rename existing part*.pdf files; the program intentionally avoids overwriting them.

This example uses synchronous processing for small documents. For larger PDFs, use asynchronous processing and check the job status before downloading the results.

Related Tutorials

See Related Tutorials