DoConure

Making a value fit the space you left for it

A placeholder may carry a formatting code after :::. It is always optional and only changes how the value is printed — never the value in your JSON.

WriteWhat it does
{{ contact.phone:::l:80 }} At most 80 characters. Cuts at the last whole word and adds an ellipsis, which counts towards the limit — so the result never exceeds the room you measured.
{{ address:::one }} Collapses line breaks and runs of spaces into single spaces. For a three-line address that has to sit on one line.
{{ iban:::wrap:20 }} Lets a long unbroken string — an IBAN, a URL, a product code — break across lines instead of running out of its column. Invisible: it adds break opportunities, not characters.
{% for line in invoice.lines:::max:50 %} On a loop: take at most 50 items. A table that receives five thousand rows becomes two hundred pages otherwise.

Codes may be chained: {{ notes:::one:::l:120 }}. A code we do not recognise is ignored and the value is printed unchanged, with a warning on the generation — a misspelled code costs you the formatting, never the document.

There are no bold, italic or underline codes. Make the placeholder itself bold in Word and the value comes out bold — the editor already does this, and a code would only duplicate it.

Number and date formatting: values are printed exactly as received. If you need 1,234.56 € or 10/09/2026, format them in the system that builds the JSON and send strings. Dates in particular: the document speaks your customer's language, and the service does not presume to know which.

Drawing a chart from the payload

A bar, line or pie chart, drawn from numbers in the payload. Works in Word and HTML templates, not in Excel.

{{ sales:::chart }}        <!-- 150 mm wide, the default -->
{{ sales:::chart:120 }}    <!-- 120 mm (40 to 180) -->

and in the payload:

{
  "sales": {
    "type": "bar",
    "title": "Revenue 2026",
    "labels": ["Q1", "Q2", "Q3", "Q4"],
    "series": [
      {"name": "Italy",  "values": [10, 12.5, 9, 14]},
      {"name": "France", "values": [4, 6, 7, 8]}
    ],
    "alt": "Revenue by quarter, Italy against France"
  }
}
  • type is bar, line or pie. A pie takes exactly one series of zero-or-more values.
  • Bounds: at most 6 series and 60 points (12 slices for a pie); labels and names at most 40 characters; values are plain numbers. Past a bound the chart is left out, with a warning, and the document is still produced.
  • The chart is drawn on our side. No address is ever fetched, and nothing in the spec can carry a style, a script or a link.
  • alt is the description a screen reader reads. Leave it out and one is built from the title and the data. Two or more series, and every pie, get a legend, so no meaning rests on colour alone.
  • A chart that cannot be drawn does not stop the document, in strict and lenient templates alike: it is left out and Validate and the generation's warnings say why. A field that is absent is the usual missing-field rule.

Putting a picture from the payload into the document

A photo of a receipt, a signature scan, a product shot — anything the payload carries rather than something already in the template.

{{ receipt:::img }}        <!-- 80 mm wide, the default -->
{{ receipt:::img:120 }}    <!-- 120 mm -->

and in the payload:

{
  "receipt": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ..."
}

It must be a data URI. Bare base64 is refused, and the reason is worth one sentence: a long run of letters is valid base64, so an ordinary text field would be mistaken for a picture and silently replaced by nothing. The data:image/jpeg;base64, prefix is one line to add in any language and removes the guesswork.

Send it at full size. Each image is checked to be a real PNG, JPEG or WebP and then resized down to fit a printed page — a 4000-pixel phone photo arrives as about a sixth of the bytes. Resizing before you send only costs quality, and the body limit is what you would be trying to avoid: it is 10 MB of JSON, and base64 inflates by about 37%, so roughly 7 MB of photos per call.

One unusable image costs that image, not the document. It is left out, the rest are placed, and the job records a warning saying how many. An expense note with ten receipts does not fail because the seventh was a screenshot of a screenshot.

Lists work the way every other list does:

{%p for picture in pictures %}
{{ picture.label }}
{{ picture.image:::img:150 }}
{%p endfor %}

Word templates only. In an HTML template there is nothing to place an image into, and you do not need this filter: put the same data URI straight into <img src=""> and it works. Using :::img in HTML leaves the space empty and says so in the job's warnings rather than failing quietly.

A URL is never fetched, in either engine. A link supplied by a caller and dereferenced by our server is a way into our own network, and that door is deliberately shut.

A misspelled code is one row in Common mistakes.