30 documents a month, free, no card

Your template, your JSON.
The filled document out.

DocMint fills Word, Excel and PowerPoint templates from a JSON payload and returns the Office file, a PDF, or both — in one request. It will also tell you, before you ever send data, exactly which fields the template needs.

  • .docx .dotx .docm
  • .xlsx .xltx .xlsm
  • .pptx .potx .ppsx .pptm

One syntax across all three. Both {name} and {{name}} work, everywhere, always.

# A saved .docx and your data. The PDF comes straight back.
curl -X POST https://docmint-832s.onrender.com/v1/render \
  -H "Authorization: Bearer dm_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{"template":"quote",
       "data":{"customer":"Acme GmbH","total":1240.5},
       "output":"pdf"}' \
  --output quote.pdf
HTTP 200 content-type: application/pdf content-length: 13660 x-docmint-credits-remaining: 28
17–27 ms
Server-side time to fill a three-line-item Word template, five consecutive live requests.
2.7 s
Added by the optional PDF step. LibreOffice, half a CPU — this is the number a customer gets.
$0.00145
Per document on the $29 Pro plan — 20,000 documents a month.

Measured on the live service on 25 August 2026, from the stats.stages object the API returns on every render. The first request after an idle period took 53 ms; the PDF path is one instance with a queue of one, so a busy moment queues rather than slows. DocMint is new — these are the only numbers there are, so they are the only ones quoted.

The thing nobody else does

It tells you what the template needs

Every document generator joins your data to your template by invisible string matching, and the placeholder names live inside a zipped binary a workflow cannot open. So the loop is: guess the keys, render, open the file in Word, find the silently empty field, guess again.

DocMint answers the question directly, and not with a flat list of names: a typed, nested field list that knows qty lives inside items and wants a number, plus a ready-to-POST sample_data skeleton.

GET /v1/templates/:name/fields is a first-class endpoint. It costs nothing and produces no document, because charging for the one call that prevents a bad render would be perverse.

It works by running the template through the real renderer with no data and a probe attached, so the answer is by construction exactly what a render would ask for — the same scope rules, the same section semantics, no second parser to drift.

  • The sample it hands you renders. Verified against the live API: POST /v1/inspect, then POST /v1/render with the sample_data it returned, produced a document with zero warnings on the first try.
  • Carbone's API has no template-introspection endpoint. Its GET /templates/tags returns organisational folder labels, not placeholders.
  • Every existing n8n node in this space ships a raw JSON textarea. The official n8n-nodes-carbone declares {name:'data', type:'json', default:'{}'}; so does n8n-nodes-docxtemplater. n8n-nodes-fill-docx is worse — a plain string you must JSON.stringify yourself.
  • Formstack's management API does return the field list on template create — which proves the demand — but it is not surfaced in any automation UI.
POST /v1/inspecta .pptx, uploaded inline0 credits
{
  "format": "pptx",
  "fields": [
    { "name": "client.name", "scope": "", "type": "string",
      "repeating": false, "required": true,
      "formatters": [], "used": 4,
      "locations": ["slide 1, shape \"Subtitle 2\"",
                    "slide 2, shape \"Heading 4\""] },
    { "name": "rows", "scope": "", "type": "array",
      "repeating": true, "required": true,
      "formatters": ["count", "sum", "currency"], "used": 6,
      "locations": [
        "slide 2, table \"Items 5\", row 1, cell 3",
        "slide 2, table \"Items 5\", row 3, cell 2",
        "slide 2, table \"Items 5\", row 3, cell 3"] },
    { "name": "amount", "scope": "rows", "type": "number",
      "repeating": false, "required": true, "used": 1,
      "formatters": ["currency"],
      "locations": [
        "slide 2, table \"Items 5\", row 2, cell 3"] }
  ],
  "names": ["title","subtitle","client.name","logo","notes",
            "rows","sku","qty","amount","findings","label",
            "detail","owner"],
  "sample_data": {
    "title": "title", "subtitle": "subtitle",
    "client": { "name": "name" },
    "logo": null, "notes": "notes",
    "rows":     [{ "sku": "sku", "qty": "qty", "amount": 0 }],
    "findings": [{ "label": "label", "detail": "detail",
                   "owner": "owner" }]
  }
}

