
Implementation Guide: Trigger content approval workflows and route assets to correct stakeholders
Step-by-step implementation guide for deploying AI to trigger content approval workflows and route assets to correct stakeholders for Marketing & Creative Agencies clients.
Hardware Procurement
VPS for n8n Automation Engine
VPS for n8n Automation Engine
$24/month MSP cost / $150/month suggested resale as managed automation hosting
Hosts the self-hosted n8n Community Edition instance that serves as the central orchestration engine for all workflow triggers, routing logic, and inter-platform integrations. Sized at 2 vCPU, 4 GB RAM, 80 GB SSD which exceeds n8n minimum requirements and provides headroom for concurrent workflow executions across multiple client accounts.
Managed PostgreSQL Database
$15/month MSP cost (included in managed hosting resale price)
Provides persistent, backed-up storage for n8n workflow execution history, credentials, and configuration. Managed PostgreSQL eliminates database maintenance burden and provides automatic daily backups, failover, and connection pooling. Required for production n8n deployments to replace the default SQLite which is not suitable for concurrent workflow executions.
Software Procurement
monday.com Pro Plan
$19/seat/month billed annually (MSP cost via partner program) / $23/seat/month suggested resale — ~$285/month cost / $345/month resale
Core project management platform and approval task backbone. Pro tier is required for its 25,000 automations/month limit, time tracking, formula columns, and chart views. Agencies use this as their single source of truth for project status, and approval tasks are created and tracked as native monday.com items with status columns mapped to approval states (Pending Review, Approved, Revision Requested, Final Approved).
Ziflow Standard Plan
$249/month MSP cost / $325/month suggested resale
Dedicated creative proofing platform that handles the actual asset review experience — markup, annotations, version comparison, and structured reviewer workflows. Supports PDF, PSD, AI, video, HTML5 banners, and live web pages. Unlimited external reviewers means client stakeholders can review and approve without consuming paid seats. SOC 2 compliant with SSO support.
Zapier Team Plan
$69/month MSP cost / $99/month suggested resale
Secondary integration layer used specifically for connecting Ziflow approval events to monday.com status updates and Slack notifications where direct webhooks are not available. The Team plan provides 2,000 tasks/month and multi-step Zaps with conditional logic. Used as a complement to n8n for vendor-specific connectors that Zapier handles more reliably out of the box.
n8n Community Edition
$0 software cost (infrastructure cost covered by DigitalOcean VPS above)
Primary workflow automation and orchestration engine. Handles the deterministic routing logic: when an asset enters the system, n8n evaluates its metadata (content type, client account, campaign phase, compliance flags) and triggers the appropriate approval chain. Self-hosting gives the MSP full control, zero per-execution fees, and the highest margin opportunity in the stack.
Slack Pro Plan
$8.75/user/month billed annually — assumed client already has this; if not, ~$131/month for 15 users
Real-time notification layer for approval requests, reminders, and status updates. Slack channels are created per client account, and bot notifications are posted when approvals are needed, overdue, or completed. Most agencies already have Slack; this line item is included only if procurement is needed.
Google Workspace Business Standard (or Microsoft 365 Business Standard)
$14/user/month (Google) or $12.50/user/month (Microsoft) — assumed client already has this
Provides SSO identity provider for all platforms in the stack, shared drive storage for asset staging, and email for external stakeholder notifications when reviewers are outside the Slack workspace. Also provides the calendar integration for deadline tracking.
Prerequisites
- Client must have an active Google Workspace or Microsoft 365 tenant with admin access for SSO configuration and API consent grants
- Minimum 25 Mbps symmetrical internet connection at the agency office (100+ Mbps recommended for agencies producing video content regularly)
- Client must provide a complete list of all active client accounts, typical content types produced (social, print, video, web, email), and the current approval chain for each — this becomes the routing rules matrix
- Client must identify at minimum: one Agency Admin (workflow owner), Creative Directors per team, Account Managers per client account, and any external client reviewers with email addresses
- Outbound HTTPS (port 443) must be open to monday.com, Ziflow, Slack, Zapier, and the n8n VPS — no special firewall rules beyond standard business configuration
- MSP must have a DigitalOcean account (or equivalent VPS provider) with billing configured and SSH key pairs generated for the n8n server
- DNS access is required to configure a subdomain (e.g., automations.agencyname.com) pointed at the n8n VPS with SSL via Let's Encrypt
- Client must provide or agree to create a dedicated service account email (e.g., automations@agencyname.com) for API integrations — this account should not be tied to any individual employee
- All stakeholders who will participate in approval workflows must have accepted invitations to the agency Slack workspace before go-live
- Docker and Docker Compose must be installed on the MSP technician's local machine for testing n8n configurations before deploying to production VPS
Installation Steps
Step 1: Provision and Secure the n8n VPS
Create a DigitalOcean Droplet to host the n8n automation engine. This server will run 24/7 and process all workflow triggers. We use Docker Compose for deployment to ensure reproducible configuration and easy updates.
doctl compute droplet create n8n-agency --region nyc3 --size s-2vcpu-4gb --image docker-20-04 --ssh-keys $(doctl compute ssh-key list --format ID --no-header | head -1) --tag-names n8n,production
doctl compute firewall create --name n8n-firewall --inbound-rules 'protocol:tcp,ports:22,address:YOUR_MSP_OFFICE_IP/32 protocol:tcp,ports:443,address:0.0.0.0/0 protocol:tcp,ports:80,address:0.0.0.0/0' --outbound-rules 'protocol:tcp,ports:all,address:0.0.0.0/0 protocol:udp,ports:all,address:0.0.0.0/0' --droplet-ids $(doctl compute droplet list --format ID --no-header | head -1)
ssh root@<DROPLET_IP>
apt update && apt upgrade -y
adduser n8nuser && usermod -aG sudo n8nuser && usermod -aG docker n8nuser
ufw allow OpenSSH && ufw allow 'Nginx Full' && ufw enable
apt install -y nginx certbot python3-certbot-nginxReplace YOUR_MSP_OFFICE_IP with the MSP's static office IP to restrict SSH access. Never leave SSH open to 0.0.0.0/0. Enable DigitalOcean monitoring alerts for CPU > 80% and disk > 75%. If client prefers AWS, use a t3.medium EC2 instance (~$30/month) with equivalent security groups.
Step 2: Configure DNS and SSL for n8n
Point a subdomain to the VPS and configure Nginx as a reverse proxy with automatic SSL certificate renewal. This gives the n8n instance a professional URL and encrypted connections.
cat > /etc/nginx/sites-available/n8n << 'EOF'
server {
server_name automations.agencyname.com;
location / {
proxy_pass http://localhost:5678;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
chunked_transfer_encoding off;
proxy_buffering off;
proxy_cache off;
}
}
EOF
ln -s /etc/nginx/sites-available/n8n /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx
certbot --nginx -d automations.agencyname.com --non-interactive --agree-tos -m msp-admin@mspcompany.comDNS propagation can take up to 48 hours but typically completes in 15 minutes with low TTL. Verify with 'dig automations.agencyname.com' before running certbot. Certbot auto-renewal is configured by default via systemd timer.
Step 3: Deploy n8n with Docker Compose
Deploy n8n using Docker Compose with PostgreSQL as the database backend, environment variables for configuration, and persistent volumes for data durability. This is the core automation engine that all routing logic runs on.
su - n8nuser
mkdir -p ~/n8n-docker && cd ~/n8n-docker
cat > docker-compose.yml << 'COMPOSE'
version: '3.8'
services:
n8n:
image: docker.n8n.io/n8nio/n8n:latest
restart: always
ports:
- '127.0.0.1:5678:5678'
environment:
- N8N_HOST=automations.agencyname.com
- N8N_PORT=5678
- N8N_PROTOCOL=https
- WEBHOOK_URL=https://automations.agencyname.com/
- N8N_BASIC_AUTH_ACTIVE=true
- N8N_BASIC_AUTH_USER=mspadmin
- N8N_BASIC_AUTH_PASSWORD=CHANGE_THIS_STRONG_PASSWORD
- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=db
- DB_POSTGRESDB_PORT=5432
- DB_POSTGRESDB_DATABASE=n8n
- DB_POSTGRESDB_USER=n8n
- DB_POSTGRESDB_PASSWORD=CHANGE_THIS_DB_PASSWORD
- GENERIC_TIMEZONE=America/New_York
- N8N_LOG_LEVEL=info
- N8N_METRICS=true
- EXECUTIONS_DATA_PRUNE=true
- EXECUTIONS_DATA_MAX_AGE=168
volumes:
- n8n_data:/home/node/.n8n
depends_on:
- db
db:
image: postgres:16-alpine
restart: always
environment:
- POSTGRES_USER=n8n
- POSTGRES_PASSWORD=CHANGE_THIS_DB_PASSWORD
- POSTGRES_DB=n8n
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
n8n_data:
postgres_data:
COMPOSE
docker compose up -d
docker compose logs -f n8nChange both CHANGE_THIS_STRONG_PASSWORD and CHANGE_THIS_DB_PASSWORD to unique, randomly generated 32+ character passwords. Store these in the MSP's password manager (e.g., IT Glue, Hudu). The WEBHOOK_URL must match the exact public URL or inbound webhooks will fail. Set GENERIC_TIMEZONE to the agency's local timezone. Execution data is pruned after 168 hours (7 days) to manage disk usage.
Step 4: Provision and Configure monday.com Workspace
Set up the monday.com workspace with a standardized board structure that supports approval workflow tracking. Each client account gets its own board, and approval items follow a consistent column schema that n8n can read and write via the API.
curl -X POST https://api.monday.com/v2 \
-H 'Authorization: Bearer MONDAY_API_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"query": "mutation { create_board (board_name: \"[Client Name] - Content Approvals\", board_kind: public, workspace_id: WORKSPACE_ID) { id } }"}'- Status Column: 'Approval Status' (labels: Pending Upload, In Review, Revision Requested, Approved, Final Approved, Published)
- People Column: 'Current Reviewer'
- People Column: 'Asset Owner'
- Dropdown Column: 'Content Type' (values: Social Post, Blog Article, Email Campaign, Print Collateral, Video, Web Banner, Landing Page)
- Dropdown Column: 'Client Account'
- Date Column: 'Review Deadline'
- Link Column: 'Ziflow Proof Link'
- Text Column: 'Revision Notes'
- Number Column: 'Revision Count'
- Status Column: 'Compliance Check' (labels: Not Required, Pending, Cleared, Flagged)
Create a monday.com Template board first, then duplicate it for each new client account. This ensures consistency. The API token should come from the service account (automations@agencyname.com), not a personal account. monday.com Pro plan is required for the automation actions/month limit (25,000) and the API rate limits needed for integration. Enable board-level permissions so external client reviewers can only see their own board.
Step 5: Configure Ziflow Proofing Workspace
Set up Ziflow with separate project folders per client account, configure reviewer groups matching the approval chains documented in discovery, and establish proof settings for each content type. Ziflow handles the actual asset review experience — markup, comments, version comparison.
Webhook URL: https://automations.agencyname.com/webhook/ziflow-eventsZiflow allows unlimited external reviewers on the Standard plan, so client stakeholders reviewing proofs do not consume paid seats. Set up email notification templates in Ziflow under Settings > Notifications to match the agency's brand. Configure proof expiration to 30 days to prevent stale proofs from cluttering the workspace. Ensure the webhook secret is stored in the MSP password manager.
Step 6: Configure Slack Integration Channels and Bot
Create a structured Slack channel hierarchy for approval notifications and set up the Slack bot that will post approval requests, reminders, and status updates. This is the real-time notification layer that keeps reviewers responsive.
The Slack bot token must be stored in n8n's credential manager, NOT hardcoded in workflows. Create a #approvals-test channel for development and testing. Consider setting Slack channel notification defaults to 'All new messages' for approval channels so reviewers don't miss requests. If the agency uses Microsoft Teams instead of Slack, replace this step with a Teams Incoming Webhook connector per channel.
Step 7: Build the Asset Routing Rules Matrix in n8n
Create the core n8n workflow that implements the deterministic routing logic. When a new asset enters the system (via Ziflow webhook, monday.com status change, or direct API call), this workflow evaluates the asset metadata and routes it to the correct approval chain, updates monday.com, and sends Slack notifications.
The routing rules matrix must be built from the discovery document created in prerequisites. Every combination of content type + client account + compliance requirement should map to a specific Ziflow workflow template and reviewer sequence. See the custom_ai_components section for the complete workflow specification. Test each routing path individually before activating the full workflow.
Step 8: Configure Zapier Bridges for Native Connectors
Set up Zapier Zaps that handle specific integration paths where Zapier's pre-built connectors are more reliable than raw API calls — specifically the Ziflow-to-monday.com proof status sync and the monday.com-to-Ziflow proof creation trigger.
Zapier Zap 1: Ziflow Proof Decision → monday.com Status Update
Zapier Zap 2: monday.com New Item → Ziflow Create Proof
Zapier Zap 3: Overdue Reminder Escalation
Zapier Team plan allows 2,000 tasks/month which is sufficient for a 15-person agency processing ~200-400 assets/month. Monitor task usage in the first month and upgrade if needed. Each Zap should have error notification emails sent to the MSP's support inbox. Name Zaps with a consistent prefix like '[Agency] Approval -' for easy identification.
Step 9: Configure monday.com Native Automations
Set up monday.com's built-in automation recipes that handle intra-board logic — moving items between groups, assigning reviewers, setting deadlines, and triggering status changes. These complement the n8n and Zapier integrations by handling logic that lives entirely within monday.com.
In each client approval board, add these automations:
monday.com Pro plan includes 25,000 automation actions/month. Monitor usage in the first month — a 15-person agency typically uses 3,000-8,000 actions. If approaching the limit, move lower-priority automations to n8n. Use monday.com's Automation Activity Log to troubleshoot any misfires during testing.
Step 10: Set Up SSO and User Provisioning
Configure Single Sign-On across all platforms using the agency's Google Workspace or Azure AD identity provider. This ensures one login for all tools, automatic user deprovisioning when employees leave, and meets compliance requirements for access control.
Google Workspace SSO Configuration (if using Google)
Azure AD SSO Configuration (if using Microsoft 365)
SSO configuration requires admin access to both the identity provider and each SaaS platform. Ziflow SSO is available on Standard plan. monday.com SSO (SAML) requires Enterprise plan — if client is on Pro, use Google/Microsoft OAuth sign-in instead (less secure but still single-identity). Test SSO login for each platform before removing password-based access. Create a break-glass local admin account for each platform in case SSO fails.
Step 11: Import Existing Projects and Historical Data
Migrate the agency's current active projects into the new approval workflow system. This includes creating monday.com boards for each active client, importing any in-progress approval items, and setting up the initial state so the team can start using the system without a gap in tracking.
- For each active client board: Create client folder in Ziflow
- Upload any assets currently in review
- Link Ziflow proofs to monday.com items via the Ziflow Proof Link column
# Run the n8n 'Initial Sync' workflow (see custom_ai_components) to validate all connectionsDo NOT attempt to migrate historical completed projects — only active and recent (last 30 days) items. Historical data creates noise and confusion. Allocate 2-4 hours per client account for migration depending on volume. Have the Account Manager for each client verify the migrated data before go-live.
Step 12: Conduct User Acceptance Testing
Execute a structured testing protocol that validates every routing path, notification, and integration before going live. Use test assets that represent each content type and client account combination documented in the routing rules matrix.
For each test, verify:
Testing should be performed by the MSP technician first, then repeated with 2-3 agency power users as a supervised pilot. Keep the test board and channels active for 1 week post-go-live as a safe space for users to experiment. Common failure points: webhook URL mismatches, timezone differences causing incorrect deadline calculations, and Slack channel ID vs. channel name confusion in n8n.
Custom AI Components
Asset Routing Engine
Type: workflow The core n8n workflow that receives webhook events from Ziflow and monday.com, evaluates asset metadata against the routing rules matrix, and triggers the appropriate approval chain. This is the central orchestration component that replaces manual asset routing with deterministic automation. It handles: new asset upload routing, approval stage progression, revision loop management, escalation triggers, and cross-platform state synchronization.
n8n Workflow: Asset Routing Engine
Workflow JSON (Import into n8n)
{
"name": "Asset Routing Engine",
"nodes": [
{
"name": "Ziflow Webhook",
"type": "n8n-nodes-base.webhook",
"position": [250, 300],
"parameters": {
"path": "ziflow-events",
"httpMethod": "POST",
"responseMode": "onReceived",
"responseData": "allEntries"
}
},
{
"name": "Parse Event Type",
"type": "n8n-nodes-base.switch",
"position": [450, 300],
"parameters": {
"dataType": "string",
"value1": "={{$json.event_type}}",
"rules": {
"rules": [
{"value2": "proof.created", "output": 0},
{"value2": "proof.decision.made", "output": 1},
{"value2": "proof.comment.added", "output": 2}
]
}
}
},
{
"name": "Extract Metadata",
"type": "n8n-nodes-base.set",
"position": [650, 200],
"parameters": {
"values": {
"string": [
{"name": "asset_name", "value": "={{$json.proof.name}}"},
{"name": "client_account", "value": "={{$json.proof.folder_name}}"},
{"name": "content_type", "value": "={{$json.proof.tags[0] || 'General'}}"},
{"name": "proof_id", "value": "={{$json.proof.id}}"},
{"name": "proof_url", "value": "={{$json.proof.url}}"}
]
}
}
},
{
"name": "Routing Rules",
"type": "n8n-nodes-base.switch",
"position": [850, 200],
"parameters": {
"dataType": "string",
"value1": "={{$json.content_type}}",
"rules": {
"rules": [
{"value2": "Social Post", "output": 0},
{"value2": "Blog Article", "output": 1},
{"value2": "Email Campaign", "output": 2},
{"value2": "Print Collateral", "output": 3},
{"value2": "Video", "output": 4},
{"value2": "Web Banner", "output": 5},
{"value2": "Landing Page", "output": 6}
]
},
"fallbackOutput": "extra"
}
},
{
"name": "Set Social Routing",
"type": "n8n-nodes-base.set",
"position": [1050, 50],
"parameters": {
"values": {
"string": [
{"name": "workflow_template", "value": "Standard Review"},
{"name": "reviewer_sequence", "value": "Social Media Manager,Account Manager,Client"},
{"name": "sla_hours", "value": "24"},
{"name": "slack_channel_prefix", "value": "approvals"}
]
}
}
},
{
"name": "Set Print Routing",
"type": "n8n-nodes-base.set",
"position": [1050, 250],
"parameters": {
"values": {
"string": [
{"name": "workflow_template", "value": "Compliance Required"},
{"name": "reviewer_sequence", "value": "Creative Director,Compliance Officer,Account Manager,Client"},
{"name": "sla_hours", "value": "48"},
{"name": "slack_channel_prefix", "value": "approvals"}
]
}
}
},
{
"name": "Set Video Routing",
"type": "n8n-nodes-base.set",
"position": [1050, 450],
"parameters": {
"values": {
"string": [
{"name": "workflow_template", "value": "Standard Review"},
{"name": "reviewer_sequence", "value": "Video Producer,Creative Director,Account Manager,Client"},
{"name": "sla_hours", "value": "72"},
{"name": "slack_channel_prefix", "value": "approvals"}
]
}
}
},
{
"name": "Create Monday Item",
"type": "n8n-nodes-base.mondayCom",
"position": [1300, 300],
"parameters": {
"resource": "boardItem",
"operation": "create",
"boardId": "={{$env.MONDAY_BOARD_MAP[$json.client_account]}}",
"itemName": "={{$json.asset_name}}",
"columnValues": {
"approval_status": "In Review",
"content_type": "={{$json.content_type}}",
"current_reviewer": "={{$json.reviewer_sequence.split(',')[0]}}",
"review_deadline": "={{$now.plus({hours: parseInt($json.sla_hours)}).toISO()}}",
"ziflow_proof_link": "={{$json.proof_url}}",
"revision_count": 0
}
}
},
{
"name": "Notify Slack",
"type": "n8n-nodes-base.slack",
"position": [1500, 300],
"parameters": {
"channel": "={{$json.slack_channel_prefix + '-' + $json.client_account.toLowerCase().replace(/ /g, '-')}}",
"text": "",
"blocksUi": {
"blocksValues": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "🎨 *New Approval Request*\n*Asset:* {{$json.asset_name}}\n*Type:* {{$json.content_type}}\n*Client:* {{$json.client_account}}\n*Reviewer:* {{$json.reviewer_sequence.split(',')[0]}}\n*Deadline:* {{$now.plus({hours: parseInt($json.sla_hours)}).toFormat('MMM dd, yyyy h:mm a')}}"
}
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {"type": "plain_text", "text": "Review in Ziflow"},
"url": "{{$json.proof_url}}",
"style": "primary"
}
]
}
]
}
}
}
],
"connections": {
"Ziflow Webhook": {"main": [[{"node": "Parse Event Type", "type": "main", "index": 0}]]},
"Parse Event Type": {"main": [[{"node": "Extract Metadata", "type": "main", "index": 0}], [{"node": "Handle Decision", "type": "main", "index": 0}], [{"node": "Handle Comment", "type": "main", "index": 0}]]},
"Extract Metadata": {"main": [[{"node": "Routing Rules", "type": "main", "index": 0}]]},
"Routing Rules": {"main": [[{"node": "Set Social Routing"}], [{"node": "Set Blog Routing"}], [{"node": "Set Email Routing"}], [{"node": "Set Print Routing"}], [{"node": "Set Video Routing"}], [{"node": "Set WebBanner Routing"}], [{"node": "Set LandingPage Routing"}]]},
"Set Social Routing": {"main": [[{"node": "Create Monday Item"}]]},
"Set Print Routing": {"main": [[{"node": "Create Monday Item"}]]},
"Set Video Routing": {"main": [[{"node": "Create Monday Item"}]]},
"Create Monday Item": {"main": [[{"node": "Notify Slack"}]]}
}
}Configuration Notes
- The
MONDAY_BOARD_MAPenvironment variable in n8n should be a JSON object mapping client account names to monday.com board IDs:{"Acme Corp": "1234567890", "Globex": "0987654321"} - Add Set nodes for each content type following the Social/Print/Video pattern above
- The reviewer_sequence is a comma-separated string parsed at each approval stage
- Duplicate the Routing Rules switch for additional content types specific to the agency
- The fallback output handles any unrecognized content types by routing to the Creative Director as default reviewer
Approval Stage Progression Workflow
Type: workflow Handles the progression of assets through multi-stage approval chains. When a reviewer approves at one stage, this workflow automatically advances to the next reviewer in the sequence, updates monday.com, notifies the next reviewer via Slack, and handles revision loops where a reviewer requests changes.
n8n Workflow: Approval Stage Progression
Trigger: Ziflow webhook event `proof.decision.made`
Logic Flow
items_page_by_column_values where ziflow_proof_link = proof_url — Extract: current monday item ID, current reviewer_sequence position, revision_countIf APPROVED
- Parse reviewer_sequence string, find current reviewer's position
- If NOT last reviewer: Advance current_reviewer to next in sequence
- Update monday.com item: current_reviewer = next person
- If next reviewer is 'Client': Update status to 'Client Review'
- Post Slack notification to next reviewer
- Post Slack update to channel: '✅ [Reviewer] approved [Asset]. Next: [Next Reviewer]'
- If LAST reviewer (final approval): Update monday.com status to 'Final Approved'
- Move item to Completed group
- Post Slack celebration: '🎉 [Asset] for [Client] is FINAL APPROVED! Ready for publishing.'
- Send email notification to Asset Owner
If CHANGES_REQUESTED
- Increment revision_count on monday.com
- Update status to 'Revision Requested'
- Reset current_reviewer to Asset Owner
- Copy Ziflow revision comments to monday.com Revision Notes column
- Post Slack notification to Asset Owner: '🔄 Revision requested on [Asset] by [Reviewer]: [Comments summary]'
- If revision_count > 3: Also post to #approvals-urgent with escalation flag
Error Handling
- If monday.com item not found: Log error, post to #approvals-urgent
- If Slack post fails: Fall back to email notification
- All errors logged to n8n execution log with full context
Key Implementation Detail — Reviewer Sequence Tracking
In a Function node, track stage progression:
const sequence = $json.reviewer_sequence.split(',');
const currentIndex = sequence.indexOf($json.current_reviewer_role);
const nextIndex = currentIndex + 1;
if (nextIndex < sequence.length) {
return {
json: {
...$json,
next_reviewer: sequence[nextIndex],
is_final: false,
stage_number: nextIndex + 1,
total_stages: sequence.length
}
};
} else {
return {
json: {
...$json,
next_reviewer: null,
is_final: true,
stage_number: sequence.length,
total_stages: sequence.length
}
};
}Revision Loop Prevention
- Maximum 5 revision cycles before automatic escalation to Creative Director + Account Manager
- After 3 revisions, Slack message includes: '⚠️ This asset has been revised 3+ times. Consider scheduling a live review call.'
- Track revision reasons in monday.com for pattern analysis
Overdue Escalation Monitor
Type: workflow A scheduled n8n workflow that runs every 2 hours during business hours, checks all monday.com boards for items past their review deadline, and sends escalation notifications to the appropriate managers. Implements a tiered escalation: first reminder at deadline, second to manager at deadline +4 hours, third to director at deadline +8 hours.
Implementation
n8n Workflow: Overdue Escalation Monitor
Trigger: Cron schedule — every 2 hours, Monday-Friday, 8 AM - 8 PM agency timezone
{
"name": "Overdue Escalation Monitor",
"nodes": [
{
"name": "Schedule Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"parameters": {
"rule": {
"interval": [{"field": "hours", "hoursInterval": 2}]
}
}
},
{
"name": "Get All Approval Boards",
"type": "n8n-nodes-base.mondayCom",
"parameters": {
"resource": "board",
"operation": "getAll",
"returnAll": true
}
},
{
"name": "Filter Approval Boards",
"type": "n8n-nodes-base.filter",
"parameters": {
"conditions": {
"string": [{"value1": "={{$json.name}}", "operation": "contains", "value2": "Content Approvals"}]
}
}
},
{
"name": "Get Items In Review",
"type": "n8n-nodes-base.mondayCom",
"parameters": {
"resource": "boardItem",
"operation": "getAll",
"boardId": "={{$json.id}}",
"returnAll": true
}
},
{
"name": "Check Overdue",
"type": "n8n-nodes-base.function",
"parameters": {
"functionCode": "const items = $input.all();\nconst now = new Date();\nconst overdueItems = [];\n\nfor (const item of items) {\n const data = item.json;\n const status = data.column_values?.find(c => c.id === 'approval_status');\n const deadline = data.column_values?.find(c => c.id === 'review_deadline');\n \n if (status?.text === 'In Review' || status?.text === 'Client Review') {\n const deadlineDate = new Date(deadline?.text);\n if (deadlineDate < now) {\n const hoursOverdue = Math.floor((now - deadlineDate) / (1000 * 60 * 60));\n let escalation_level = 'reminder';\n if (hoursOverdue >= 8) escalation_level = 'director';\n else if (hoursOverdue >= 4) escalation_level = 'manager';\n \n overdueItems.push({\n json: {\n item_name: data.name,\n board_name: data.board?.name || 'Unknown',\n current_reviewer: data.column_values?.find(c => c.id === 'current_reviewer')?.text,\n hours_overdue: hoursOverdue,\n escalation_level: escalation_level,\n ziflow_link: data.column_values?.find(c => c.id === 'ziflow_proof_link')?.text,\n client_account: data.column_values?.find(c => c.id === 'client_account')?.text\n }\n });\n }\n }\n}\n\nreturn overdueItems;"
}
},
{
"name": "Route by Escalation Level",
"type": "n8n-nodes-base.switch",
"parameters": {
"dataType": "string",
"value1": "={{$json.escalation_level}}",
"rules": {
"rules": [
{"value2": "reminder", "output": 0},
{"value2": "manager", "output": 1},
{"value2": "director", "output": 2}
]
}
}
},
{
"name": "Send Reminder",
"type": "n8n-nodes-base.slack",
"parameters": {
"channel": "={{$json.client_account ? 'approvals-' + $json.client_account.toLowerCase().replace(/ /g, '-') : 'approvals-internal'}}",
"text": "⏰ *Reminder:* {{$json.item_name}} for {{$json.client_account}} is {{$json.hours_overdue}} hours past deadline. {{$json.current_reviewer}}, please review: {{$json.ziflow_link}}"
}
},
{
"name": "Send Manager Escalation",
"type": "n8n-nodes-base.slack",
"parameters": {
"channel": "approvals-urgent",
"text": "⚠️ *ESCALATION:* {{$json.item_name}} for {{$json.client_account}} is {{$json.hours_overdue}} hours overdue. Assigned reviewer: {{$json.current_reviewer}}. Account Manager — please intervene. {{$json.ziflow_link}}"
}
},
{
"name": "Send Director Escalation",
"type": "n8n-nodes-base.slack",
"parameters": {
"channel": "approvals-urgent",
"text": "🚨 *CRITICAL:* {{$json.item_name}} for {{$json.client_account}} is {{$json.hours_overdue}} hours overdue (8+ hours). Creative Director — immediate action required. Reviewer: {{$json.current_reviewer}}. {{$json.ziflow_link}}"
}
}
]
}Schedule Configuration
- Run every 2 hours between 8 AM and 8 PM, Monday through Friday
- Agency timezone configured in n8n environment variable GENERIC_TIMEZONE
- Do NOT run on weekends or agency-designated holidays (maintain a holiday list in n8n static data)
- First run at 10 AM to allow morning processing time
Client Board Provisioning Workflow
Type: workflow
An on-demand n8n workflow triggered via a simple form or API call that automates the setup of a new client account across all platforms — creates the monday.com board from template, Ziflow folder, Slack channel, and configures the routing rules for the new client. Reduces new client onboarding from 2 hours of manual setup to a 5-minute form submission.
Implementation
n8n Workflow: Client Board Provisioning
Trigger: n8n Form Trigger or Webhook POST with payload:
{
"client_name": "Acme Corp",
"account_manager_email": "am@agency.com",
"creative_director_email": "cd@agency.com",
"client_reviewer_emails": ["marketing@acme.com", "cmo@acme.com"],
"content_types": ["Social Post", "Blog Article", "Email Campaign"],
"compliance_required": false,
"default_sla_hours": 48
}Steps
acme-corpStep 2 — Create monday.com Board (HTTP Request node)
POST https://api.monday.com/v2
Authorization: Bearer {{$credentials.mondayApi.apiToken}}
{
"query": "mutation { duplicate_board (board_id: TEMPLATE_BOARD_ID, duplicate_type: duplicate_board_with_structure, board_name: \"{{$json.client_name}} - Content Approvals\") { board { id } } }"
}- Store returned board_id
- Update the MONDAY_BOARD_MAP environment variable (or a static data store in n8n)
Step 3 — Create Ziflow Folder (HTTP Request node)
POST https://api.ziflow.com/v1/folders
Authorization: Bearer {{$credentials.ziflowApi.apiToken}}
{
"name": "{{$json.client_name}}",
"default_workflow_id": "{{$json.compliance_required ? COMPLIANCE_WORKFLOW_ID : STANDARD_WORKFLOW_ID}}"
}Step 4 — Invite External Reviewers to Ziflow (Loop node): For each email in client_reviewer_emails:
POST https://api.ziflow.com/v1/users/invite
{
"email": "{{$json.email}}",
"role": "reviewer",
"folder_ids": ["{{$json.ziflow_folder_id}}"]
}approvals-{{$json.slug}} — Set channel topic: Approval notifications for {{$json.client_name}} — Invite Account Manager and Creative Director — Post welcome message with workflow overview✅ New client provisioned: {{$json.client_name}}. Board: [link], Ziflow: [link], Channel: #approvals-{{$json.slug}} — Send email to Account Manager with setup summary and onboarding checklistError Handling
If any step fails, roll back previous steps (delete created resources), post error details to #approvals-urgent, and log full error context to the n8n execution log for MSP troubleshooting.
Weekly Approval Analytics Report
Type: workflow A scheduled weekly workflow that compiles approval metrics from monday.com — average approval time by content type, number of revision cycles, overdue rate, and bottleneck identification — and posts a formatted summary to Slack and emails it to agency leadership. Provides the data needed to continuously optimize approval workflows.
Implementation
n8n Workflow: Weekly Approval Analytics
Trigger: Cron — Every Monday at 9:00 AM agency timezone
const items = $input.all();
const now = new Date();
const weekAgo = new Date(now - 7 * 24 * 60 * 60 * 1000);
const metrics = {
total_completed: 0,
total_in_progress: 0,
avg_approval_hours: 0,
revision_rate: 0,
overdue_count: 0,
by_content_type: {},
by_client: {},
bottleneck_reviewer: null,
longest_pending: null
};
let totalHours = 0;
let revisedCount = 0;
for (const item of items) {
const d = item.json;
const contentType = d.content_type || 'Unknown';
const client = d.client_account || 'Unknown';
if (!metrics.by_content_type[contentType]) {
metrics.by_content_type[contentType] = { completed: 0, avg_hours: 0, revisions: 0 };
}
if (!metrics.by_client[client]) {
metrics.by_client[client] = { completed: 0, avg_hours: 0, revisions: 0 };
}
if (d.status === 'Final Approved') {
metrics.total_completed++;
const hours = d.completion_hours || 0;
totalHours += hours;
metrics.by_content_type[contentType].completed++;
metrics.by_client[client].completed++;
}
if (d.revision_count > 0) {
revisedCount++;
metrics.by_content_type[contentType].revisions += d.revision_count;
}
if (d.status === 'In Review' && new Date(d.deadline) < now) {
metrics.overdue_count++;
}
}
metrics.avg_approval_hours = metrics.total_completed > 0 ?
Math.round(totalHours / metrics.total_completed) : 0;
metrics.revision_rate = items.length > 0 ?
Math.round((revisedCount / items.length) * 100) : 0;
return [{ json: metrics }];📊 *Weekly Approval Report* ({{weekStart}} — {{weekEnd}})
*Overall Metrics:*
• Assets Completed: {{total_completed}}
• Currently In Progress: {{total_in_progress}}
• Average Approval Time: {{avg_approval_hours}} hours
• Revision Rate: {{revision_rate}}%
• Currently Overdue: {{overdue_count}}
*By Content Type:*
{{#each by_content_type}}
• {{@key}}: {{this.completed}} completed, avg {{this.avg_hours}}h, {{this.revisions}} revisions
{{/each}}
*By Client:*
{{#each by_client}}
• {{@key}}: {{this.completed}} completed
{{/each}}
*Action Items:*
{{#if overdue_count}}⚠️ {{overdue_count}} items currently overdue — review in #approvals-urgent{{/if}}
{{#if high_revision_types}}🔄 High revision rates on: {{high_revision_types}} — consider adding a brief checkpoint before formal review{{/if}}Value to MSP
- This report demonstrates ongoing value to the client
- Metrics inform workflow optimization recommendations (upsell opportunity)
- Trending data helps justify the managed services retainer
Testing & Validation
- TEST 1 — Social Post Routing: Upload a test social media image to the test Ziflow folder tagged 'Social Post'. Verify within 60 seconds: (a) n8n execution log shows successful webhook receipt, (b) a new item appears on the test monday.com board with status 'In Review' and Content Type 'Social Post', (c) Current Reviewer is set to 'Social Media Manager', (d) Review Deadline is set to 24 hours from now, (e) Slack notification appears in #approvals-test with asset name, reviewer, and Ziflow link button.
- TEST 2 — Print Collateral Compliance Routing: Upload a test PDF tagged 'Print Collateral' to the test Ziflow folder. Verify the Compliance Required workflow template is selected in Ziflow, and the reviewer sequence includes Compliance Officer as the first reviewer. Verify the monday.com item shows a 48-hour SLA deadline and the Compliance Check column is set to 'Pending'.
- TEST 3 — Approval Stage Progression: In Ziflow, approve the test social post as the Social Media Manager. Verify: (a) monday.com current_reviewer updates to Account Manager, (b) Slack posts '✅ Social Media Manager approved [asset]. Next: Account Manager', (c) Ziflow advances to the next proof stage. Then approve as Account Manager and verify progression to Client stage.
- TEST 4 — Revision Request Loop: In Ziflow, select 'Changes Requested' on a test proof and add a comment 'Please adjust the color palette'. Verify: (a) monday.com status changes to 'Revision Requested', (b) Revision Count increments to 1, (c) Revision Notes column contains the Ziflow comment text, (d) Slack notification goes to the Asset Owner with the revision details, (e) Current Reviewer resets to Asset Owner.
- TEST 5 — Overdue Escalation Tier 1: Create a monday.com item with Review Deadline set to 1 hour ago and status 'In Review'. Manually trigger the Overdue Escalation Monitor workflow. Verify a reminder message posts to the appropriate client approval channel with the reviewer's name and Ziflow link.
- TEST 6 — Overdue Escalation Tier 2: Create a monday.com item with Review Deadline set to 5 hours ago. Trigger the escalation workflow. Verify the message posts to #approvals-urgent (not just the client channel) with 'ESCALATION' prefix and mentions the Account Manager.
- TEST 7 — Overdue Escalation Tier 3: Create a monday.com item with Review Deadline set to 9 hours ago. Verify the message posts to #approvals-urgent with 'CRITICAL' prefix and mentions the Creative Director.
- TEST 8 — New Client Provisioning: Trigger the Client Board Provisioning workflow with test data for a fictional client 'Test Industries'. Verify: (a) A new monday.com board 'Test Industries - Content Approvals' is created with all required columns, (b) A Ziflow folder 'Test Industries' exists, (c) Slack channel #approvals-test-industries is created, (d) Confirmation message posts to #approvals-internal. Then clean up all test resources.
- TEST 9 — Final Approval End-to-End: Walk through a complete approval lifecycle for one test asset — upload, route, review at each stage, approve at each stage, reach 'Final Approved'. Verify the celebration message in Slack, the item moves to the Completed group in monday.com, and the email notification reaches the Asset Owner. Time the entire process and confirm it completes in under 5 minutes of active reviewer time.
- TEST 10 — Zapier Integration Sync: Create a proof in Ziflow and make a decision. Verify the Zapier Zap correctly updates the corresponding monday.com item status within 2 minutes. Check Zapier task history for successful execution with no errors.
- TEST 11 — SSO Login Verification: Log out of all platforms. Attempt to log into monday.com, Ziflow, and Slack using SSO. Verify all three succeed with a single identity provider login and that user profiles (name, email) are correctly mapped.
- TEST 12 — Error Handling: Temporarily disable the monday.com API token in n8n. Upload a test proof to Ziflow. Verify n8n logs the error, does NOT crash the workflow, and posts an error notification to #approvals-urgent indicating the monday.com integration failed. Re-enable the token and confirm normal operation resumes.
- TEST 13 — Weekly Analytics Report: Manually trigger the Weekly Approval Analytics workflow. Verify a formatted report appears in #approvals-internal with all metric categories (completed count, average approval time, revision rate, overdue count, by content type, by client). Verify the email is received by the designated recipients.
Client Handoff
Client Handoff Checklist
Training Sessions (Schedule 2 sessions, 90 minutes each)
Session 1: Power Users — Agency Admin, Creative Directors, Account Managers (90 min)
- How to read and manage the monday.com approval boards: item creation, status changes, column meanings
- How to review and approve in Ziflow: markup tools, version comparison, decision buttons, comments
- How the routing logic works: which content types go to which reviewers, SLA timelines, escalation tiers
- How to add external client reviewers to Ziflow for a new campaign
- How to interpret the weekly analytics report and identify bottlenecks
- Live walkthrough of an asset from upload through final approval
- Q&A and hands-on practice with test assets
Session 2: All Staff — Full team including designers and copywriters (60 min)
- How to submit assets for approval: uploading to Ziflow, tagging content type, selecting client folder
- How to respond to revision requests: reading comments, uploading new versions
- How Slack notifications work: what each notification type means, what action to take
- What NOT to do: approving via email/Slack instead of Ziflow, changing monday.com statuses manually
- Quick reference card walkthrough
Documentation to Leave Behind
Success Criteria to Review Together at Handoff
Maintenance
Ongoing Maintenance Plan
...
Monthly Maintenance Tasks (MSP Responsibility)
docker compose ps
df -h
docker compose logs --tail=100 n8n | grep -i error
certbot certificates
docker pull docker.n8n.io/n8nio/n8n:latestQuarterly Maintenance Tasks
docker exec n8n n8n export:workflow --all --output=/backups/workflows.jsonSLA Considerations
- Response Time: 4-hour response for workflow-breaking issues (routing stopped, webhooks failing); 24-hour response for non-critical issues (notification formatting, report inaccuracies).
- Uptime Target: 99.5% for the n8n automation engine (translates to ~3.6 hours/month allowed downtime). This is achievable with a single VPS but does not provide HA. If client requires higher uptime, recommend the n8n Cloud alternative.
- Planned Maintenance Window: Sunday 2-6 AM agency timezone for updates and patches, communicated 48 hours in advance.
Escalation Path
Update and Change Management
- All workflow changes are tested in a cloned n8n workflow before modifying production. The test workflow uses test monday.com boards and test Slack channels.
- n8n Docker image updates are applied monthly, tested in staging first. Pin to specific version tags in production (e.g.,
n8nio/n8n:1.50.2) rather thanlatestafter initial deployment stabilizes. - monday.com and Ziflow platform updates happen automatically (SaaS); monitor vendor changelogs for breaking changes to APIs or webhooks.
- Document all changes in the MSP's ticketing system with before/after configuration screenshots.
Alternatives
All-in-One with monday.com + Make.com (No Ziflow)
Replace Ziflow with monday.com's native file proofing and markup features, and replace n8n + Zapier with Make.com as the single automation platform. monday.com has built-in file annotations and approval status columns, while Make.com provides visual workflow automation with strong monday.com integration at a lower price point than Zapier.
Asana + Filestage + Power Automate (Microsoft-Native Stack)
For agencies already invested in Microsoft 365, use Asana (which has native approval task types and a rules engine) as the PM backbone, Filestage for creative proofing (GDPR-compliant, flat-rate pricing), and Microsoft Power Automate for orchestration. Power Automate is included in many M365 plans or available at $15/user/month.
Teamwork.com + Ziflow + Zapier (Agency-Specialized PM)
Replace monday.com with Teamwork.com, which is specifically designed for client-facing agency work with built-in time tracking, budgeting, and resource planning. Keep Ziflow for proofing and Zapier for automation. This simplifies the stack by using an agency-purpose-built PM tool.
Enterprise: Workfront + Frame.io + Custom Integration
For large agencies (50+ staff) or agencies that are part of media conglomerates, use Adobe Workfront (enterprise work management with native Adobe CC integration), Frame.io (video-first proofing now owned by Adobe), and custom API integrations built on the agency's existing infrastructure. This is the premium stack for organizations already in the Adobe ecosystem.
Lightweight: Planable + Slack Workflows (Social-Only Agencies)
For agencies that exclusively produce social media content, use Planable ($33-49/workspace/month) which combines content planning, visual preview in platform-native formats, and built-in approval workflows in a single tool. Supplement with native Slack workflows for internal notifications. No additional automation platform needed.
Want early access to the full toolkit?