Office-authored templates
Fill tagged DOCX, XLSX and PPTX files while retaining authored OOXML styles,
headers, footers, lists, section settings, formulas and embedded media. Save in
standard Transitional OOXML. Strict OOXML, macros and encryption are rejected.
Enable OFFICE_TEMPLATES_ENABLED=true. Native output needs no Office installation;
PDF output uses the optional Gotenberg LibreOffice sidecar.
Tags and scoping
Put {{customer.name}} in text or a cell. Split Word/PowerPoint text runs are
normalized with the first run’s formatting; smart quotes inside tags are
normalized. Shared helpers include {{currency total "EUR"}} and
{{date issued "long"}}. Values are XML escaped. Triple braces, partials and
prototype access are rejected.
{{#each lines}} ... {{/each}}repeats content.{{#if approved}} ... {{else}} ... {{/if}}selects content.{{#with customer}} ... {{/with}}changes the current object.- Loops support
{{name}},{{@index}},{{../customer.name}}and{{@root.customer.name}}. - A block within one paragraph repeats inline. Across sibling paragraphs it repeats the paragraph band. Across cells in one table row it repeats that row; across sibling rows it repeats the row band.
- Control-only paragraphs/rows are removed. A structural
elseneeds its own paragraph or row. Blocks cannot cross tables, parts or unrelated parents. - PowerPoint supports text, table rows, paragraph bands and pictures. Slide repetition is not supported.
Lint reports part/paragraph, sheet/cell or slide/shape locations and nearby schema paths for unbound tags. Omitted schemas are inferred as a draft: loops become arrays and leaves become strings. Review numeric/date types before use. Use explicit paths rather than block aliases for schema inference.
Images
Set an embedded picture’s alt text to exactly {{image logoUrl}}. Supply a
tenant-owned asset reference or base64 image data URI. Remote protocols are
rejected. Original frame size and crop remain. SVG input is sanitized and
rasterized for compatibility. Images are limited to 20 MB.
Excel values and formulas
A cell containing one tag receives a numeric or boolean value when data has that
type. A date-styled cell receives an Excel date serial, including the workbook’s
1904 date system. Authored styles and number formats remain. Other values stay
strings; a string beginning with = never becomes a formula.
Row bands expand and rows/cells are renumbered. Formula references, merges,
dimensions, tables, filters, conditional-format/data-validation ranges and defined
names shift. A range covering the band expands: SUM(D7:D7) becomes
SUM(D7:D16) for ten items. Shared formulas are resolved before expansion. Cached
formula values and calculation chains are removed and a full calculation is
requested on open. Chart references shift and pivot caches request refresh.
Complex workbooks need representative Excel validation. Structured formulas, dynamic arrays, drawings around repeated bands, external workbooks and pivot layouts are outside the initial fidelity guarantee. Native output retains links; PDF conversion removes external relationships from a copy and runs without egress.
API
| Operation | Endpoint |
|---|---|
| Create | POST /templates/office |
| Replace source/metadata | PUT /templates/{key}/office |
| Download original | GET /templates/{key}/office/source?version= |
| Inspect tags | GET /templates/{key}/office/tags?version= |
| Stateless lint | POST /templates/office/lint |
Authoring/source endpoints require tenant-scoped template permissions. Create,
replace and lint accept multipart file and meta; meta is a JSON object encoded
as a string. Create requires key and name. Optional metadata includes
description, version, inputSchema, fieldMappings, dataOptions, parameters,
dataSources, i18n and locale-only renderConfig. Lint accepts inputSchema.
Replace requires a quoted current-version If-Match. Replacing creates a version;
JSON metadata updates cannot switch between Office and visual kinds.
| Source | Native | HTML/CSV/other native formats | |
|---|---|---|---|
| DOCX | DOCX | Gotenberg | 422 office_format_unsupported |
| XLSX | XLSX | Gotenberg | 422 office_format_unsupported |
| PPTX | PPTX | Gotenberg | 422 office_format_unsupported |
Use existing production, batch, async-job, scheduled-render, label and variant
endpoints. PPTX output also requires PPTX_ENABLED and tenant feature permission.
dryRun fills/validates without returning an artifact or requiring PDF conversion.
Missing conversion returns 503 office_conversion_unavailable; rejected, timed
out or invalid conversion returns 502 office_conversion_failed.
POST /render/preview/office accepts {template, version?, data, format} and returns
a private uncached binary. Preview routes must be enabled separately.
Private storage and lifetime
Source bytes are content-addressed by SHA-256 and tenant scoped. Set
TEMPLATE_SOURCE_DIR (default ./template-sources) or a private
TEMPLATE_SOURCE_BUCKET using configured S3 credentials. No public source URL is
exposed, including when image assets are public. Preserve source storage alongside
template metadata.
Versions, labels and restores reference immutable hashes. Trash and private drafts retain sources. Permanent template purge collects blobs without any remaining tenant version/draft reference. Database gates coordinate publication and collection across replicas; file mode supports one API process. Tenant purge removes private sources. Portable backups and tenant export/import/clone include and verify source bytes/hashes.
Limits and licensing
Default uploads are limited to 20 MB (OFFICE_TEMPLATE_MAX_BYTES, maximum 100 MB).
Packages are limited to 2,000 entries, 100 MB expanded input, 20 MB per XML part,
250,000 XML nodes/attributes and nesting depth 128. Unsafe paths, checksums,
DOCTYPEs and invalid blocks are rejected. Expansion is bounded to 10,000
evaluation steps and 100 MB output. PDF conversion defaults to 60 seconds
(OFFICE_PDF_TIMEOUT_MS) with bounded, signature-checked responses.
Unlicensed builds mark Word section footers, Excel sheets/print footers and every
PowerPoint slide. Rendering/conversion remain commercial. Read-only parsing,
normalization, tag analysis and linting bundled in the MIT CLI are MIT licensed;
see module licensing.
Run offline:
pulp-engine office lint contract.docx --schema schema.json --strict
The command prints JSON and fails for invalid files/tags. --strict also fails
for unbound-path warnings.