Guides
FinBaze keeps the official copy of every invoice, quote, reminder, payslip and year document. You choose how it looks, per document type, at one of three levels. Documents and rendering explains each; this guide is the order to do things in.
Pick a level#
| Level | When to choose it | Effort |
|---|---|---|
finbaze_layout | Your colours, fonts and logo are enough. | Small |
template | You want your own HTML for the page, rendered by FinBaze. | Medium |
partner | You already render PDFs and want one look everywhere. | Highest |
mutation { setPlatformDocumentRenderSetting(documentType: invoice, mode: finbaze_layout) { documentType mode timeoutSeconds } }
Whatever the level, required content (VAT number, address, invoice number, reverse-charge text) is checked. A rule the tax adviser has not confirmed gives a warning; others refuse activation, or reject your PDF, and FinBaze then falls back to its own layout.
1. A preset#
mutation Preset($layout: JSONObject!) {
upsertPlatformDocumentLayout(input: { documentType: invoice, name: "Acme classic", layout: $layout, companyEditable: unlocked_blocks }) {
id version status warnings { ruleId field message severity }
}
}
Check a layout before you save it with validateDocumentLayout(documentType: invoice, layout: …), then activatePlatformDocumentLayout(id: …, makeDefault: true). platformDocumentLayoutPreview(id: …) returns the HTML. A company can choose among your presets (chooseDocumentLayout) or edit the blocks you unlock.
2. A template#
mutation Template($source: String!, $css: String) {
upsertDocumentTemplate(input: { documentType: invoice, name: "Acme", source: $source, css: $css }) { id status version }
}
Then validateDocumentTemplate(id: …) renders twelve fixtures and checks the required content, and activateDocumentTemplate(id: …, makeDefault: true) works only after a pass. Templates are logic-less: placeholders, loops and conditions over the document data; scripts, iframes, remote images, @import and SVG with script are refused. documentTemplatePreview(id: …, fixture: "default") shows a render.
3. Render it yourself#
Set the mode to partner and subscribe to document.render_requested:
mutation { setPlatformDocumentRenderSetting(documentType: invoice, mode: partner, timeoutSeconds: 60) { mode timeoutSeconds } }
The event carries the job, the data model (never a BSN), a deadline and signed links to attachments such as the invoice UBL. Render the PDF and answer before the deadline:
mutation Attach($job: ID!, $pdf: String!) {
attachRenderedDocument(jobId: $job, pdfBase64: $pdf) { id status }
}
For larger files upload first (up to 10 MB, valid for an hour) and pass uploadId instead of pdfBase64. FinBaze scans the PDF (no scripts, no embedded files) and checks its text against the document's facts. Emails and payment pages wait for the job; after a rejection, a timeout or no answer FinBaze renders its own layout. Events: document.render_requested, document.render_rejected, document.render_failed, document.official_copy_created. documentRenderJob(id: …) shows a job.
4. Your own domain#
mutation { addPlatformCustomDomain(hostname: "pay.acme.nl") { id status } }
Create the DNS records the answer lists, then checkPlatformCustomDomain(id: …). FinBaze issues the certificate; custom_domain.status_changed follows the status. A company is served only on its own platform's domains.
Promote from the sandbox#
Presets and templates travel with the documents policy when you promote your configuration from the sandbox (previewPlatformPromotion, applyPlatformPromotion).
Try it in the sandbox#
Seed a company, finalise an invoice with upsertSalesInvoice(… finalise: true) and fetch it with companyDocument(company, kind: sales_invoice_pdf, …); the link works for 15 minutes without a token.
Pitfalls#
- Activating without validating: activation fails if the report has failures.
- Answering a
partnerrender after the deadline: the job has already fallen back. - Putting personal data you do not need in a template fixture.