Skip to content

Example: Document Submission Workflow

This walkthrough shows how to build a workflow that asks a user to download a form, fill it out, upload the completed version, and route it through an approval before the workflow proceeds.

Use Case

An HR onboarding process requires a new employee to complete and submit a signed I-9 form. An HR manager must review and approve the submission before the employee's onboarding continues.

Prerequisites

  • A document template (blank I-9 PDF) uploaded via Document Templates (POST /api/document-templates).
  • A workflow variable hrManagerId of type String containing the HR manager's user ID.

Workflow Settings

Field Value
Category user
Subject Variable user (auto-created)
Error Strategy stop
Trigger manual

When you select the user category, the designer automatically creates a context variable named user of type User and selects it as the subject variable. Every run is linked to the employee being onboarded. This allows administrators to see all document submission activity for a person via GET /api/users/:id/workflow-activity or filter runs with GET /api/runs?subjectType=user&subjectId=....

Workflow Definition

Step Type Purpose
Start start Entry point
Submit Signed I-9 document_submission Sends the employee a blank I-9, waits for upload, then routes to HR for approval
I-9 Approved notification Sends confirmation email on approval
I-9 Rejected notification Sends rejection email and instructions to resubmit
End end Exit point

Step Configuration

Submit Signed I-9

{
  "id": "request-i9",
  "name": "Submit Signed I-9",
  "type": "document_submission",
  "config": {
    "submitterEmail": "{{user.email}}",
    "submitterId": "{{user.id}}",
    "documentLabel": "Signed I-9 Form",
    "templateId": "<uuid-of-blank-i9-template>",
    "instructions": "Download the I-9 form below, complete and sign it, then upload the signed copy as a PDF.",
    "allowedMimeTypes": ["application/pdf"],
    "maxSizeBytes": 5242880,
    "approvers": ["{{hrManagerId}}"],
    "notifySubmitter": true,
    "notifyApprovers": true
  },
  "transitions": [
    { "on": "success", "goto": "i9-approved" },
    { "on": "error", "goto": "i9-rejected" }
  ]
}

Key config fields:

  • templateId — references the blank I-9 PDF uploaded to Document Templates. The submitter sees a "Download Form" button.
  • allowedMimeTypes — restricts uploads to PDFs only.
  • maxSizeBytes — limits file size to 5 MB.
  • approvers — the HR manager reviews the uploaded document.
  • notifySubmitter / notifyApprovers — sends email notifications at each phase.

Transitions

  • success — all approvers approved the document. Routes to the confirmation notification.
  • error — any approver rejected the document. Routes to the rejection notification.

Runtime Flow

Start
Submit Signed I-9 (document_submission)
  ├── Engine sends notification to employee with "Download Form" link
  ├── Run pauses (waiting_submission)
  │   [Employee downloads blank I-9, fills it out, uploads signed PDF]
  │   [Submitter may include optional comments with their upload]
  ├── Upload creates approval records for HR manager
  ├── Task transitions to waiting_approval
  │   [Employee can WITHDRAW submission → returns to waiting_submission]
  │   [HR manager reviews document, approves or rejects]
  ├── approved ──► I-9 Approved (notification) ──► End
  └── rejected ──► Task resets to waiting_submission
                   [Employee sees rejection reason, resubmits]
                   ──► Back to waiting_approval (loop)

Step-by-step

  1. The workflow starts and reaches the Submit Signed I-9 step.
  2. The engine sends a notification email to the employee and pauses the run with status waiting_submission.
  3. The employee logs in, sees the task in My Tasks, clicks Download Form to get the blank I-9, completes it, and clicks Upload Document to submit the signed PDF. They may optionally add comments for the reviewer.
  4. The system validates the file type and size, stores the document, and creates an approval record for the HR manager. The task transitions to waiting_approval.
  5. While pending approval, the employee can withdraw the submission. This cancels pending approvals, marks the document as withdrawn, and resets the task to waiting_submission so they can upload a corrected file.
  6. The HR manager sees a pending approval in My Tasks > Approvals, clicks to review, downloads the submitted document, and approves or rejects. A rejection reason is required.
  7. If approved: the task completes with success, the workflow advances (e.g., sends a confirmation email), and the run continues.
  8. If rejected: the task resets to waiting_submission. The employee sees the rejection reason and can upload a revised document. This cycle repeats until the document is approved (or an admin manually fails/skips the step).

Document Lifecycle

Status Meaning
uploaded Document submitted, pending approval
approved All approvers approved
rejected An approver rejected; submitter may resubmit
withdrawn Submitter withdrew before approval decision
cancelled Parent run was cancelled
expired Approved document past its expiry date

Withdrawal

A submitter (or admin) can withdraw a document while it is pending approval via POST /api/documents/:id/withdraw. This:

  • Sets the document status to withdrawn
  • Cancels all pending approval records for the step
  • Resets the task to waiting_submission

Submitter Comments

When uploading a document, the submitter can include a submitterComments field in the multipart form data. These comments are stored on the document record and visible to approvers during review.

Rejection and Resubmission

When an approver rejects a document, they must provide a rejection reason. The rejection:

  • Sets the document status to rejected and stores the rejection reason
  • Resets the task to waiting_submission (does not advance the workflow)
  • The submitter sees the rejection reason in their task inbox and can upload a revised document
  • A new approval cycle starts with the resubmitted document

Variations

No Approval Required

Remove the approvers field. The document is accepted immediately upon upload and the workflow continues.

Multiple Approvers

Provide multiple user IDs in approvers. All must approve for the step to succeed; if any rejects, the step fails.

External Template URL

Instead of uploading a template to Document Templates, use templateUrl to link to an externally-hosted form:

{
  "templateUrl": "https://www.uscis.gov/sites/default/files/document/forms/i-9.pdf"
}

The submitter sees an "Open Form" link that opens in a new tab.

Training Certificate Upload (No Template)

Omit both templateId and templateUrl. The step simply asks the user to upload a document:

{
  "documentLabel": "Training Completion Certificate",
  "instructions": "Upload your certificate of completion for the required safety training.",
  "allowedMimeTypes": ["application/pdf", "image/*"]
}