# mergedocx > mergedocx is a hosted HTTPS API for generating Microsoft Word (`.docx`) > documents from a server. It does two things: (1) **merge** N `.docx` files > into one clean document, and (2) **render** a Word template from JSON data > using placeholders, `{{#if}}` conditionals, and `{{#each}}` loops. The > Go-native engine produces output that opens without a repair dialog in > Microsoft Word on both Mac and Windows. mergedocx is for developers who generate finished Word documents from a backend — contract and agreement generation, mail-merge at volume, report and packet assembly — without running Microsoft Office or a LibreOffice sidecar. It is **language-agnostic**: any stack that can make an HTTPS request can use it (Go, Node.js, Python, Ruby, PHP, .NET, …). The finished `.docx` is streamed back in the same response; nothing is stored server-side. ## Base URL and authentication - **Base URL:** `https://mergedocx-production.up.railway.app` - **Auth:** `Authorization: Bearer ` on every request. Create keys in the dashboard at . ## API endpoints - **`POST /v1/merge`** — a base template + N source `.docx` fragments → one merged `.docx`. Reconciles conflicting styles, preserves every section's headers/footers, continues page numbering, de-duplicates embedded media and fonts. - **`POST /v1/render`** — one template + one JSON `data` object → one filled `.docx`. - **`POST /v1/render_batch`** — one template + a `records` array → a `.zip` of rendered documents, or a single merged `.docx` when `merge: true`. - **`POST /v1/template/inspect`** — returns the placeholders a template exposes (key, syntax, count) without rendering. Templates and source documents are sent per request (stateless), each via one of three transport modes: inline base64 bytes, a path reference under the server's template root, or a content hash (to skip re-uploading an unchanged file). ## Merge example Combine a cover template and two section documents into one `.docx`: ```bash curl -X POST https://mergedocx-production.up.railway.app/v1/merge \ -H "Authorization: Bearer $MERGEDOCX_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "base_docx_ref": "templates/cover.docx", "replacements": { "client_name": "Acme Ltd", "date": "2026-04-20" }, "documents": [ { "docx_ref": "sections/terms.docx" }, { "docx_ref": "sections/pricing.docx" } ] }' --output merged.docx ``` Response: `200 OK` with the merged `.docx` bytes and an `X-Merge-Stats` header. `replacements` fills `«KEY»` / `[[KEY]]` / `{{KEY}}` placeholders in the base; each fragment may carry its own `replacements`. ## Render example Fill a template that contains `Policy {{policy_no}}`, an `{{#if flood}}` clause, and a `{{#each items}}` table row: ```bash curl -X POST https://mergedocx-production.up.railway.app/v1/render \ -H "Authorization: Bearer $MERGEDOCX_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "template_bytes": "'"$(base64 < schedule.docx)"'", "data": { "policy_no": "P-100", "holder": { "name": "Acme Ltd" }, "flood": true, "flood_limit": "$5M", "items": [ { "desc": "Buildings", "sum": "$5M" }, { "desc": "Contents", "sum": "$1M" } ] } }' --output policy.docx ``` Returns a `.docx` with the placeholders filled, the flood clause kept, and the one template row expanded into two rows. ## Template syntax (render) - **Placeholders:** `{{key}}`, `«KEY»`, or `[[KEY]]` — a bare data key fills all three spellings. Nested data uses dotted paths: `{{holder.name}}`. - **Conditionals:** `{{#if key}} … {{/if}}` keeps a block when `key` is truthy; `{{#unless key}} … {{/unless}}` is the inverse. Each marker sits on its own paragraph/line (paragraph-level granularity). - **Loops:** `{{#each items}} … {{/each}}` repeats a table row or a paragraph block once per array element; formatting is preserved because the whole unit is cloned. Inside, `{{field}}` reads the current element and outer keys still resolve (element fields shadow same-named outer keys). - **Missing keys** are left verbatim and the fill call always returns `200` (lenient policy). **Structural mistakes** — an unbalanced marker, a loop over a non-array, or a marker crossing a table/cell boundary — fail closed with a `400`; the API never returns a corrupt `.docx`. ## How mergedocx compares - **vs docxtpl (Python / Jinja2):** docxtpl is an in-process Python library — you run it inside a Python service and template with Jinja2 syntax. mergedocx is a **language-agnostic HTTP API** (call it from any stack, no Python runtime), and the *same* service also **merges** documents and hardens Word-for-Mac compatibility. Both fill Word templates with placeholders, conditionals, and loops; mergedocx trades in-process control for a hosted API plus merge and cross-Word correctness. - **vs Aspose.Words:** Aspose is a commercial .NET / Java SDK with per-developer / per-site licensing. mergedocx is Go-native, called over HTTP, with flat subscription pricing and no SDK to embed. - **vs docxcompose / python-docx:** open-source Python — docxcompose merges, python-docx is a low-level document builder. mergedocx handles the Word-Mac open-and-save edge cases and adds template logic (conditionals, loops) in one API. - **vs LibreOffice headless:** no Office or LibreOffice process to run, license, or scale — mergedocx is a stateless HTTPS call. Full comparison matrix: ## Docs - [Template engine documentation](https://mergedocx.dev/docs): full syntax reference, quick-start `curl`, endpoint table, and a downloadable working sample template. - [Sample template (.docx)](https://mergedocx.dev/samples/template-demo.docx): a one-page schedule using nested fields, `{{#if}}`, and `{{#each}}`. - [Comparison vs Aspose, unidoc, docxcompose, CloudMersive](https://mergedocx.dev/comparison). - [Pricing](https://mergedocx.dev/pricing): plans and per-call allowances.