DocGen: Dataverse document generation without a code release
Branded PDFs from your Dataverse records, through one API that your model-driven app, Power Automate, Code Apps and Power Pages can all call. Templates are configuration, and everything runs in your own Azure subscription.
€7,500 per production environment per year€625 a month equivalent, billed annually. Excl. VAT; implementation and Azure costs are additional.
See the finished documents
Two statements generated by DocGen: standard and credit balance. Sample data, anonymised branding.
In production today
Changing templates: before and after
The same request, a line moved on an invoice, under compiled templating and under DocGen.
- Client wants a line moved on an invoice
- A platform consultant edits compiled C# templating code
- 15–40 hours of build, test, and deploy per change
- ~€4,750 average per change, billed T&M
- Wait in the vendor's dev queue for a release
- Aspose.Words OEM licence + annual support on top
- Client wants a line moved on an invoice
- Edit template.html (Handlebars) or a FetchXML dataset
- Preview locally: npm run preview <code>
- Seed by alternate-key upsert — no code release
- Live in every channel that calls the API
- One change per quarter included; beyond that, a fixed price you can approve without a scoping call
Compare the cost of template changes
The typical firm changes its documents about six times a year — a rebrand, a new remittance block, a regulatory line, a field the partners want moved. Under compiled templating, every one of those is a project. Here is what six changes a year cost.
- 6 changes × ~€4,750 each
- Billed time & materials, per change
- Each one waits in a dev queue
- Cost grows with every change you ask for
- €7,500 platform — one production environment, every template in it
- 4 changes included, one per quarter
- 2 chargeable changes × €750
- Fixed price, quoted before you approve
- 68% less for the same six changes
- No dev queue between you and a corrected invoice
- Savings compound — the more you change, the wider the gap
Forty seconds, template edit to finished document
A recorded template change on the real production statement template: edit the Handlebars source, re-render, and see the change land in the document. In production the same edit ships by seed — an idempotent alternate-key upsert — with no compiled-code release.
What happens in this video
- A title card: a template change, start to finished document — real production template, real rendering pipeline, no code release.
- Step 1, edit the Handlebars template. In template.html for the account statement, the Invoice Detail table's “Reference” column header is changed to “Invoice No.”, because the client wants the column called Invoice No.
- Step 2, re-render. A terminal runs npm run preview account-statement-openchecks: Handlebars plus the enriched data tree become HTML, then Chromium turns it into the PDF.
- The re-rendered statement scrolls past with the same data in the new layout: letterhead, account summary, invoice detail, unapplied payments, aging summary and the payment and remittance panel.
- The change, live in the document: the Invoice Detail table now has an “Invoice No.” column where “Reference” was.
- In production, the same edit ships with npm run seed, an idempotent alternate-key upsert into Dataverse, and is live in every channel that calls sss_GenerateDocument. No compiled-code release, no dev queue.
39 seconds, no sound. Anonymised production statement template, synthetic data.
Technical details: the document pipeline
One call, seven stages
Your app calls a single unbound custom API with a template code and a record id. A thin plugin proxies it (Entra client-credentials) to the rendering container, which runs the pipeline and returns the finished PDF. Nothing is stored unless you ask for it — pass Attach to have the document written back to the record as a note.
// MDA / Power Automate / Code App → sss_GenerateDocument { "Code": "account-statement-openchecks", "EntityId": "a1f8c2e6-4b90-4d1e-9a77-3f0e5c8b2d14", "Attach": true // optional, default false — store a note on the record } // engine pipeline (in your Azure subscription) ▸ TemplateStore read sss_documenttemplate by sss_code ▸ DatasetRunner 4 FetchXML datasets in parallel // @entityId@ bound ▸ TreeBuilder nest child rows via sss_parentkeyfield ▸ Enricher totals, amountDue, aging buckets, credit-balance flag ▸ Handlebars template.html + data tree → HTML ▸ PdfRenderer HTML → PDF // Playwright Chromium ▸ DeliveryService annotation on the record // only when Attach=true // return { "fileName": "Statement_ACME-Corp_2026-07.pdf", "annotationId": "7c3d…e21a", "fileBase64": "JVBERi0xLjc…", // full PDF, ready to attach or download "warnings": null // non-fatal problems, e.g. a truncated dataset }
Technical details: engine capabilities
What's in the engine
A template is data, not code: manifest.json, FetchXML datasets, and a Handlebars template.html, seeded into Dataverse by idempotent alternate-key upsert.
Child sss_templatedataset queries run in parallel — 5,000-row pages, 50k hard cap — then nest into a JSON tree by parent key field.
Totals, amount due, credit-balance detection, aging buckets, and bill-address resolution — all the business logic, kept out of the templates.
Handlebars → HTML → pixel-faithful PDF via Playwright Chromium, with fonts baked into the container image.
Nothing is stored by default. Pass Attach and the run writes an annotation (note attachment) to the target record; the optional draft email is a per-environment flag — so you don't pay Dataverse file storage twice, or at all.
One unbound custom API — sss_GenerateDocument — from the model-driven app, Power Automate, Code Apps, and Power Pages.
Output=html returns the rendered layout without starting a browser; Output=data returns the enriched data tree as JSON, so template authors can see every field before writing a line of markup.
The dangerous failure is a document that renders successfully but wrongly. A truncated dataset or an unresolved parent key comes back in a warnings field instead of passing silently — branch on it rather than trusting HTTP 200.
Deployment, security and maintenance
Runs in your tenant, by design
No black-box SaaS holding your documents. DocGen deploys into your own cloud and talks only to your own data.
Your Azure subscription
Scale-to-zero Azure Container Apps (1 vCPU / 2 GiB). All-in run cost typically well under €900/yr at current Azure pricing — you pay Azure directly, and the actual cost depends on your region, tier and volume.
Your Dataverse & Entra ID
One app registration, client-credentials token. The container uses the same service principal as its Dataverse application user.
Secrets, and where they actually live
The container app reads its Entra client secret from Key Vault through its own managed identity — never checked in, never in logs. The Dataverse plugin needs its own copy, and the platform request it uses can't resolve Key Vault-backed variables, so that one is a Text environment variable you restrict to admins. We'd rather say so here than have your security reviewer find it.
Deliberately simple
No queues, no blob storage, no caching until real volume proves the need. Fewer moving parts to break.
100+ tests
Engine and integration coverage: happy path plus normal and credit-balance variants, verified against real sample data.
Managed & versioned
Monitoring, patching, Chromium and Dataverse-API compatibility maintenance. Dev and test environments are included at no charge — you should never be billed for good ALM.
High-volume invoices and statements
If you send invoices or statements in bulk
Two real jobs. Three ways to do them. The price that actually moves with volume is Power BI capacity, not DocGen.
Send invoices in bulk
-
SSRS / paginated
An RDL per document type. Bulk PDF uses exportToFile, and that API requires a workspace on dedicated Power BI Embedded, Premium, or Fabric capacity — it isn't optional. Premium Per User allows one export per five minutes, which is unusable for a thousand-plus invoices. A1 (~$735/mo) is a lab floor; real paginated load sits on A3/A4-class nodes. A layout change is another RDL release.
-
Word templates (platform)
A Power Automate loop — Populate a Word template, then Convert to PDF on the premium connector, once per invoice. Fine for a handful; a monthly batch is hundreds or thousands of runs. More in Dynamics 365 Word template limitations.
-
DocGen
One HTML template in Dataverse, sss_GenerateDocument per invoice, attach and send from a flow. No Power BI Embedded. No monthly document cap.
Send account statements in bulk
-
SSRS / paginated
Same three paths. A second RDL on the same expensive capacity.
-
Word templates (platform)
A second .docx and the same per-document loop.
-
DocGen
Clone the template, change the FetchXML. The €7,500 environment licence does not move.
| Path — licence only | 1,000 / mo12k / year | 5,000 / mo60k / year | 10,000 / mo120k / year |
|---|---|---|---|
| SSS DocGen€7,500 / year, flat — no Power BI Embedded, no monthly cap | €0.63per PDF | €0.13per PDF | €0.06per PDF |
| Power BI Embedded A3, 24/7US East estimate · ~$2,939/mo (~$35k/year) | $2.94per PDF | $0.59per PDF | $0.29per PDF |
| Power BI Embedded A4, 24/7US East estimate · ~$5,878/mo (~$70k/year) | $5.88per PDF | $1.18per PDF | $0.59per PDF |
Pricing
€7,500per production environment per year€625 a month equivalent, billed annually. Excl. VAT.
Not per user, not per document, and not by template count — the same number for a five-person team and a five-thousand-person one, because you aren't buying seats. Marginal cost per document is effectively zero because the infrastructure is yours, so metering volume would only be a tax on using the thing you bought. Dev and test environments are free. Everything else in this category makes you book a call to find out the price; we don't think a price is a negotiating position to protect until a salesperson has qualified you.
Platform
per production environment · billed annually| Line | Per month |
|---|---|
| SSS DocGen | €625 / month €7,500 / year, billed annually |
| SSS DMS — add-on to DocGen, not sold on its own | €375 / month €4,500 / year, billed annually |
| Both, same environment | €1,000 / month €12,000 / year, billed annually |
- Dev and test environments at no charge
- Every template in the environment — no bands, no count to report
- Monitoring and patching
- Chromium and Dataverse API compatibility maintenance
- Business-hours support, next-business-day response
- One template change per quarter
Changes
fixed price · no retainer| Line | Price |
|---|---|
| Template change — layout, wording, field swap | €750 |
| Block of 5 changes | €3,300 |
| Template change — new dataset or enrichment rule | €1,300 |
One-time
fixed price · per item| Line | Price |
|---|---|
| Deployment and onboarding, first environment | €5,500 |
| Each additional environment | €2,200 |
| New template — simple | €1,750 |
| New template — standard | €2,600 |
| New template — complex | €3,900 |
No per-seat creep. Per-seat document tools license every user with write access to a Dataverse table. Above roughly 300 users, that costs more than DocGen — and it keeps growing as the firm does. They also cap how many documents you may generate each month; DocGen has no document count at all.
Licensing never blocks a document. Documents are business-critical, so enforcement is deliberately soft: past renewal, whatever the state — the PDF still generates, and the discrepancy is flagged to us, not to your users. A licensing dispute should never stop a firm invoicing.
Building a Dataverse product with compiled templating inside it? There is an OEM lane: you embed the engine, resell at your price, and pay a wholesale per-environment rate. The terms — including the parts that might rule you out — are published. OEM and embed terms, on the partners page.
Questions buyers actually ask
Who owns the templates?
You do. A template is configuration — Handlebars markup and FetchXML rows — living in your Dataverse, readable and exportable at any time. If we part ways, your templates stay where they've always been.
What counts as a production environment?
Any Dataverse environment where real business documents are generated — typically one per legal entity. Dev and test environments are free, however many you run: we don't tax good ALM.
What's a change versus a new template?
A change edits a template you already have: layout, wording, or a field swap is €750; a new dataset or enrichment rule behind it is €1,300. A new template is a document class you don't have yet — €1,750–€3,900 by complexity, quoted before you approve.
Does the number of templates change the price?
No. One production environment is €625 per month, billed annually (€7,500/year), whether it runs three templates or fifty — templates are unlimited, and there's no count to report at renewal. If your library is very large we'll still say so — a library that size tends to hide near-duplicates, and rationalising it makes the thing easier to own — but it's advice, not an invoice.
Where do the generated PDFs live?
They're rendered in your Azure subscription and returned to the caller — nothing is stored by default, and nothing leaves your tenant. Pass Attach and the PDF is written to the record as a note, in your Dataverse, under your retention rules.
Why isn't pricing per document?
Because your documents cost us nothing. The engine runs scale-to-zero on your own infrastructure, so a per-document meter would just be a tax on using the thing you bought. The only meter that tracks real cost is the environment — so that's what you pay for: €625 a month, billed once a year, at a number you can read on this page. At 10,000 invoices a month the flat licence works out at €0.06 per PDF, and it keeps falling as you send more.
Tell us about your documents
The fastest route to a useful answer: tell us what you generate today, what it's built on, and how often it changes. We'll come back with whether DocGen fits, what it would cost you, and what it wouldn't solve — before anyone books a call.
Which documents, which system generates them now, roughly how often they change, and how many production environments you run. That's enough for us to answer properly.
Runs in your tenantData Processing AgreementSecurity overview
- Controller. Simple Smooth Safe, Unipessoal Lda., Rua Retiro dos Pacatos 50, Ed. Startup, Sala 9, 2635-224 Rio de Mouro, Portugal. NIF/VAT PT518264742. Questions or requests: info@simplesmoothsafe.com.
- What we hold. Your name, email address, whatever you chose to tell us about your organisation, and the correspondence itself.
- Purpose. To answer you, and to follow up on the specific thing you asked about.
- Legal basis. Legitimate interest (Art. 6(1)(f)) in responding to an enquiry you initiated, or steps prior to entering a contract (Art. 6(1)(b)) where you are asking to buy.
- Retention. Up to 24 months after our last exchange, then deleted — unless you become a customer, in which case section 1.4 applies.
- Your rights. Ask for access, correction or deletion, or object, at any time by emailing us. Full detail in the Privacy Policy, section 1.2.
- Controller. Simple Smooth Safe, Unipessoal Lda., Rua Retiro dos Pacatos 50, Ed. Startup, Sala 9, 2635-224 Rio de Mouro, Portugal. NIF/VAT PT518264742. Questions or requests: info@simplesmoothsafe.com.
- Where it goes. The form is hosted on Microsoft Forms. It collects your name, work email, company, tenant or environment details, and whether you are a partner or an end client.
- Purpose. To contact you about the product you asked about — early access, availability, or a demo. That is the only thing it is used for.
- Legal basis. Consent (Art. 6(1)(a)), given by ticking the box on the form.
- Retention. Until you withdraw consent, or until the programme you signed up for closes, whichever is first.
- Withdrawing. Email us. No reason needed, no effect on anything else, and no retention "for our records". Full detail in the Privacy Policy, section 1.3.
Prefer email? info@simplesmoothsafe.com reaches the same place, under section 1.2 of the Privacy Policy.