PDFPipe

Guide

Generate a PDF from HTML in Java

You have a Spring Boot controller, some HTML (an invoice, a statement, a label), and you need to return a PDF. The classic Java answers each carry baggage: iText wants an AGPL license or a commercial one, Flying Saucer chokes on modern CSS, and Playwright means a browser in your container. The lighter path is one HTTP call with the java.net.http.HttpClient that has shipped with the JDK since Java 11.

The minimal Spring Boot controller

The PDFPipe endpoint is POST https://api.pdfpipe.xyz/v1/pdf. Send a JSON body with your HTML and options, attach a bearer token, and you get back raw application/pdf bytes.

java
@RestController
public class InvoiceController {

    private static final HttpClient http = HttpClient.newBuilder()
        .connectTimeout(Duration.ofSeconds(10))
        .build();

    private static final String KEY = System.getenv("PDFPIPE_KEY");

    @GetMapping(value = "/invoice/{id}", produces = MediaType.APPLICATION_PDF_VALUE)
    public ResponseEntity<byte[]> invoice(@PathVariable String id)
            throws IOException, InterruptedException {

        String html = """
            <html>
              <body style="font-family: sans-serif; padding: 40px">
                <h1>Invoice #%s</h1>
                <p>Amount due: $420.00</p>
              </body>
            </html>""".formatted(id);

        String payload = new ObjectMapper().writeValueAsString(Map.of(
            "html", html,
            "options", Map.of("format", "A4")
        ));

        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://api.pdfpipe.xyz/v1/pdf"))
            .timeout(Duration.ofSeconds(20))
            .header("Content-Type", "application/json")
            .header("Authorization", "Bearer " + KEY)
            .POST(HttpRequest.BodyPublishers.ofString(payload))
            .build();

        HttpResponse<byte[]> response =
            http.send(request, HttpResponse.BodyHandlers.ofByteArray());

        if (response.statusCode() != 200) {
            throw new ResponseStatusException(HttpStatus.BAD_GATEWAY,
                "PDF render failed: " + new String(response.body()));
        }

        return ResponseEntity.ok()
            .header(HttpHeaders.CONTENT_DISPOSITION,
                "inline; filename=\"invoice-" + id + ".pdf\"")
            .body(response.body());
    }
}

That is the whole feature: no native libraries, no font configuration on the server, no license discussion with legal. The only dependency in play is Jackson, which Spring Boot already ships.

Why not iText, Flying Saucer, or Playwright?

ConcernLibrary in the JVMHttpClient to PDFPipe
LicensingiText is AGPL or paid; OpenPDF trails behindPlain API pricing, your code stays yours
Modern CSSFlying Saucer is CSS 2.1, no flexbox or gridCurrent engine, renders what your browser renders
Container weightPlaywright adds a browser and ~700 MB to the imageNothing beyond your jar
Heap pressureDocument object models for large reports get bigOne response buffer, GC-friendly

The pattern holds outside Spring too: the same HttpClient code works in Quarkus, Micronaut, a plain servlet, or a CLI tool, because it is just the JDK.

Timeouts and error handling

Both timeouts are set above: connect on the client, request on the call. Renders are idempotent, so a single retry on a 5xx or an IOException is safe. If you are on virtual threads (Java 21+), the blocking send call parks the virtual thread and costs you nothing while the render runs.

java
// Virtual-thread friendly retry, render calls are idempotent.
HttpResponse<byte[]> response;
try {
    response = http.send(request, HttpResponse.BodyHandlers.ofByteArray());
    if (response.statusCode() >= 500) {
        response = http.send(request, HttpResponse.BodyHandlers.ofByteArray());
    }
} catch (IOException firstFailure) {
    response = http.send(request, HttpResponse.BodyHandlers.ofByteArray());
}

Keep the API key in an environment variable or your secrets manager. The options object also accepts other page sizes (for example Letter), margins, and landscape orientation, documented in full on the docs page.

Paste your own HTML into the live playground on the home page to see the PDF render instantly, then read the docs for every option.

See pricing →