Vault Platform for Dynamics 365 Sales

Developer Guide - Vault Platform for Dynamics 365 Sales

Technical architecture, detailed action flows, Dataverse table schemas, Custom API and plugin reference, batch dispatch modes, workflow enforcement, and deployment/ALM for the Vault Platform CRM integration.

Integration Architecture

The Vault Platform for Dynamics 365 Sales uses a native server-side processing layer within Dataverse. Each Command Bar action routes through a Custom Dataverse API to server-side logic that builds the document payload, uploads it to SharePoint, and calls the Vault Dispatcher.

LayerDynamics 365 Sales
UI triggerCommand Bar button
Template galleryJavaScript dialog
Server-side processingDataverse Plugin (runs within Dataverse sandbox)
Template and field mapping storageDataverse custom tables
SharePoint uploadMicrosoft Graph API
PDF generationVault Dispatcher
Document link storageDataverse vault_documentlink table
Workflow enforcementDataverse pre-operation plugin
Credential storageDataverse Environment Variables

No Azure Function or Power Automate relay

There is no intermediate Azure Function or Power Automate flow in the processing path. The server-side plugin runs directly on the Dataverse platform. JavaScript handles UI only - it reads context, calls the Custom API, and displays results.


Dispatcher Contract

The Dispatcher is source-agnostic. It is a pure request-response service with four operations, and it only reads and writes SharePoint.

ActionEndpointMethodRequestResponse
Generate Document/renderPOST{ templatePath, payloadPath, options, templateSettings }PDF buffer + headers: x-vaultpdf-blobpath, x-vaultpdf-correlationid, x-vaultpdf-workflowid
Open Document/docGET?blobPath=...{ url: "<SAS_URL>" }
Workflow Status/workflow/{id}/statusGET{id} in path{ state, title, currentStepIndex, totalSteps }
Workflow Sealed PDF/workflow/{id}/exportGET{id} in path, ?format=pdf{ downloadUrl: "<SAS_URL>" }

The Dispatcher never calls back to Dynamics 365. There is no push, no webhook, and no write to Dataverse. All state updates in CRM happen when a CRM user explicitly triggers an action - pull model throughout.


Action Summary

Each Command Bar button routes to a dedicated Custom Dataverse API. The table below describes what each action does and when to use it.

ActionWhat it doesWhen to use
Process DocumentReads the CRM record, uploads a data payload to SharePoint, calls the Dispatcher to render the PDF, and stores a document link on the recordFirst time generating a document for a record, or to regenerate
Open DocumentRetrieves a short-lived download URL for the most recently generated PDF and opens it in a new tabViewing a document that has already been generated
Sync Workflow StatusQueries the Dispatcher for the current workflow state and displays it in a dialog; saves the outcome against the record on completion or rejectionChecking whether a workflow has been approved, rejected, or is still in progress
Get Signed DocumentRetrieves the sealed, signed PDF from the Dispatcher after a workflow completesDownloading the final signed document

Pull Model - No Background Sync

Workflow status is never updated automatically. It is only refreshed when a user clicks Sync Workflow Status. There is no Dispatcher callback or background sync into Dynamics 365.


Dataverse Custom Tables

The managed solution installs six custom tables. All table names are prefixed with vault_.

vault_template

Stores template definitions - one row per template.

ColumnTypeDescription
vault_templateidGUID (PK)Unique template identifier
vault_nameTextHuman-readable display name
vault_entitylogicalnameTextCRM entity, e.g. quote, opportunity
vault_templatevariantidTextTemplate ID in the Vault template library
vault_dispatchmodeChoiceStandard, PerRecord, SingleArray, GroupedArray
vault_workflowenabledBooleanActivate workflow routing for this template
vault_workflowenforcementmodeChoiceBlock, Validate, or None
vault_watermarkenabledBooleanPrint a watermark on generated PDFs
vault_watermarktextTextWatermark text, e.g. CONFIDENTIAL
vault_isactiveBooleanOnly active templates appear in the gallery

vault_templatefield

Stores field mappings for each template - one row per mapped field.

ColumnTypeDescription
vault_templatefieldidGUID (PK)Unique identifier
vault_nameTextDescriptive label for this mapping
vault_templateidLookup → vault_templateParent template
vault_crmfieldnameTextCRM field logical name, e.g. name, totalamount
vault_placeholderkeyTextKey in the Vault payload JSON, e.g. documentTitle
vault_sectiontypeChoice (OptionSet)Header (100000000), Line (100000001), or Footer (100000002)
vault_jsongroupTextOptional nesting key, e.g. billing, shipping
vault_sequencenumberIntegerField ordering within a section

vault_templateassignment

Controls which templates appear on which entities and contexts.

