1 creditHTML to PDF API — faithful to your CSS
The Chromium-based renderer built for invoices, receipts, and reports.
ASHDOCS renders an HTML template containing `{{ }}` variables, `for` loops and conditionals into a PDF in a single request, substituting values from a `data` object you send alongside the markup. Strict mode refuses to ship a document that still contains unfilled placeholders and returns the missing variable names instead.
How does the HTML to PDF API work?
One HTTP request from any language. Every ASHDOCS endpoint uses the same X-API-Key header.
curl -X POST https://www.ashdocs.com/api/v1/tools/html-to-pdf \
-H "X-API-Key: ash_live_..." \
-H "Content-Type: application/json" \
-d '{"html":"<h1>Invoice #1042</h1>","options":{"format":"A4","printBackground":true}}'import requests
r = requests.post(
"https://www.ashdocs.com/api/v1/tools/html-to-pdf",
headers={"X-API-Key": "ash_live_..."},
json={
"html": "<h1>Invoice #1042</h1>",
"options": {
"format": "A4",
"printBackground": True
}
},
)
job = r.json()
print(job["status"], job["output_files"][0]["url"])const res = await fetch("https://www.ashdocs.com/api/v1/tools/html-to-pdf", {
method: "POST",
headers: { "X-API-Key": "ash_live_...", "Content-Type": "application/json" },
body: JSON.stringify({"html":"<h1>Invoice #1042</h1>","options":{"format":"A4","printBackground":true}}),
});
const job = await res.json();
console.log(job.status, job.output_files[0].url);using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "ash_live_...");
var body = new StringContent(
"{\"html\":\"<h1>Invoice #1042</h1>\",\"options\":{\"format\":\"A4\",\"printBackground\":true}}",
Encoding.UTF8, "application/json");
var res = await client.PostAsync("https://www.ashdocs.com/api/v1/tools/html-to-pdf", body);
var job = await res.Content.ReadAsStringAsync();
Console.WriteLine(job);import java.io.ByteArrayOutputStream;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
public class Sample {
public static void main(String[] args) throws Exception {
String json = "{\"html\":\"<h1>Invoice #1042</h1>\",\"options\":{\"format\":\"A4\",\"printBackground\":true}}";
HttpRequest req = HttpRequest.newBuilder(URI.create("https://www.ashdocs.com/api/v1/tools/html-to-pdf"))
.header("X-API-Key", "ash_live_...")
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(json))
.build();
HttpResponse<String> res = HttpClient.newHttpClient().send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(res.body());
}
}#include <stdio.h>
#include <curl/curl.h>
int main(void) {
CURL *curl = curl_easy_init();
if (!curl) return 1;
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "X-API-Key: ash_live_...");
headers = curl_slist_append(headers, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "{\"html\":\"<h1>Invoice #1042</h1>\",\"options\":{\"format\":\"A4\",\"printBackground\":true}}");
curl_easy_setopt(curl, CURLOPT_URL, "https://www.ashdocs.com/api/v1/tools/html-to-pdf");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
CURLcode rc = curl_easy_perform(curl);
printf("\n");
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
return rc == CURLE_OK ? 0 : 1;
}Example input
<h1>Invoice #INV-2026-0042</h1> <p>Amount due: $175.00</p>
How do I use HTML to PDF API in Make, Zapier or n8n?
Add an HTTP "Make a request" module, POST your HTML as JSON, and turn off Parse response so the binary arrives intact.
Make setup guide →Use Webhooks by Zapier with a POST action and map the returned file URL into your next step.
Zapier setup guide →Trigger an automation on a record change and call the endpoint with the Send request action.
Airtable setup guide →Common problems and fixes
| Symptom | Cause | Fix |
|---|---|---|
| Background colours are missing | Print rendering suppresses backgrounds by default | Set printBackground: true in your options |
| Table headers appear only on the first page | A thead does not repeat unless told to | Add thead { display: table-header-group; } to your CSS |
| Fonts are substituted | The rendering container has almost no fonts installed | Load web fonts explicitly with @font-face and an absolute URL |
| Images do not appear | Assets must be reachable from the public internet | Host images publicly and reference them by absolute URL |
| Content splits mid-row across pages | No page-break rules are applied by default | Add page-break-inside: avoid to rows and cards |
Common use cases
- →Invoicing systems
- →Rendered email templates as PDFs
- →Reports from data dashboards
Frequently asked questions
Which templating syntax does it use?+
Sandboxed Jinja2 — {{ variable }}, {% for %} and {% if %} over the data object you send.
Can I use web fonts?+
Name fonts that are installed on the renderer, or upload them as font assets and list their ids in fonts on the v2 route. A font the renderer cannot find is silently substituted and your layout will move.
Why does my table header only appear on page one?+
Because the thead is not set to repeat. Add four rules to your print CSS: table { break-inside: auto; } tr { break-inside: avoid; } thead { display: table-header-group; } .totals { break-inside: avoid; } — the third repeats the header on every page; the others stop a row or the totals block splitting across a page.
How much does one render cost?+
One credit.