Skip to Content
GuidesTemplates

Templates

Templates let you define a reusable document layout — signer roles, field positions, and merge variables — so you can generate ready-to-sign documents without reconfiguring fields each time.

How Templates Work

  1. Upload a PDF or DOCX file as the base document
  2. Define signer roles (e.g., “Client”, “Approver”) — these are placeholders that get assigned to real people when you create a document
  3. Place fields on the template and assign each to a signer role
  4. Create documents from the template by mapping real signers to roles

Creating a Template

Template creation follows the same two-step upload flow as documents:

import { KoralaClient } from '@korala/api-client'; import fs from 'fs'; const korala = new KoralaClient({ apiKeyId: 'your-api-key-id', apiSecret: 'your-api-secret', }); // Step 1: Get upload URL const { templateId, uploadUrl, key } = await korala.templates.createUploadUrl({ filename: 'nda-template.pdf', contentType: 'application/pdf', }); // Step 2: Upload the file const pdfBuffer = fs.readFileSync('nda-template.pdf'); await fetch(uploadUrl, { method: 'PUT', body: pdfBuffer, headers: { 'Content-Type': 'application/pdf' }, }); // Step 3: Confirm and set metadata const template = await korala.templates.confirmUpload(templateId, { name: 'NDA Template', description: 'Standard non-disclosure agreement', }); console.log(`Template created: ${template.id}`);

Templates support both PDF and DOCX files. DOCX files are automatically converted to PDF for preview, and merge fields ({{placeholder}}) are detected automatically.

Signer Roles

Signer roles are named placeholders that define who needs to sign, without specifying the actual person. When you create a document from a template, you map real signers to these roles.

Adding Roles

// Add roles with signing order const client = await korala.templates.addSignerRole(templateId, { name: 'Client', signingOrder: 1, }); const approver = await korala.templates.addSignerRole(templateId, { name: 'Approver', signingOrder: 2, });

Managing Roles

// List all roles const roles = await korala.templates.getSignerRoles(templateId); // Update a role await korala.templates.updateSignerRole(templateId, roleId, { name: 'Company Representative', signingOrder: 2, }); // Delete a role await korala.templates.deleteSignerRole(templateId, roleId);

Template Fields

Fields define where signers need to fill in information. Each field is positioned on a specific page and assigned to a signer role.

Adding Fields

// Add a signature field for the Client role await korala.templates.addField(templateId, { signerRoleId: clientRoleId, fieldType: 'signature', pageNumber: 1, xPosition: 100, yPosition: 650, width: 200, height: 50, }); // Add a date field await korala.templates.addField(templateId, { signerRoleId: clientRoleId, fieldType: 'date', pageNumber: 1, xPosition: 350, yPosition: 650, width: 150, height: 30, }); // Add a text field with a merge variable await korala.templates.addField(templateId, { signerRoleId: clientRoleId, fieldType: 'text', pageNumber: 1, xPosition: 100, yPosition: 200, width: 300, height: 30, mergeFieldName: 'company_name', defaultValue: 'Acme Corp', });

Field Types

TypeDescription
signatureDrawn or uploaded signature image
initialsSigner’s initials
dateDate value
textFree-text input
checkboxBoolean checkbox

Managing Fields

// List all fields const fields = await korala.templates.getFields(templateId); // Update field position or assigned role await korala.templates.updateField(templateId, fieldId, { xPosition: 150, yPosition: 700, signerRoleId: newRoleId, }); // Delete a field await korala.templates.deleteField(templateId, fieldId);

DOCX Merge Fields

When you upload a DOCX template, Korala automatically detects {{placeholder}} merge fields in the document text. These are substituted with real values when generating documents.

// Get detected merge fields const mergeFields = await korala.templates.getMergeFields(templateId); console.log(mergeFields); // [ // { name: 'company_name', occurrences: 3 }, // { name: 'effective_date', occurrences: 1 }, // { name: 'client_address', occurrences: 2 }, // ]