ColumnTypeDescription
vault_templateidLookup → vault_templateThe template to expose
vault_entitylogicalnameTextTarget entity
vault_contextChoiceform, view, or both

vault_templatesigner

Stores e-signature signer configuration per template. Fields reference CRM field logical names resolved at generation time — they are not hardcoded email addresses.

ColumnTypeDescription
vault_templateidLookup → vault_templateParent template
vault_emailfieldnameTextCRM field providing the signer's email, e.g. emailaddress1
vault_namefieldnameTextCRM field providing the signer's display name, e.g. fullname
vault_signerroleTexte.g. Signer, Witness, Approver
vault_sequencenumberIntegerSigning order for sequential mode

vault_templaterecipient

Stores delivery and workflow recipient configuration per template. Recipients can be either dynamic (resolved from the CRM record) or static (hardcoded email address).

ColumnTypeDescription
vault_templateidLookup → vault_templateParent template
vault_recipienttypeChoiceDelivery or Workflow
vault_emailfieldnameTextCRM field logical name to resolve the recipient email from the record (mutually exclusive with vault_staticemailaddress)
vault_staticemailaddressTextHardcoded recipient email — used when vault_emailfieldname is not set
vault_sequencenumberIntegerRecipient ordering

The runtime document link table. One row per generated document per record per link type.

ColumnTypeDescription
vault_documentlinkidGUID (PK)Unique document link
vault_entitynameTextSource CRM entity
vault_recordidTextSource CRM record GUID
vault_linktypeChoicestandard or workflow - see write rules below
vault_correlationidTextJob reference from Dispatcher
vault_blobpathTextSharePoint path to the generated PDF
vault_workflowidTextWorkflow instance ID (only for workflow linktype)
vault_workflowstateTextcomplete or rejected - written only on terminal states
vault_enforcementmodeChoiceBlock, Validate, or None (only for workflow linktype)
vault_generatedonDateTimeTimestamp of generation
vault_generatedbyuserTextCRM user who triggered the action

Write rules:

ActionWritten columns
Process DocumentblobPath, correlationId, linkType; also workflowId + enforcementMode when template is a workflow type
Sync Workflow StatusworkflowState - only when state = complete or rejected
Open DocumentRead only
Get Signed DocumentRead only
DispatcherNever writes to this table

Link type policy: A record can hold one standard link and one workflow link simultaneously. A new standard document never deletes a workflow link, and vice versa. The latest document of each type overwrites the previous.


Custom APIs

The solution includes eight Custom Dataverse APIs. The four command actions are invoked by Command Bar buttons. The four admin APIs are intended for one-time or periodic administrative use.

Command Actions

Custom APIDispatcher EndpointTriggered by
vault_ProcessDocumentPOST /render[Process Document] button
vault_OpenDocumentGET /doc[Open Document] button
vault_SyncWorkflowStatusGET /workflow/{id}/status[Sync Workflow Status] button
vault_GetSealedDocumentGET /workflow/{id}/export[Get Signed Document] button

Admin APIs

Custom APIPurpose
vault_BrowseSharePointFolderLists folders and .vpdf files in the templates SharePoint drive via Microsoft Graph. Used by the template browser dialog.
vault_ImportTemplateDownloads a .vpdf from SharePoint and creates or updates the matching vault_template record.
vault_InitializeDefaultsCreates default templates and field mappings for all eight supported entities. Run once after installation.
vault_ValidateSettingsChecks which of the twelve environment variables are configured and returns a missing-settings report.

vault_InitializeDefaults parameters:

ParameterTypeDescription
overwriteExisting (input, optional)BooleanIf true, regenerates field mappings even if templates already exist
templatesCreated (output)IntegerNumber of new templates created
fieldMappingsCreated (output)IntegerNumber of new field mapping records created
assignmentsCreated (output)IntegerNumber of new template assignments created
summary (output)StringHuman-readable summary

vault_ValidateSettings outputs:

ParameterTypeDescription
isConfiguredBooleanTrue if all required variables are set
missingSettingsStringJSON array of missing variable names
configuredCountIntegerNumber of variables that have values
totalCountIntegerTotal number of expected variables
summaryStringHuman-readable summary

Workflow Enforcement

A pre-operation plugin checks whether a pending workflow should block or warn before certain CRM operations complete. It reads the last-known workflow state saved on the record - it never calls the Dispatcher directly. If a user has not recently synced the workflow status, enforcement acts on the most recently saved state.

Enforcement modes (configured per template):

ModeBehaviour
BlockCRM operation is prevented until the workflow reaches a terminal state (Complete or Rejected)
ValidateA warning is shown to the user but the operation is allowed to proceed
NoneNo enforcement - workflow state is tracked but does not affect CRM operations

