System Maintenance and Advanced Workflows Routing Daily Tasks in Monday.com

Automating your daily task assignments can save hours of manual work and ensure your team knows exactly what to tackle first. This guide walks you through building a workflow that queries Monday.com via GraphQL to filter, prioritize, and route daily tasks for your team members.

By combining Zapier with a custom Python script, this workflow identifies the first job of the day for specific team members and automatically updates their task status in Monday.com.

Workflow Overview

Here is a high-level look at how the routing workflow operates:

flowchart TD
    A["Webhook Trigger"] --> B["Fetch Target Date (Monday.com)"]
    B --> C["Python Code Step"]
    C -->|GraphQL Query| D[("Monday.com API")]
    D -->|Returns Tasks| C
    C -->|Filters & Sorts| E["Extract 'First Jobs'"]
    E --> F["Loop Through Found IDs"]
    F --> G["Update Action Column to 'Route'"]

Prerequisites

Before building this workflow, ensure you have the following:

  • A Monday.com API Key (v2024-01 or later).

  • A Zapier account with access to Webhooks and Code steps.

  • A Monday.com board configured with the following column types:

Column PurposeColumn ID ExampleType
Team Memberstatus_mkm1amqeStatus / Text
Sort Numbernumeric_mkvv7q5jNumbers
Action Statuscolor_mm19bvt6Status / Button
Target Datedate_mkvn1we4Date

Building the Routing Workflow

Follow these steps to recreate the "Route Entire Day" workflow in Zapier.

  1. 1

    Set up the trigger and fetch the date

    Start your Zap with a Webhook trigger to catch the routing request. Then, add a Monday.com Get Column Values step to fetch the Target Date from the triggering item. This date will be used to filter the tasks for the day.

  2. 2

    Add the Python Code step

    This is the brain of the workflow. Add a Code by Zapier (Python) step. This script will query Monday.com for all tasks on the target date, find the tasks assigned to your VIP team members, and determine which task has the lowest "Sort Number" (their first job of the day).

    Map your api_key, parent_id, and target_date in the Zapier input data, then paste the following code:

    import requests
    import json
    
    # --- 1. CONFIGURATION ---
    api_key = input_data.get('api_key')
    parent_id = input_data.get('parent_id') 
    raw_date = input_data.get('target_date', '')
    board_id = 7932413985
    
    # Column IDs
    STAFF_COL = "status_mkm1amqe"    # Team Member
    SORT_COL  = "numeric_mkvv7q5j"   # Sort Number
    ACTION_COL = "color_mm19bvt6"    # Action Status Button
    DATE_COL   = "date_mkvn1we4"     # Target Date
    
    # Only process these team members
    vip_names = ["matt", "eric", "matteric", "kyle", "travis", "derek", "paul", "tim", "charlie", "grover"]
    
    headers = {
        "Authorization": api_key, 
        "Content-Type": "application/json", 
        "API-Version": "2024-01"
    }
    
    # Standardize Date
    clean_date = raw_date.split(" ")[0].split("T")[0]
    date_json = json.dumps([clean_date, clean_date])
    
    # --- 2. FETCH ALL ITEMS ---
    # Note: Using .replace() instead of f-strings to bypass Zapier parser errors
    query_template = 'query { boards(ids: [B_ID]) { items_page(limit: 500, query_params: { rules: [{ column_id: "D_COL", compare_value: D_VAL, operator: between }] }) { items { id name column_values(ids: ["S_COL", "N_COL"]) { id text } } } } }'
    graphql_query = query_template.replace('B_ID', str(board_id)).replace('D_COL', DATE_COL).replace('D_VAL', date_json).replace('S_COL', STAFF_COL).replace('N_COL', SORT_COL)
    
    res = requests.post("https://api.monday.com/v2", json={'query': graphql_query}, headers=headers).json()
    
    try:
        items = res['data']['boards'][0]['items_page']['items']
    except Exception as e:
        return {"status": "Error", "details": str(res)}
    
    # --- 3. MASTER SWEEP LOGIC ---
    alpha_map = {}
    
    for item in items:
        cvs = {cv['id']: cv for cv in item['column_values']}
        staff_text = cvs.get(STAFF_COL, {}).get('text', '').lower().strip()
        
        # SMART MATCH: Handles partial matches (e.g., "Matt" matching "MattEric")
        is_vip = any(vip in staff_text or staff_text in vip for vip in vip_names if staff_text != "")
        
        if is_vip:
            try:
                sort_text = cvs.get(SORT_COL, {}).get('text', '999')
                current_sort = float(sort_text) if sort_text else 999
            except:
                current_sort = 999
                
            # If this is the first job for this person, or a lower sort number
            if staff_text not in alpha_map or current_sort < alpha_map[staff_text]['sort']:
                alpha_map[staff_text] = {
                    "id": item['id'],
                    "sort": current_sort
                }
    
    # Extract IDs of the "First Jobs"
    found_ids = [{"item_id": val['id']} for val in alpha_map.values()]
    
    # --- 4. THE JANITOR (Cleanup) ---
    mut_template = 'mutation { change_multiple_column_values(item_id: P_ID, board_id: B_ID, column_values: "{\\\"A_COL\\\": null}") { id } }'
    mut_query = mut_template.replace('P_ID', str(parent_id)).replace('B_ID', str(board_id)).replace('A_COL', ACTION_COL)
    requests.post("https://api.monday.com/v2", json={'query': mut_query}, headers=headers)
    
    # --- 5. RETURN FOR LOOPING ---
    return {
        "found_ids": found_ids, 
        "photographers_found": list(alpha_map.keys()),
        "count": len(found_ids)
    }
  3. 3

    Loop through the results

    Add a Looping by Zapier step. Choose "Create Loop From Line Items" and map the found_ids array returned by your Python step. This ensures the workflow processes each identified "first job" individually.

  4. 4

    Update the routed tasks

    Finally, add a Monday.com Change Multiple Columns Value step inside your loop.

    • Set the Item ID to the ID provided by the current loop iteration.

    • Update the Action Status column (e.g., color_mm19bvt6) to your desired routing status, such as "⬆️ Route".

Zapier Python Formatting
You might notice the Python script uses .replace() instead of standard Python f-strings (e.g., f"{variable}"). This is intentional! Zapier's code parser can sometimes throw "Incomplete legacy curly" errors when it encounters complex JSON strings mixed with f-strings. Sticking to .replace() ensures your GraphQL queries run safely.

Advanced Details

How does the 'Smart Match' logic work?

The script includes a smart matching line:
is_vip = any(vip in staff_text or staff_text in vip for vip in vip_names if staff_text != "")

This ensures that if a task is assigned to a combined team (like "MattEric"), the system will still recognize it as a valid task for either "Matt" or "Eric" and route it accordingly.

What is the 'Janitor' mutation doing?

At the end of the Python script, a small GraphQL mutation runs against the parent_id (the item that triggered the webhook). It sets the action column to null, effectively resetting the trigger button so it can be used again the next day without manual cleanup.