Merge fields are only available for DOCX templates. PDF templates use positioned fields instead.

Anchor Placement (DOCX)

Absolute xPosition/yPosition coordinates are fragile on DOCX templates: when merge fields are substituted, the document reflows and repaginates, so a coordinate captured against the preview may no longer line up. Anchor placement fixes this — a field anchors to a literal string in the document body and is positioned wherever that string actually renders, regardless of reflow or page count. This is the same model as DocuSign “anchor tabs”.

Set placement: 'anchor' and provide an anchorText:

await korala.templates.addField(templateId, { signerRoleId: fundLeadRole.id, fieldType: 'signature', placement: 'anchor', anchorText: 'Fund Lead Signature:', anchorPosition: 'right', // place the field to the right of the matched text anchorOffsetX: 8, width: 200, height: 50, });
PropertyTypeDescription
placementenumcoordinate (default) or anchor
anchorTextstringLiteral string to locate in the rendered document. Must not contain {{ }}.
anchorPositionenumreplace, left, right, above, below — where the field sits relative to each match
anchorOffsetX / anchorOffsetYnumberOffset in points applied after resolution
hideAnchorbooleanWhite-out a visible marker after resolving it

Key behaviors:

  • Every occurrence is placed. If the anchor string appears three times, three fields are created. Use a unique marker if you want exactly one.
  • Invisible markers. Make the anchor text white in your Word document — it is still extracted for positioning but is invisible to signers, so no clean-up is needed. Alternatively set hideAnchor: true to cover a visible marker.
  • Coordinate fields still work. Mix anchor and coordinate fields freely. For coordinate fields on documents whose page count varies, set pageNumber: -1 to target the last page.

Anchor placement is resolved per generation, so it requires no preview clicking and stays correct as merge content changes.

Creating Documents from Templates

Map real signers to template roles and optionally fill merge field variables:

const document = await korala.templates.createDocument(templateId, { name: 'NDA — Acme Corp', signers: [ { roleId: clientRoleId, name: 'Jane Smith', email: '[email protected]', }, { roleId: approverRoleId, name: 'Bob Johnson', email: '[email protected]', }, ], variables: { company_name: 'Acme Corp', effective_date: '2024-03-01', client_address: '123 Main St', }, }); console.log(`Document created: ${document.id}`); console.log(`Status: ${document.status}`); // 'draft'

The created document is in draft status. Send it for signing to start the signing workflow.

Generating PDFs Without Signing

Generate a filled PDF from a template without starting a signing workflow. Useful for previews or non-signing document generation:

const result = await korala.templates.generate(templateId, { variables: { company_name: 'Acme Corp', effective_date: '2024-03-01', }, }); console.log(`Download: ${result.downloadUrl}`);

Managing Templates

// List all templates const templates = await korala.templates.list(); // Get template with full details (roles + fields) const template = await korala.templates.get(templateId); console.log(`Roles: ${template.signerRoles.length}`); console.log(`Fields: ${template.fields.length}`); // Update name, description, or active status await korala.templates.update(templateId, { name: 'Updated NDA Template', description: 'Revised for 2024', isActive: true, }); // Deactivate a template await korala.templates.update(templateId, { isActive: false }); // Delete a template await korala.templates.delete(templateId);

Replacing the Template File

Replace the underlying PDF/DOCX without losing signer roles or field positions:

// Step 1: Get replacement upload URL const { uploadUrl, key } = await korala.templates.replaceFile(templateId, { filename: 'nda-v2.pdf', contentType: 'application/pdf', }); // Step 2: Upload new file await fetch(uploadUrl, { method: 'PUT', body: fs.readFileSync('nda-v2.pdf'), headers: { 'Content-Type': 'application/pdf' }, }); // Step 3: Confirm replacement await korala.templates.confirmReplaceFile(templateId, { key });

After replacing a template file, verify that existing field positions still align with the new document layout.

Last updated on