How to Validate a ZUGFeRD PDF in .NET with C#

Validate a ZUGFeRD or Factur-X hybrid invoice and its PDF/A conformance with pdfRest using .NET with C#.
Share this page

This tutorial shows how to validate an existing ZUGFeRD or Factur-X hybrid invoice with .NET with C#. It uses the pdfRest Create ZUGFeRD PDF API Tool to submit the invoice PDF to its validation endpoint and print the response without modifying the document.

Why Validate a ZUGFeRD PDF in .NET with C#?

Receiving an invoice PDF is not the same as knowing that it is a usable hybrid electronic invoice. A validation step checks the ZUGFeRD or Factur-X package and its PDF/A conformance before a receiving, records, or accounts-payable workflow treats the file as an accepted result.

For example, a .NET with C# intake service can validate supplier invoices as they arrive, retain the response with the processing record, and route an unsuccessful result for follow-up before the invoice enters an automated approval path. This gives operational teams a clear decision point rather than discovering a problem later in the workflow.

Validation does not repair or replace the submitted PDF. It reports on the existing hybrid invoice, allowing the calling application to preserve the original, request a corrected version, or route the document to a separate creation or remediation process when appropriate.

What the Request Does

The multipart request contains one PDF in the file field. The endpoint analyzes that existing document and returns validation information; it does not generate a replacement invoice or modify the supplied PDF.

The C# samples use framework HttpClient APIs and disposable request content. The API key is read from PDFREST_API_KEY, keeping the credential out of the source file.

How to Validate a ZUGFeRD PDF in .NET with C# Code Example

/*
 * What this sample does:
 * - Validates a hybrid ZUGFeRD / Factur-X PDF without modifying it.
 *
 * Setup (environment):
 * - Copy .env.example to .env and 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 -- validated-zugferd-multipart /path/to/zugferd-invoice.pdf
 *
 * Output:
 * - Prints the validation JSON response and returns a nonzero exit code when the request fails.
 */
using System.Net.Http.Headers;

namespace Samples.EndpointExamples.MultipartPayload;

public static class ValidatedZugferd
{
    public static async Task Execute(string[] args)
    {
        var zugferdPdf = args.Length > 0 ? args[0] : "/path/to/zugferd-invoice.pdf";
        if (!File.Exists(zugferdPdf)) throw new FileNotFoundException("ZUGFeRD PDF not found.", zugferdPdf);
        var apiKey = Environment.GetEnvironmentVariable("PDFREST_API_KEY") ?? throw new InvalidOperationException("Missing PDFREST_API_KEY");
        var baseUrl = Environment.GetEnvironmentVariable("PDFREST_URL") ?? "https://api.pdfrest.com";
        using var client = new HttpClient { BaseAddress = new Uri(baseUrl) };
        client.DefaultRequestHeaders.TryAddWithoutValidation("Api-Key", apiKey);
        using var form = new MultipartFormDataContent();
        var pdf = new ByteArrayContent(await File.ReadAllBytesAsync(zugferdPdf));
        pdf.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
        form.Add(pdf, "file", Path.GetFileName(zugferdPdf));
        var response = await client.PostAsync("validated-zugferd", form);
        Console.WriteLine(await response.Content.ReadAsStringAsync());
        if (!response.IsSuccessStatusCode) Environment.ExitCode = 1;
    }
}

Source: View the multipart sample on GitHub.

Breaking Down the Code

The request is compact, but each field has a distinct role in the hybrid-invoice workflow.

  • Submit the finished hybrid invoice. Validation accepts one existing ZUGFeRD or Factur-X PDF through the file field. The code sends it as application/pdf and does not include XML, pdf_file, regenerate_pdf, or render_options.
  • Build the multipart request. MultipartFormDataContent owns the fields and generates the multipart boundary. Each StreamContent value is disposed with the form after HttpClient sends it.
  • Configure the request safely. The sample gets PDFREST_API_KEY and an optional PDFREST_URL from environment variables, keeping both regional selection and credentials outside the code.
  • Call the validation endpoint. The request goes to /validated-zugferd, which is the validation endpoint within the Create ZUGFeRD PDF API Tool. It analyzes the submitted document without replacing or modifying it.
  • Use the result as a workflow decision. The example prints response.Content and returns a nonzero process exit code for an unsuccessful HTTP status. Parse the JSON only after IsSuccessStatusCode is true. A receiving or accounts-payable service can continue an accepted path or send an unsuccessful result for review.

Beyond the Tutorial

In this .NET with C# tutorial, you submitted an existing hybrid invoice for validation and handled the returned result as application data. That pattern fits an intake gate, a supplier-invoice check, or a controlled audit record.

For the complete request fields, accepted values, response contract, and service limits, review the Create ZUGFeRD PDF API Tool documentation for the validation endpoint. The same endpoint can be used with multipart uploads when the files are present in the current request or with resource IDs after a separate upload step.

The repository also includes a JSON-payload Validate ZUGFeRD PDF sample for .NET with C#. That version uploads the source files first and then sends their resource IDs to /validated-zugferd, which is useful when a service already stages input files for later operations.

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