/// REFERENCE

How do I convert HTML to PDF with the ASHDOCS API?

Reference for POST /api/v1/tools/html-to-pdf: request shape, template data and strict mode, options, credits and error codes, with curl examples.

Published: Last updated:

Answer: POST /api/v1/tools/html-to-pdf takes JSON with your HTML and returns a job envelope whose output_files[0].url is the PDF; one credit. Send a data object and the {{ }} placeholders, for loops and if blocks in the HTML are filled before rendering — strict mode, on by default, refuses a template with a missing variable and names it. The v2 route, POST /api/v2/tools/html-to-pdf, adds running headers and footers, page numbers, uploaded fonts and an explicit engine choice.

v1: a template and its data

The v1 route reads html, data, strict and literal_mode from the JSON body. Templating is sandboxed Jinja2 over data. A template with variables but no data is a 422 template_syntax_without_data; a variable data does not supply is a 422 missing_template_variables listing the names. Set literal_mode: true to print braces as text.

bash
curl -X POST https://www.ashdocs.com/api/v1/tools/html-to-pdf \
  -H "X-API-Key: ash_test_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "html": "<h1>Invoice {{ number }}</h1>{% for l in lines %}<p>{{ l.desc }}</p>{% endfor %}",
        "data": { "number": "INV-0041", "lines": [ { "desc": "Design" } ] } }'

v2: render control

The v2 route reads the body keys and the three options keys in the table below. It fills data only on deployments with v2 templating enabled; elsewhere a template sent to v2 renders with its braces as text, so send templates to v1 unless you have confirmed otherwise. The engine row gives the size rule auto uses to choose between WeasyPrint and Chromium.

bash
curl -X POST https://www.ashdocs.com/api/v2/tools/html-to-pdf \
  -H "X-API-Key: ash_test_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "html": "<h1>Report</h1>", "header_html": "<div>ACME</div>",
        "page_numbers": { "start": 1 }, "options": { "margin_mm": 15 } }'

Options

Generated from the backend source.

Sent inKeyWhat it does
v1 + v2 bodyhtmlThe HTML to render. Required.
v1 bodydataObject of template variables. {{ }}, {% for %} and {% if %} in the HTML are filled from it (sandboxed Jinja2) before rendering. Omit it and the HTML renders as sent.
v1 bodystrictDefault true. A variable the template uses but data does not supply returns 422 missing_template_variables listing the names, instead of rendering a blank.
v1 bodyliteral_modetrue outputs the HTML exactly as sent: braces are text, not template syntax, and no data is needed.
v1 response422 template_syntax_without_dataThe HTML contains template variables but no data was sent. Send data, or set literal_mode: true.
v1 response422 missing_template_variablesstrict is on and these variables (listed in missing) are not in data.
v2 bodyheader_html / footer_htmlHTML repeated at the top / bottom of every page.
v2 bodypage_numbersObject that adds a page-number footer when footer_html is not given; start sets the first number.
v2 bodyengineauto (default), weasyprint or chrome. auto renders with WeasyPrint below 512,000 bytes of HTML and with Chromium at or above it; an explicit value always wins.
v2 bodywait_for / wait_untilChromium only: wait for an element (wait_for) or a load state (wait_until, default load) before printing.
v2 bodypdfaRequest PDF/A output at the given level.
v2 bodyfontsIds of fonts you uploaded as assets; they are injected as @font-face before rendering.
v2 bodydiagnosticstrue adds render diagnostics (overflowing elements, blocked resources, warnings) to the response.
v2 bodydry_runtrue checks the render without producing a billable job.
v2 bodypreviewtrue returns a preview of the first page as well.
v2 optionsoptions.margin_mmPage margin in millimetres. Default 10.
v2 optionsoptions.titleDocument title written into the PDF (WeasyPrint).
v2 optionsoptions.taggedtrue produces a tagged (PDF/UA-1) file, which forces WeasyPrint; tagged with engine: chrome is a 400. Returns 404 tagged_not_available on deployments without PDF/UA output.

Frequently asked questions

Why did my PDF print {{ name }} literally?

literal_mode was true, or the request went to the v2 route on a deployment without v2 templating. Send the template to /api/v1/tools/html-to-pdf with a data object.

What does 422 missing_template_variables mean?

strict is on (the default) and the template uses variables that data does not contain; the response lists them in missing. Supply them, or send strict: false to render them empty.

How much does a render cost?

One credit on either route.