Skip to main content

POST /api/docs/generate-bulk

Generates N documents from a single template in one request. The server resolves the template by key, fetches the binary once, merges each document in a loop, uploads all results to Salesforce Files, and returns an array of ContentDocumentId values. No document bytes are returned to the caller.

Designed for Apex batch classes — see KS_BulkGenerateDocument for the Apex utility that wraps this endpoint.

Base URL: https://app.keelstone.dev
Authentication: x-org-api-key + x-sf-user-id (Apex-originated; set via KS_LicenseService.setAuthHeaders)

Request

POST /api/docs/generate-bulk
Content-Type: application/json
x-org-api-key: <orgApiKey>
x-sf-user-id: <sfUserId>
{
templateKey: string; // Template_Key__c on a Keelstone_Template__c record
documents: Document[]; // Array of per-document merge specs
outputFormat?: string; // 'pdf' to convert all outputs (optional)
}

type Document = {
data: object; // Merge context — keys become template tokens
filename?: string; // Output filename, e.g. 'Ada Welcome.docx'
linkedEntityId?: string; // Salesforce record ID to attach the file to
externalLink?: boolean; // true to return a public download URL
sharePointPath?: string; // SharePoint folder to upload this document to
}
FieldTypeRequiredDescription
templateKeystringYesTemplate_Key__c on the Keelstone_Template__c record
documentsDocument[]YesNon-empty array — one entry per document to generate
outputFormatstringNo'pdf' converts all outputs regardless of template extension

Response

200 OK

{
"results": [
{ "success": true, "contentDocumentId": "069...", "filename": "Ada Welcome.docx" },
{ "success": true, "contentDocumentId": "069...", "filename": "Bob Welcome.docx", "documentUrl": "https://...", "sharePointFileUrl": "https://contoso.sharepoint.com/..." },
{ "success": false, "error": "Render failed: unknown token {BadField}", "filename": "Eve Welcome.docx" },
{ "success": true, "contentDocumentId": "069...", "filename": "Hal Welcome.docx", "sharePointError": "SharePoint integration requires the Keelstone Pro plan or higher." }
]
}

Results are returned in the same order as the input documents array. A per-document failure does not abort the rest — the endpoint always returns 200 with a results array. Inspect each success flag to detect partial failures.

FieldTypeDescription
successbooleantrue if the document was generated and uploaded to Salesforce Files
contentDocumentIdstringSalesforce ContentDocumentId of the generated file
documentUrlstringPublic download URL (only when externalLink: true was set)
sharePointFileUrlstringSharePoint URL of the uploaded file (only when sharePointPath was supplied and the upload succeeded)
sharePointErrorstringPer-document SharePoint error — set when the SP upload failed or the org is not on Pro. Does not affect success.
errorstringPer-document generation error message when success is false
filenamestringThe filename used for this document

400 Bad Request — missing or invalid inputs

{ "error": "templateKey is required" }
{ "error": "documents must be a non-empty array" }
{ "error": "Unsupported template type: .pptx. Supported: .docx, .xlsx" }

404 Not Found — template key does not resolve

{ "error": "No active template found with key: welcome-packet" }
{ "error": "No file attached to template: welcome-packet" }

How it works

  1. Resolves Salesforce credentials from connected_orgs using the authenticated org ID
  2. Queries the Keelstone_Template__c record by templateKeyContentDocumentId → latest ContentVersion
  3. Downloads the template binary once
  4. For each document in the array: creates a fresh in-memory ZIP from the template buffer, merges via docxtemplater (.docx) or XlsxTemplate (.xlsx), injects _ks_template_key as a custom document property, optionally converts to PDF
  5. Uploads each merged file to Salesforce as a new ContentVersion; creates a ContentDocumentLink if linkedEntityId was provided
  6. Returns the results array — per-document errors are caught and reported without aborting remaining documents

The template buffer is parsed once and reused across all iterations — no redundant Salesforce downloads.

Using from Apex

The idiomatic way to call this endpoint is via KS_BulkGenerateDocument.generateAll(), which handles serialisation, auth headers, and result mapping:

global class GenerateWelcomePackets
implements Database.Batchable<SObject>, Database.AllowsCallouts {

global Database.QueryLocator start(Database.BatchableContext ctx) {
return Database.getQueryLocator(
'SELECT Id, Name, Level__c FROM Contact WHERE Send_Packet__c = true'
);
}

global void execute(Database.BatchableContext ctx, List<SObject> scope) {
List<KS_BulkGenerateDocument.Request> reqs = new List<KS_BulkGenerateDocument.Request>();
for (SObject rec : scope) {
Contact c = (Contact) rec;
KS_BulkGenerateDocument.Request req = new KS_BulkGenerateDocument.Request();
req.templateKey = 'welcome-packet';
req.contextJson = JSON.serialize(new Map<String, Object>{
'Name' => c.Name,
'Level__c' => c.Level__c
});
req.filename = c.Name + ' Welcome Packet.docx';
req.linkedEntityId = c.Id;
reqs.add(req);
}
KS_BulkGenerateDocument.generateAll(reqs);
}

global void finish(Database.BatchableContext ctx) {}
}
Database.executeBatch(new GenerateWelcomePackets(), 20);

See Bulk Document Generation in the Developer Guide for the full KS_BulkGenerateDocument API reference and batch size guidance.

Governor limit profile (N documents)

ResourceKS_GenerateDocument (serial)KS_BulkGenerateDocument (bulk)
SOQL queries4N1 (license check)
HTTP calloutsN1
DML statements2N0
Apex heapO(N × template size)O(N × context size)