Suggested Enforcement Triggers by Entity

EntitySuggested blocked operations
QuoteActivate Quote, Close as Won/Lost, Convert to Order
OpportunityClose as Won, Close as Lost
AccountDeactivate Account
OrderFulfil Order, Cancel Order
InvoiceMark as Paid, Cancel Invoice

Enforcement mode (Block / Validate / None) is configured per template and stored in vault_documentlink.enforcementMode at the time of document generation.


Batch Dispatch Modes

The Dispatcher detects the operation mode from the payload schema. The plugin code is identical for single and batch operations - both call POST /render and receive a PDF buffer in response.

ModePayload shapeDispatcher response
Single{ mode: "single", sourceRecordId: "...", metadata: {...} }Rendered PDF buffer
Batch{ mode: "batch", references: [{...}, {...}, ...] }Intake Receipt PDF buffer

For batch operations, the Dispatcher accepts the job, immediately generates and returns an Intake Receipt PDF as acknowledgment, then processes the batch asynchronously and writes results to SharePoint. The CRM user receives the Intake Receipt immediately - the same hand-in-hand experience as a single record operation.

Initial release scope:

ModeDescriptionInitial release
StandardOne PDF for the current recordYes
Per RecordOne PDF per selected record from a list viewYes
Single ArrayAll selected records combined into one PDFYes
Grouped ArrayRecords grouped into arrays within one PDFFuture

Batch Safety Thresholds

Record countBehaviour
≤ 25Processes immediately
26–100Confirmation dialog before processing
> 100Blocked with error message

Thresholds are stored as Dataverse Environment Variables and can be adjusted per customer without a solution update.


Managed Solution Contents

VaultPlatform_D365Sales (Managed Solution)
├── Dataverse Tables (6)
│   ├── vault_template
│   ├── vault_templatefield
│   ├── vault_templateassignment
│   ├── vault_templatesigner
│   ├── vault_templaterecipient
│   └── vault_documentlink
├── Custom Dataverse APIs (8)
│   ├── vault_ProcessDocument         - Command Bar action
│   ├── vault_OpenDocument            - Command Bar action
│   ├── vault_SyncWorkflowStatus      - Command Bar action
│   ├── vault_GetSealedDocument       - Command Bar action
│   ├── vault_BrowseSharePointFolder  - Admin: browse template library
│   ├── vault_ImportTemplate          - Admin: import .vpdf from SharePoint
│   ├── vault_InitializeDefaults      - Admin: seed default templates (8 entities)
│   └── vault_ValidateSettings        - Admin: check environment variable config
├── Web Resources
│   ├── vault_/scripts/vault_actions.js    - Command Bar button handlers
│   ├── vault_/scripts/vault_gallery.js    - Template gallery + progress dialog
│   ├── vault_/scripts/vault_browser.js    - Template browser + import dialog
│   ├── vault_/stylesheets/vault_gallery.css
│   ├── vault_/stylesheets/vault_browser.css
│   ├── vault_/pages/vault_gallery.html
│   └── vault_/pages/vault_browser.html
├── Command Bar Customisations (8 entities)
│   ├── quote, opportunity, account, contact
│   ├── salesorder, invoice, incident, lead
│   └── Buttons: [Process Document] [Open Document] [Sync Workflow Status] [Get Signed Document]
├── Security Roles
│   └── Vault User
└── Environment Variables (12)
    ├── vault_graph_tenantid
    ├── vault_graph_clientid
    ├── vault_graph_clientsecret           (secret)
    ├── vault_graph_driveid                (output document library)
    ├── vault_graph_templatesdriveid       (templates library)
    ├── vault_graph_templatessourcefolder  (folder path within templates library)
    ├── vault_dispatcher_baseurl
    ├── vault_dispatcher_tenantid
    ├── vault_dispatcher_clientid
    ├── vault_dispatcher_clientsecret      (secret)
    ├── vault_batchwarningthreshold        (default: 25)
    └── vault_batchmaxthreshold            (default: 100)

Deployment and ALM

StageMethod
DevelopmentUnmanaged solution; plugins registered via Plugin Registration Tool
QA / UATExport managed solution → import to target environment; set environment variables per environment
ProductionImport managed solution
UpgradeImport new managed solution version - tables and data are preserved
UninstallDelete managed solution - full clean removal, no residual customisations left in the environment
Credential rotationUpdate the relevant Environment Variable secret values only - no code change or solution reimport required

Entity Extension Pattern

Command Bar customisations are the only entity-specific artefacts in the solution. Adding support for a new CRM entity requires only a new Command Bar entry in a solution update - no plugin code changes. The plugin reads the entity name from the Custom API request parameters, so it works generically for any entity with an assigned template.

On this page