Example: AP 3-Way Match
A complete governance workflow schema for AP 3-way match validation: PO vs. Goods Receipt vs. Invoice. Uses autoValidateOnCreate to run validation without portal interaction, then routes to Finance Director or AP Manager based on invoice total.
This example shows a governance workflow with autoValidateOnCreate: true. The workflow validates a three-way match between a Purchase Order, a Goods Receipt Note, and a Vendor Invoice. All field data is supplied in the API request payload; no participant interaction is needed. VaultWorkflow runs validation immediately and routes to the appropriate approver.
Workflow type: governance
Validation: auto (no portal interaction required)
Steps: 1 (auto-review with 4 sections)
Routing: sequential, two priority tiers
Full Schema
workflow:
templateVersion: "1.0"
title: "AP 3-Way Match — PO vs. GR vs. Invoice"
workflowType: governance
autoValidateOnCreate: true
layout:
mode: tabs
pdfColumns: 3
steps:
# ── Step: Auto Review (AP data, no participant interaction) ───────────────
- id: auto-review
title: "AP 3-Way Match Review"
sections:
- title: "Purchase Order"
blocks:
- type: input
inputType: text
fieldKey: po_number
label: "PO Number"
- type: input
inputType: number
fieldKey: po_amount
label: "PO Amount ($)"
- type: input
inputType: number
fieldKey: po_quantity
label: "PO Quantity"
- type: input
inputType: text
fieldKey: po_vendor_id
label: "PO Vendor ID"
- title: "Goods Receipt"
blocks:
- type: input
inputType: text
fieldKey: gr_number
label: "GR Number"
- type: input
inputType: number
fieldKey: gr_quantity
label: "Quantity Received"
- type: input
inputType: date
fieldKey: gr_received_date
label: "Received Date"
- title: "Invoice"
blocks:
- type: input
inputType: text
fieldKey: invoice_number
label: "Invoice Number"
- type: input
inputType: date
fieldKey: invoice_date
label: "Invoice Date"
- type: input
inputType: number
fieldKey: invoice_total
label: "Invoice Total ($)"
- type: input
inputType: number
fieldKey: invoice_quantity
label: "Invoiced Quantity"
- type: input
inputType: text
fieldKey: invoice_vendor_id
label: "Invoice Vendor ID"
- title: "Line Items & Cost Allocation"
blocks:
- type: input
inputType: text
fieldKey: lines_all_price_match
label: "All Line Prices Match"
- type: input
inputType: text
fieldKey: lines_all_qty_match
label: "All Line Quantities Match"
- type: input
inputType: text
fieldKey: department
label: "Department"
- type: input
inputType: text
fieldKey: cost_center
label: "Cost Center"
# ── Validation Rules ──────────────────────────────────────────────────────────
validation:
rules:
# Error: invoice total must not exceed PO amount (5% tolerance)
- id: invoice_le_po
description: "Invoice total must not exceed PO amount"
condition: "invoice_total <= po_amount"
severity: error
message: "Invoice total exceeds PO amount"
fieldKey: invoice_total
type: numericTolerance
left:
path: po_amount
label: "PO Amount"
right:
path: invoice_total
label: "Invoice Total"
tolerance:
percent: 5
expandableDetails: true
# Error: goods receipt quantity must cover invoiced quantity
- id: gr_qty_covers_invoice
description: "GR quantity must be >= invoiced quantity"
condition: "gr_quantity >= invoice_quantity"
severity: error
message: "Goods receipt quantity does not cover invoiced quantity"
fieldKey: gr_quantity
# Error: vendor IDs must match across all three documents
- id: vendor_match
description: "PO, GR, and invoice vendor IDs must match"
condition: "po_vendor_id == invoice_vendor_id"
severity: error
message: "Vendor ID mismatch between PO and invoice"
fieldKey: invoice_vendor_id
# Error: all line item prices must match
- id: lines_price_match
description: "All line item prices must match across PO and invoice"
condition: "lines_all_price_match == true"
severity: error
message: "One or more line item prices do not match between PO and invoice"
fieldKey: lines_all_price_match
# Warning: line quantities are mismatched but within acceptable range
- id: lines_qty_match
description: "All line quantities match across PO, GR, and invoice"
condition: "lines_all_qty_match == true"
severity: warning
message: "Line quantity mismatch detected — review recommended"
fieldKey: lines_all_qty_match
# Warning: invoice is within the 5% tolerance band of PO amount
- id: tolerance_warning
description: "Invoice is within the 5% tolerance band of PO amount"
condition: "invoice_total <= po_amount * 1.05"
severity: warning
message: "Invoice is near the PO amount ceiling — review recommended"
fieldKey: invoice_total
type: numericTolerance
left:
path: po_amount
label: "PO Amount"
right:
path: invoice_total
label: "Invoice Total"
tolerance:
percent: 5
# ── Approval Routing ──────────────────────────────────────────────────────────
approval:
routing:
mode: sequential
routes:
- id: finance-director
condition: "invoice_total > 50000"
priority: 1
description: "High-value invoice — Finance Director approval"
approver:
email: [email protected]
role: Finance Director
escalateAfterDays: 3
- id: ap-manager
priority: 2
description: "Standard invoice — AP Manager approval"
approver:
email: [email protected]
role: AP Manager
escalateAfterDays: 5
fallback:
approver:
email: [email protected]
role: AP ManagerSchema Notes
workflowType: governance
Governance workflows validate a structured data payload against a defined rule set. They are not interactive by default. The participant-facing portal is available only if reviewers need to amend field values before approval.
autoValidateOnCreate: true
Validation runs immediately when the workflow session is created via POST /api/workflow. No participant interaction is required to trigger validation. If all rules pass, the workflow proceeds directly to approval routing.
Errors block routing
Validation rules with severity: error block the workflow from advancing to the approval stage. All error rules must pass before routing can begin. Warning rules are surfaced to the approver as annotations but do not block routing.
Validation rule types
| Rule ID | Type | Severity | What it checks |
|---|---|---|---|
invoice_le_po | numericTolerance | error | Invoice total does not exceed PO amount within 5% |
gr_qty_covers_invoice | standard | error | Goods Receipt quantity covers invoiced quantity |
vendor_match | standard | error | Vendor ID matches across PO and Invoice |
lines_price_match | standard | error | All line item prices match |
lines_qty_match | standard | warning | All line quantities match |
tolerance_warning | numericTolerance | warning | Invoice is near the 5% PO ceiling |
type: numericTolerance
The numericTolerance rule type compares two numeric fields with a configurable percentage band. Setting expandableDetails: true renders a side-by-side comparison card in the approver interface showing both values and the tolerance calculation.
Approval routing
Routing mode is sequential. Routes are evaluated in priority order. The first route whose condition matches receives the approval task. If no condition matches, the fallback approver receives the task. escalateAfterDays triggers an escalation notification if the approver has not acted within the specified number of days.
Submitting the Payload
All field data is submitted in the POST /api/workflow request body. No portal interaction is required.
POST /api/workflow
{
"templatePath": "templates/ap-3way-match.vpdf",
"correlationId": "inv-2026-8821",
"initialData": {
"po_number": "PO-2024-0412",
"po_amount": 42500.00,
"po_quantity": 100,
"po_vendor_id": "VEND-0098",
"gr_number": "GRN-2024-0187",
"gr_quantity": 100,
"gr_received_date": "2024-07-15",
"invoice_number": "INV-2024-8821",
"invoice_date": "2024-07-18",
"invoice_total": 43200.00,
"invoice_quantity": 100,
"invoice_vendor_id": "VEND-0098",
"lines_all_price_match": true,
"lines_all_qty_match": true,
"department": "Procurement",
"cost_center": "CC-4400"
},
"options": { "documentId": "INV-2024-8821", "docType": "ap-invoice" }
}The response includes workflowId, correlationId, state, and portalUrl. Poll GET /api/workflow/{workflowId}/status to track approval status.
Invoice total near the PO ceiling
In the example above, the invoice total of $43,200 exceeds the PO amount of $42,500 by approximately 1.6%, which is within the 5% tolerance. The invoice_le_po error rule passes, but the tolerance_warning warning rule fires. The approver sees the tolerance annotation but can approve without override.
Governance Validation Page
Because this schema uses workflowType: governance, every sealed PDF includes an automatically generated Governance Validation page. No configuration is required.
The page shows three things:
- Workflow Outcome. One of
Approved,Approved with Exception, orRejected. AnApproved with Exceptionoutcome means the approver reviewed one or more rule failures, provided a written justification, and approved with override. - Governance Validation summary. The overall status (
PASSED,EXCEPTION, orFAILED) with a count breakdown: failed, warning, and passed rules out of the total. - Validation Rule Breakdown table. One row per rule, showing the rule message and its result (Pass, Fail, or Warning). All 6 rules in this schema appear in this table.
For this schema, a typical exception scenario looks like:
| Rule | Result |
|---|---|
| Invoice total exceeds PO amount | Fail |
| GR quantity does not cover invoiced quantity | Pass |
| Vendor ID mismatch between PO and invoice | Pass |
| Line item prices do not match between PO and invoice | Fail |
| Line quantity mismatch detected | Pass |
| Invoice is near the PO amount ceiling | Warning |
The summary line in that scenario reads: EXCEPTION — 2 failed · 1 warning · 3 passed (6 total). An Exception Review section below the table captures the approver's justification text and the timestamp of the override decision.
Justification is immutable
The approver's justification text is sealed into the PDF and captured in the WORKFLOW_SEALED audit event. It cannot be modified after sealing.
Electronic Evidence Appendix
When this workflow is approved and sealed, VaultWorkflow automatically appends an Electronic Evidence Appendix page to the final PDF. No schema configuration is required. The appendix is present for all governance workflows.
The appendix records the Workflow ID, Correlation ID, seal timestamp, approver hash (HMAC-SHA256), and Tenant ID. For governance workflows, participant identity is captured within the sealed content and referenced from the appendix rather than reproduced in plaintext.
A WORKFLOW_SEALED audit event is emitted to the tenant immutable audit archive in Azure Blob Storage. The archive uses a time-based immutability policy; records cannot be modified, overwritten, or deleted during the retention window. The Correlation ID in the example payload (b5a0d8fb-0bc9-4349-9868-f380b61dd6f6) is the stable reference to retrieve that audit event.
Hash chain covers the full document
The document hash is computed over the complete sealed PDF, including the appendix page. Any post-seal modification to the document invalidates the hash and fails integrity verification.
See the Workflow Schema Reference for the full appendix field reference and audit event payload.
Workflow Intake Receipt
When the workflow session is created via POST /api/workflow, VaultWorkflow generates a Workflow Intake Receipt PDF stored in your Azure Blob Storage. For governance workflows, the receipt records the Workflow ID, Correlation ID, submitter identity, and the expected output path of the sealed PDF. File it against the originating AP record in Dynamics 365 Finance as your submission confirmation.
Example: Vendor Onboarding
A complete data-collection workflow schema for vendor onboarding. Collects contact details, compliance declarations, and supporting documents across three steps, then routes to an approver before sealing the onboarding record.
VaultESign
VaultESign provides native electronic signing for documents rendered by VaultPDF. Your documents stay in your Azure subscription. Signers access a signing portal to verify identity, review documents, and apply legally-binding electronic signatures. All signing evidence and audit records are stored entirely within your tenant.