How to Validate a ZUGFeRD PDF with Java
This tutorial shows how to validate an existing ZUGFeRD or Factur-X hybrid invoice with Java. 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 with Java?
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 Java 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 Java samples use OkHttp for HTTP and the repository’s established project dependencies. Applications adopting the class should provide equivalent dependencies and obtain credentials from secure runtime configuration.
How to Validate a ZUGFeRD PDF with Java Code Example
import io.github.cdimascio.dotenv.Dotenv;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
public class ValidatedZugferd {
// By default, we use the US-based API service. This is the primary endpoint for global use.
private static final String API_URL = "https://api.pdfrest.com";
// For GDPR compliance and enhanced performance for European users, use the EU-based service
// instead.
// For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work
// private static final String API_URL = "https://eu-api.pdfrest.com";
// Specify your API key here, or in the environment variable PDFREST_API_KEY.
// You can also put the environment variable in a .env file.
private static final String DEFAULT_API_KEY = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
private static final OkHttpClient CLIENT =
new OkHttpClient.Builder().readTimeout(60, TimeUnit.SECONDS).build();
public static void main(String[] args) throws IOException {
// Specify the completed hybrid ZUGFeRD or Factur-X PDF path here, or as the first program
// argument.
File zugferdPdf = new File(args.length > 0 ? args[0] : "/path/to/zugferd-invoice.pdf");
String apiKey =
Dotenv.configure()
.ignoreIfMalformed()
.ignoreIfMissing()
.load()
.get("PDFREST_API_KEY", DEFAULT_API_KEY);
// Validate a hybrid ZUGFeRD / Factur-X PDF without modifying it.
MultipartBody body =
new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart(
"file",
zugferdPdf.getName(),
RequestBody.create(zugferdPdf, MediaType.parse("application/pdf")))
.build();
send(
new Request.Builder()
.url(API_URL + "/validated-zugferd")
.header("Api-Key", apiKey)
.post(body)
.build());
}
private static void send(Request request) throws IOException {
try (Response response = CLIENT.newCall(request).execute()) {
String body = response.body() == null ? "" : response.body().string();
System.out.println("Result code " + response.code());
System.out.println(body);
if (!response.isSuccessful()) {
System.exit(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
filefield. The code sends it asapplication/pdfand does not include XML,pdf_file,regenerate_pdf, orrender_options. - Build the multipart request.
MultipartBody.Buildercreates the form and its boundary.RequestBody.createassigns the XML and PDF media types before the request is sent with OkHttp. - Configure the request safely. The sample loads
PDFREST_API_KEYthrough dotenv, with a placeholder only as a fallback. Replace the placeholder and keep real credentials outside source control. - 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
sendmethod reads and prints the JSON body, then exits nonzero whenresponse.isSuccessful()is false. A production caller can parse a successful body after that check. A receiving or accounts-payable service can continue an accepted path or send an unsuccessful result for review.
Beyond the Tutorial
In this Java 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 Java. 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.