From the live API on 25 August 2026, abridged: the real response lists all 13 fields and 26 tags. scope is what makes it a tree — amount lives inside rows, not at the root — and sample_data is a skeleton you can POST straight back. An image comes back as null, because DocMint cannot invent a picture for you.

The failure this product exists to prevent

It refuses to render a document with a missing field

A document that renders a placeholder as an empty cell, or as the literal text undefined, is worse than no document at all — because nobody notices until it has been emailed to a customer.

POST /v1/renderHTTP 4220 credits — the reservation is refunded
{
  "error": {
    "code": "placeholder_unresolved",
    "message": "The template uses {price|currency} but
                the data has no \"price\".",
    "hint": "Add \"price\" to the data, or write
             {price|default:} to allow it to be absent.",
    "docs": "https://docmint-832s.onrender.com/docs#errors",
    "details": {
      "field": "price",
      "location":
        "word/document.xml, table 1 row 2, paragraph 7",
      "available": ["invoice_no","customer","items",
                    "description","qty"],
      "format": "docx"
    },
    "request_id": "dm_IHD7M11U8enL"
  }
}

Every failure carries the field name, the place it was written, the field names that do exist at that point in the data, and — when the name is close enough to be a typo — a "did you mean".

  • The location is where a human would look. word/document.xml, table 1 row 2, paragraph 7 in Word, Invoice!C5 in Excel, slide 2, table "Items 5", row 2, cell 3 in PowerPoint. All three are real strings from the live API.
  • docxtemplater writes the literal word "undefined" into the document by default, and sells finding out where a tag failed as a separately-licensed 500 EUR/year module.
  • A typo'd tag in Carbone does not error; it renders blank.
  • A failed render costs no credits. The reservation is taken before the work and refunded when the work fails.

A value that is present but null renders as empty — you said "nothing here" and were believed. {x|default:—} is the sanctioned opt-out, and onMissing: "empty" relaxes the rule wholesale if you really want it.

The bug that prints the same value on every row

It warns when a tag inside a loop came from outside it

