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
- Upload a PDF or DOCX file as the base document
- Define signer roles (e.g., “Client”, “Approver”) — these are placeholders that get assigned to real people when you create a document
- Place fields on the template and assign each to a signer role
- 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:
TypeScript
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
TypeScript
// 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
TypeScript
// 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
| Type | Description |
|---|---|
signature | Drawn or uploaded signature image |
initials | Signer’s initials |
date | Date value |
text | Free-text input |
checkbox | Boolean 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.
Creating Documents from Templates
Map real signers to template roles and optionally fill merge field variables:
TypeScript
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.