Automated Document Generation - VaultPDF Business Central
Trigger VaultPDF document generation automatically on posting, from external systems via API, or programmatically from AL code. Covers the Generation Queue, job setup, and monitoring.
Overview
VaultPDF supports four ways to trigger document generation. All four paths funnel into the same Generation Queue - a persistent table that the VaultPDF Gen Processor job drains asynchronously.
| Trigger | When to use |
|---|---|
| Interactive gallery | User opens a document and clicks Generate - standard on-demand use |
| Auto-generate on post | Template flag queues generation automatically when a BC document is posted |
| External API | An integrated system (ERP, custom app, integration platform) calls the BC API after creating or posting a document |
| AL code | A partner or customer extension calls the queue table helper directly |
The first three scenarios are covered in detail below. The interactive gallery is described in Processing Documents.
Architecture: The Generation Queue
The Generation Queue (VaultPDF Gen Request, table 77113) decouples the act of requesting PDF generation from the act of executing it. Any trigger path inserts a row; the VaultPDF Gen Processor (codeunit 77136), running as a recurring Job Queue entry, picks up Pending rows in batches and drives each one through the full VaultPDF pipeline (JSON build → SharePoint upload → Dispatcher call → Record Link).
Trigger (Post event / API call / AL code)
↓
Gen Request row (Status = Pending)
↓
Job Queue → VaultPDF Gen Processor (codeunit 77136)
↓
SharePoint Upload + Dispatcher Call
↓
Status = Completed (or Failed / Dead after retries)Key design properties:
- Trigger-agnostic - the processor does not know or care how a row was created
- Retry-safe - failed rows are retried up to
VAULTPDF_GEN_QUEUE_MAX_RETRIEStimes before being markedDead - Concurrent-safe - the processor marks a row
Processingbefore committing, so parallel Job Queue workers cannot double-process the same request - Non-blocking for posting - the posting subscriber inserts Gen Request rows in a new transaction after posting commits, so a subscriber failure never rolls back a completed posting
Scenario 1: Auto-Generate on Post
Enable this flag on a template to have VaultPDF automatically queue a generation request whenever a Business Central document from that template's source table is posted.
Supported posting events:
- Sales Invoice posted from a Sales Order or Sales Invoice
- Sales Credit Memo
- Purchase Invoice
- Purchase Credit Memo
Enable Auto Generate on Post on the Template
Open VaultPDF Templates and open the template you want to automate.
In the Variants subform, select the variant to automate (usually the default variant) and click Edit Variant Settings. In the Dispatch section, enable the Auto Generate on Post toggle.
Standard Dispatch Mode Only
Auto Generate on Post is only available for variants with Dispatch Mode = Standard. Batch modes (Per Group, Per Record, Single Array, Grouped Array) are not supported for posting automation because each posted document generates exactly one header record - batch modes require a filtered record set selected at dispatch time.
Verify that the template's Source Table ID maps to the correct Business Central document table. The posting subscriber matches on this table ID:
| Document type | Source Table ID |
|---|---|
| Sales Invoice | 112 (Sales Invoice Header) |
| Sales Credit Memo | 114 (Sales Cr.Memo Header) |
| Purchase Invoice | 122 (Purch. Inv. Header) |
| Purchase Credit Memo | 124 (Purch. Cr. Memo Hdr.) |
Create the VaultPDF Gen Processor Job Queue Entry
The posting subscriber inserts queue rows, but nothing processes them unless the Gen Processor job is running.
Search for Job Queue Entries in Business Central and click New.
Configure the entry with these values:
| Field | Value |
|---|---|
| Object Type to Run | Codeunit |
| Object ID to Run | 77136 |
| Object Caption to Run | VaultPDF Gen Processor |
| Recurring Job | Yes |
| Run on Mondays ... Sundays | Enable all days (or the days matching your posting schedule) |
| Starting Time | 00:00:00 |
| Ending Time | 23:59:59 |
| No. of Minutes between Runs | 2 (poll every 2 minutes) or 5 for lower-frequency environments |
| Status | Ready |
One Job Entry is Sufficient
A single recurring Job Queue entry processes all pending generation requests for all templates. Do not create one entry per template - this wastes Job Queue worker capacity and can cause contention.
Post a Document and Verify
Post any Sales Order or Purchase Invoice that uses a template with Auto Generate on Post enabled.
After posting, open VaultPDF Generation Queue from the Tell Me bar (or via the Generation Queue action on the Template Card).
You should see a new row with:
- Source =
Posting Event - Status =
Pending(orProcessingif the job picked it up quickly, orCompletedif already done) - Template Code = the template that matched the posted document
Within the next Job Queue cycle, the row transitions to Completed and a Record Link (PDF link) is attached to the posted document.
Scenario 2: External System Triggers Generation via API
Use this pattern when an external application - a custom ERP, an integration platform (Power Automate, Logic Apps, Boomi, MuleSoft), or a BC API client - creates or posts a BC document and then wants to trigger VaultPDF generation without requiring a user to open Business Central.
API Endpoint
POST /api/refractlogic/vaultpdf/v1.0/companies({companyId})/generationRequestsAuthentication: Standard BC OData API authentication (OAuth 2.0 with Dynamics 365 Business Central scope, or Basic auth for on-premises).
Request body:
{
"templateCode": "PINV-STANDARD",
"tableId": 122,
"docNo": "PINV-00001",
"externalRef": "ERP-JOB-REF-789"
}| Field | Type | Required | Description |
|---|---|---|---|
templateCode | string | Yes | VaultPDF template code, e.g. PINV-STANDARD. Must exist and be enabled. |
tableId | integer | Yes | Business Central table ID for the posted document. See table IDs below. |
docNo | string | Yes | The document number (No. field) of the posted document. |
externalRef | string | No | Free-text reference from the calling system (e.g. correlation ID, job number). Stored on the queue row for traceability. |
Common table IDs:
| Document | Table ID |
|---|---|
| Sales Invoice Header | 112 |
| Sales Credit Memo Header | 114 |
| Purchase Invoice Header | 122 |
| Purchase Credit Memo | 124 |
| Sales Order Header (pre-post) | 36 |
| Purchase Header (pre-post) | 38 |
Response (201 Created):
{
"requestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"templateCode": "PINV-STANDARD",
"tableId": 122,
"docNo": "PINV-00001",
"status": "Pending",
"externalRef": "ERP-JOB-REF-789",
"createdAt": "2026-06-20T14:32:00Z"
}Polling for Completion
Poll the returned requestId to track processing:
GET /api/refractlogic/vaultpdf/v1.0/companies({companyId})/generationRequests({requestId})Response when complete:
{
"requestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "Completed",
"blobPath": "RefractLogic/PurchaseInvoices/PINV-00001_PINV-STANDARD.pdf",
"correlationId": "vpdf-corr-xyz",
"processedAt": "2026-06-20T14:33:15Z"
}| Status | Meaning |
|---|---|
Pending | Queued; not yet picked up by the processor |
Processing | Processor is actively working on this request |
Completed | PDF generated and stored; blobPath and correlationId are populated |
Failed | Processing failed; errorMessage contains the reason; will be retried |
Dead (Max Retries Reached) | All retry attempts exhausted; manual intervention required |
Polling Interval Recommendation
The Gen Processor runs every 2 - 5 minutes by default. Poll at a 30 - 60 second interval and implement an overall timeout of 15 - 30 minutes for large documents or documents involving workflow routing.
End-to-End Example: External System Posts an AP Invoice
This is the canonical scenario: an external procurement system creates and posts a Purchase Invoice via the BC standard API, then triggers VaultPDF generation.
Create and post the Purchase Invoice using the standard BC purchaseInvoices API (or equivalent custom API). Retrieve the posted invoice's No. from the response.
Request PDF generation by calling the VaultPDF generation API with the invoice number and the appropriate template code.
POST /api/refractlogic/vaultpdf/v1.0/companies({companyId})/generationRequests
Content-Type: application/json
{
"templateCode": "PINV-STANDARD",
"tableId": 122,
"docNo": "PINV-00001",
"externalRef": "PROC-SYSTEM-JOB-42"
}Store the requestId from the 201 response. Use it to poll for completion.
Poll until status = Completed and use the blobPath or open the Vault Lifecycle portal via correlationId to retrieve the generated PDF.
Power Automate / Logic Apps Integration
To integrate with Power Automate or Azure Logic Apps, use the Business Central connector's Call a Bound Action action - or make a direct HTTP call to the OData endpoint using the HTTP with Microsoft Entra ID connector.
Recommended flow pattern:
- Trigger: When a record is created/modified in Business Central (or on a schedule)
- Action: POST to
generationRequestsusing HTTP connector - Action: Do-Until loop polling
GET generationRequests({requestId})untilstatus = Completedor timeout - Action: Send Teams/email notification with
blobPath
Scenario 3: AL Developer Queues Programmatically
A partner or customer extension can queue generation requests directly from AL code without going through a user action or a posting event.
Using the Public API: QueueGenerationForPosting
The preferred way to trigger generation from AL code is VaultPDF Batch Dispatcher.QueueGenerationForPosting. This is the same path the built-in posting subscriber uses, so your requests participate in the same retry policy, queue monitoring, and extensibility hooks.
local procedure TriggerVaultGenerationForMyDoc(PostedHeader: Record "My Posted Header")
var
BatchDispatcher: Codeunit "VaultPDF Batch Dispatcher";
RecRef: RecordRef;
begin
RecRef.GetTable(PostedHeader);
BatchDispatcher.QueueGenerationForPosting('MY-TEMPLATE', RecRef);
end;Calling QueueGenerationForPosting fires OnBeforeQueueForTable (described below) before inserting the Gen Request row. This means any partner or customer subscriber that intercepts or redirects posting-triggered generation will also apply to your call - consistent behaviour across the system.
Queue from a Custom Posting Flow (Low-Level)
If you need direct control over the Gen Request row fields, call QueueFromPosting on the table directly:
local procedure AfterMyDocumentPosting(var PostedHeader: Record "My Posted Header")
var
GenRequest: Record "VaultPDF Gen Request";
RecRef: RecordRef;
begin
RecRef.GetTable(PostedHeader);
GenRequest.QueueFromPosting('MY-TEMPLATE', RecRef);
end;QueueFromPosting sets Source = Posting Event, captures the RecordId directly from the RecordRef, and resolves the Doc No. from the record's No. field. It is safe to call within a posting transaction - the Gen Request insert is committed independently.
OnBeforeQueueForTable
Published by "VaultPDF Posting Subscriber". Fires before the posting subscriber queues a generation request for a specific posted document table. Allows partners to skip, redirect, or substitute the template code before the Gen Request row is created.
[EventSubscriber(ObjectType::Codeunit, Codeunit::"VaultPDF Posting Subscriber",
'OnBeforeQueueForTable', '', false, false)]
local procedure OnBeforeQueueForTable(
TableId: Integer;
var TemplateCode: Code[20];
var IsHandled: Boolean)
begin
// Example 1: Skip generation entirely for a specific custom table
if TableId = Database::"My Custom Header" then begin
IsHandled := true; // Prevent default queue; handle in your own subscriber
exit;
end;
// Example 2: Redirect to a different template per company
if (TableId = Database::"Sales Invoice Header") and (CompanyName = 'SUBSIDIARY') then begin
TemplateCode := 'SINV-SUBSIDIARY';
IsHandled := true; // Use the overridden template code instead of the default
end;
end;Setting IsHandled := true prevents the default posting subscriber from inserting a Gen Request row. Set it without changing TemplateCode to suppress generation completely, or set it after assigning a new TemplateCode to redirect to a different template.
Queue a Specific Record Internally
Use QueueInternal when triggering generation from a background codeunit, upgrade routine, or any non-posting context:
local procedure ReprocessDocument(DocNo: Code[20])
var
InvHeader: Record "Sales Invoice Header";
GenRequest: Record "VaultPDF Gen Request";
RecRef: RecordRef;
begin
InvHeader.Get(DocNo);
RecRef.GetTable(InvHeader);
GenRequest.QueueInternal('SINV-STANDARD', RecRef);
end;Queue from an API (Server-Side Validation)
If you need to add validation logic before accepting an API-originated request, subscribe to the OnInsertRecord trigger override pattern by creating a page extension on VaultPDF Gen Request API (page 77138) and adding your logic in OnBeforeInsertRecord or a custom validation codeunit.
Configuring Maximum Retries
The Gen Processor retries failed requests up to a configurable maximum before marking them Dead (Max Retries Reached).
Navigate to VaultPDF System Settings and find the key VAULTPDF_GEN_QUEUE_MAX_RETRIES.
| Key | Default | Description |
|---|---|---|
VAULTPDF_GEN_QUEUE_MAX_RETRIES | 3 | Maximum processing attempts per request before the row is marked Dead. Increase for environments with transient connectivity issues; decrease for faster failure detection. |
This key is created automatically by Initialize Default Keys with a default value of 3. Individual queue rows also carry their own Max Retries field - the system setting provides the default; the per-row value can be overridden by AL code when queuing.
Log Retention and Auto-Purge
VaultPDF automatically purges old batch job entries and upload log rows to prevent unbounded table growth. The purge runs at the start of each VaultPDF Batch Job Runner execution (codeunit 77132).
| Key | Default | Description |
|---|---|---|
VAULTPDF_LOG_RETENTION_DAYS | 90 | Days to retain completed and failed batch jobs and upload log entries before automatic deletion. Entries older than this threshold are permanently removed. Set to 0 to disable auto-purge entirely. |
Configure this key in VaultPDF System Settings after running Initialize Default Keys.
What gets purged:
VaultPDF Batch Job Entryrecords with statusCompletedorFailedthat are older than the retention thresholdVaultPDF Upload Logrows linked to purged batch job entriesVaultPDF Batch Detail Linerows linked to purged batch job entries
What is not purged:
Queued,Running, orPartialbatch jobs (regardless of age) - active records are never deleted- Generation Queue rows (
VaultPDF Gen Request) - these are managed independently via Purge Completed on the Generation Queue page
If VAULTPDF_LOG_RETENTION_DAYS is set to 0, auto-purge is disabled entirely and records accumulate indefinitely. Plan a manual maintenance strategy (e.g., periodic Purge Completed from the batch page) if you disable automatic purge.
Monitoring the Generation Queue
Generation Queue Page
Open VaultPDF Generation Queue from the Tell Me bar to view all requests across all templates.
From the Template Card, the Generation Queue action in the action bar opens the same list pre-filtered to the current template.
Page columns:
| Column | Description |
|---|---|
| Request ID | Unique identifier (GUID) for this generation request |
| Template Code | The VaultPDF template used |
| Doc No. | Document number from the source BC record |
| Status | Current state: Pending, Processing, Completed, Failed, Dead |
| Source | How the request was created: Internal, API, Posting Event, Batch |
| Retry Count | Number of processing attempts so far |
| Error Message | Error text from the last failed attempt |
| Blob Path | SharePoint path of the generated PDF (populated on Completed) |
| Created At | When the request was queued |
| Processed At | When processing completed or last failed |
Status color coding:
| Status | Style |
|---|---|
Completed | Green (Favorable) |
Failed | Red (Unfavorable) |
Dead (Max Retries Reached) | Red (Unfavorable) |
Pending | Standard (Ambiguous) |
Processing | Yellow (Attention) |
Actions
| Action | Purpose |
|---|---|
| Retry Selected | Resets selected Failed or Dead rows back to Pending for reprocessing. Only enabled when selected rows are in a retryable state. |
| Delete Selected | Removes selected rows. Use for cleaning up rows that are no longer needed. |
| Purge Completed | Removes all Completed rows for the current template filter. Use for routine maintenance of the queue table. |
| Filter: Pending | Applies a quick filter showing only rows awaiting processing |
| Filter: Failed / Dead | Shows rows that require attention |
| Clear Filter | Removes the quick filter |
Dead Rows Require Manual Intervention
A row enters Dead (Max Retries Reached) status when all retry attempts have failed. Investigate the Error Message column to identify the root cause (connectivity, template misconfiguration, missing data) before using Retry Selected to requeue the row. Retrying without fixing the underlying issue will exhaust retries again.
Troubleshooting
| Symptom | Likely cause | Resolution |
|---|---|---|
Queue rows stay Pending indefinitely | Gen Processor Job Queue entry is not running or is on hold | Open Job Queue Entries, find codeunit 77136, confirm status is Ready and not on hold |
All rows show Failed immediately | Dispatcher or SharePoint connection error | Run System Status Check in System Settings; check Error Message on a failed row |
Auto Generate on Post not queuing any rows | Template's Source Table ID does not match the posted document table | Verify the template's Page ID auto-resolved to the correct source table; check that Enabled = true |
| API returns 401 or 403 | OData authentication missing or caller lacks permissions | Ensure the API caller has VPDF-USER permission set; verify OAuth scope includes Dynamics 365 Business Central |
| API returns 400 with "Template Code not found" | templateCode value in the request body does not match any enabled template | Check VaultPDF Templates - template must exist and have Enabled = true |
| Row completes but no PDF link on the document | CommitPendingLink was not called, or Record Link creation failed | Check the Blob Path field on the queue row - if populated, the PDF exists in SharePoint; the Record Link attachment may have been skipped due to a missing RecordId on the request |
Dead rows accumulating faster than expected | VAULTPDF_GEN_QUEUE_MAX_RETRIES set too low, or a systemic error is failing all requests | Increase VAULTPDF_GEN_QUEUE_MAX_RETRIES in System Settings; investigate root cause from Error Message before retrying |
Template Configuration - VaultPDF Business Central
Configure VaultPDF templates for PDF generation, batch dispatch, e-signature, approval workflows, distribution, and multi-hop field traversal in Business Central.
Developer Guide - VaultPDF Business Central
Extend VaultPDF with custom AL code. Subscribe to integration events, override templates, customize storage paths, and integrate with third-party systems.