Scopes nest outwards, so inside {#items} a tag can legitimately reach the invoice's {currency} at the root. That convenience has a nasty edge: if your rows have product_name and you write {name}, and name happens to exist at the root, every row silently prints the same value. Nothing errors. The document looks plausible. It is wrong.

DocMint still allows it — {currency} from the invoice root is a reasonable thing to write — but it reports every occurrence back in the render response, naming the field, the location, and the fields the loop item actually has. Setting strictScope: true turns the warning into a 422.

  • No competitor reports this. docxtemplater's own documentation presents {#products}{name}{/products}, where name exists only at the root, as normal behaviour.
  • When the outer name looks like a typo of an item field, it is an error, not a warning. Reaching outwards for something the item nearly has is not a deliberate reach.
POST /v1/renderHTTP 200 — the file is returnedx-docmint-warnings: 1
"warnings": [
  {
    "code": "resolved_from_outer_scope",
    "field": "currency",
    "location":
      "word/document.xml, table 1 row 2, paragraph 5",
    "message": "{currency} is not a field of the loop item;
                it was taken from 1 level further out, so it
                prints the same value on every row.",
    "item_fields": ["title", "amount"]
  }
]
the same request with "strictScope": trueHTTP 422
{
  "code": "placeholder_outside_loop",
  "message": "{currency} is not a field of the loop item.",
  "hint": "strictScope is on, so a tag inside a loop must
           name a field of the item. Write {../currency} if
           you meant the value from outside the loop.",
  "details": {
    "field": "currency", "available": ["title", "amount"],
    "location":
      "word/document.xml, table 1 row 2, paragraph 5" }
}

Three steps, and the second one is optional

How it fits together

You author the template in Word, Excel or PowerPoint — the tool your finance team already uses — and type placeholders into it. There is no template editor to learn and no proprietary format.

  1. Upload it once, or send it inline

    POST /v1/templates stores it under a name you choose, and every upload is a new version. Or skip storage entirely and send the file as template_base64 on every render.

  2. Ask what it needs

    GET /v1/templates/:name/fields returns the placeholder list with locations. Free, and it never throws on a field you have not supplied yet.

  3. Render

    POST /v1/render with your data. Ask for document, pdf or both — per request, not per template.

one syntax

Both brace styles

{name} and {{name}} both work in all three formats. A template written for docxtemplater and one written for Docupilot both render unchanged; no third syntax was invented.

43 formatters

Totals computed, not typed

{items|sumProduct:qty:price|currency}. An invoice template that writes its own total is an invoice template that is wrong the first time a line changes.

split runs

Real-world templates

Word stores {{na+me}} as two runs the moment you edit the middle of a word. Every part is flattened and re-sliced, so a template that has been through Google Docs still works.

spreadsheets

Numbers stay numbers

A cell holding the text "1234.5" is not a number: SUM() over a column of them returns 0 and nothing warns anybody. A cell that is one placeholder resolving to a number becomes a real numeric cell, keeping its format.

Against the Office document generators

What is actually different

Everything in this table was read off the vendors' own documentation and pricing pages, and everything in the DocMint column is verifiable against the live API on this domain.

DocMintCarboneDocupilotFormstack Documents
Tells you the template's fields Yes — GET /v1/templates/:name/fields, free No introspection endpoint Not published On template create, via the management API — not in any automation UI
A placeholder your data does not have HTTP 422, naming the field and its location Renders blank, no error Not published Not published
Loop tag resolved from an outer scope Warned on every render; an error under strictScope No competitor reports it
Output format Per request — document, pdf or both Per request Fixed per template in their dashboard Not published
Billing unit One credit per document produced; a PDF costs one more Payload size: (JSON + images + PDF bytes) / 1,000,000. A 2.3 MB render costs 3 documents. Per delivery. "Downloading generated document also consumes 1 credit." Per delivery
At the quota ceiling 402 until the next calendar month; no overage billing Not published Hard stop: "You will not be able to generate documents once you have hit 100% limit." Not published
Entry price $9 / 2,000 docs = $0.0045 EUR 29 / 1,000 = EUR 0.029 $29 / 100 = $0.29 $250/mo annual / 250 deliveries = $1.00+

Scroll the table sideways to see every column.

Sources: each vendor's published pricing and documentation, read on 25 August 2026. "Not published" means exactly that — the vendor does not document the behaviour, and it was not guessed at. Deliberately absent from this table: APITemplate.io, which is often listed as a competitor here but has no Word, Excel or PowerPoint support of any kind — its live v2 API contains no docx endpoint and cannot accept a .docx even as input. Comparing against it on Office features would be a false comparison, so it is not made.

Pricing

One credit per document

A document costs one credit. Converting it to PDF costs one more, because LibreOffice costs roughly a hundred times the CPU of the fill itself and pretending otherwise would mean the cheap path subsidising the expensive one. Nothing else is metered — asking what fields a template needs is free, and so is downloading a template you already uploaded.

Free
$0 /month
30 documents a month
no card, self-serve over the API

Enough to wire a workflow end to end and see it work before deciding anything.

Get a key
Starter
$9 /month
2,000 documents a month
$0.0045 per document

A steady invoice or report flow out of one workflow.

Start a subscription
Pro
$29 /month
20,000 documents a month
$0.00145 per document

The same $29 that buys 100 documents at Docupilot buys 20,000 here.

Start a subscription
Scale
$99 /month
100,000 documents a month
$0.00099 per document

Bulk statement, payslip and certificate runs.

Start a subscription
Every plan has every feature. All three formats, PDF output, images, the typed field list, the missing-field contract, the outer-scope warning, template versioning and rollback, localisation, and the same limits: 25 MB per template, 8 MB of data per request, 20 versions kept per template, 120 requests a minute with a burst of 30. There is no feature ladder and no paid module — the limits are all here.

Quotas are per calendar month and reset on the 1st. A failed render is refunded, so a 422 on a missing field costs nothing. How quota works.

Read this before you build on it

What DocMint does not do yet

Not everything is in our favour, and a landing page that only lists strengths is a landing page you will find out the truth about later, at a worse moment.

No rich text, QR codes, maps or dynamic PDF passwords Docupilot has all four — HTML and Markdown into a DOCX included. DocMint writes plain text, numbers, images and raw OOXML. If you need HTML flowed into a Word document, DocMint is not the tool today.
Carbone's formatter library is larger than ours Theirs includes aggregates such as aggSum and cumSum, an i18n system, currency conversion at live rates, and drop/keep block operators. Ours is 43 formatters covering the common cases.
LibreOffice is the only PDF converter Carbone lets you choose between LibreOffice, OnlyOffice, Chromium and their own engine, and offers PDF/A, watermarking and PDF encryption. DocMint has none of that: one converter, one PDF profile, ~2.7 s per conversion, one at a time per instance.
No delivery integrations Carbone and Docupilot will email the document, or drop it in Drive or S3. DocMint returns the file and expects your workflow tool to do the delivering. For an n8n or Make user that is the right split — but it is a difference, not a strict advantage.
No charts, styling API, footnotes or subtemplates These are not implemented. Whatever styling the placeholder carries in the template is inherited by the value that replaces it, and that is the whole styling story.
Macro-enabled templates lose their macros A .docm, .xlsm or .pptm is filled correctly, but the macros are not guaranteed to survive the rewrite and the file comes back with the plain content type. The render response says so, as a warning.
Formula rewriting in spreadsheets has known edges A range whose two ends are the same repeated row — SUM(B3:B3) over a per-group subtotal — widens to cover the rows in between. Chart series and pivot caches keep their own copies of ranges and are not rewritten. Column loops and sheet loops are not supported at all.
There is no web dashboard Everything is the API: keys are managed with POST /v1/keys and DELETE /v1/keys/:prefix, usage with GET /v1/usage, and a subscription is started with POST /v1/billing/checkout, which hands back a Stripe URL to open. There is also no self-service account deletion; that is a request by email today.
The n8n node is written but not published n8n-nodes-docmint exists in the repository and is not yet on npm, so it cannot be installed today. Until it is, the API is a plain HTTP call from any workflow tool.
No SLA, one region, one instance The service runs in Frankfurt on a single small instance and restarts on every deploy. There is no third-party uptime monitor and no SOC 2 report. If an hour of downtime would damage your business, this is not yet the right dependency.

Questions

The ones that come up first

What does a template look like?

A perfectly ordinary .docx, .xlsx or .pptx with placeholders typed into it: {customer.name}, {{invoice_no}}, {#items}…{/items} around a table row, {%logo} where a picture goes. Nothing else changes; the file still opens in Word, and your finance team can keep editing it.

Do I have to upload the template?

No. Send it as template_base64 on the render call and nothing is stored. Uploading it once and referring to it by a name you choose is usually nicer, because replacing the letterhead then does not mean editing every workflow that used it.

What happens if my data has an extra field the template does not use?

Nothing — extra data is ignored. It is the other direction that is an error: a placeholder with nothing behind it.

Does a failed render cost a credit?

No. The credit is reserved before the work and refunded if the work fails, so a 422 on a missing field costs nothing.

Are my documents stored?

Rendered documents are never written to the database — they are produced in memory and returned in the response. Templates you upload are stored, because that is what uploading them means. The privacy policy lists every row of every table.

Why is the PDF so much slower than the Office file?

Because it is a different kind of work. Filling a template is XML surgery in a few milliseconds; converting to PDF is a full LibreOffice process, measured at about 2.7 s on this instance and 219 MB of peak memory. That is also why a PDF costs two credits and why conversions run one at a time.

Which brace style should I use?

Whichever you already type. {name} is the docxtemplater and Carbone style; {{name}} is the mustache and n8n style. Both work everywhere, and {{[Field With Spaces]}} works too, because that is the Docupilot form.

Is anything in my template or data used to train a model?

No. Nothing is read, mined, sold or used to train anything, and the service sends no email at all.

Fill your first template in about a minute

Sign up over the API, upload a .docx, ask it what fields it needs, and render. Thirty documents a month, free, no card.

Who runs this

DocMint is built and operated by productivity-boost.com Betriebs UG (haftungsbeschränkt) & Co. KG in Passau, Germany. It is new, it is small, and the honest limits are listed above rather than buried in a footnote.

The document fill engine has no third-party dependencies — no docxtemplater, no Carbone, no JSZip. The only external program is LibreOffice, run as a separate process for the optional PDF step. The full list is in THIRD-PARTY-NOTICES.md.