VaultWorkflow

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 Manager

Schema 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 IDTypeSeverityWhat it checks
invoice_le_ponumericToleranceerrorInvoice total does not exceed PO amount within 5%
gr_qty_covers_invoicestandarderrorGoods Receipt quantity covers invoiced quantity
vendor_matchstandarderrorVendor ID matches across PO and Invoice
lines_price_matchstandarderrorAll line item prices match
lines_qty_matchstandardwarningAll line quantities match
tolerance_warningnumericTolerancewarningInvoice 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:

  1. Workflow Outcome. One of Approved, Approved with Exception, or Rejected. An Approved with Exception outcome means the approver reviewed one or more rule failures, provided a written justification, and approved with override.
  2. Governance Validation summary. The overall status (PASSED, EXCEPTION, or FAILED) with a count breakdown: failed, warning, and passed rules out of the total.
  3. 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:

RuleResult
Invoice total exceeds PO amountFail
GR quantity does not cover invoiced quantityPass
Vendor ID mismatch between PO and invoicePass
Line item prices do not match between PO and invoiceFail
Line quantity mismatch detectedPass
Invoice is near the PO amount ceilingWarning

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.

On this page