Skip to main content

Use One Flow or Logic App to Trigger Multiple SharePoint Lists from Multiple SharePoint Sites

Step-by-step guide to monitoring multiple SharePoint lists across multiple sites using just two Power Automate flows with webhooks instead of dozens of individual flows.

· By Ulrich Bojko · 11 min read

If you need to monitor 50 SharePoint lists for changes, the obvious approach requires 50 separate flows. This creates a management nightmare with 50 flows to maintain and update.

The solution: Use SharePoint webhooks. Instead of 50 flows, you need exactly two:

  1. Subscription Flow – Creates and renews webhook subscriptions (runs monthly)
  2. Handler Flow – Receives notifications and processes changes (triggered automatically)

What you'll learn: How to monitor multiple SharePoint lists across multiple sites using just two flows instead of dozens.

Time required: 60-90 minutes

Prerequisites:

  • Power Automate Premium license OR Azure Logic Apps access
  • SharePoint site collection administrator permissions
  • A SharePoint site for storing configuration lists

Architecture Overview

Architecture Overview showing Subscription Flow and Handler Flow
Architecture overview: Two flows working together to monitor multiple SharePoint lists

The Subscription Flow runs once per month. It loops through all your sites, finds lists matching your criteria, and creates webhook subscriptions pointing to the Handler Flow.

When something changes on any monitored list, SharePoint sends a notification to the Handler Flow. The Handler Flow then queries the list to find what changed and executes your business logic.

💡
Licensing Note: This solution requires Power Automate Premium because the Handler Flow uses the "When a HTTP request is received" trigger (a premium connector). Alternative: Use Azure Logic Apps with consumption-based pricing—often more cost-effective for low-volume scenarios.

Part 1: Create the Configuration Lists

Before building the flows, you need two SharePoint lists to store configuration data.

Step 1.1: Create the Sites List

This list stores the SharePoint sites you want to monitor.

Step 1.1.1: Navigate to Your Management Site

  1. Open your browser and go to the SharePoint site where you want to store the configuration
  2. This could be any site, for example: https://yourtenant.sharepoint.com/sites/management

Step 1.1.2: Create a New List

  1. Click + New in the top left
  2. Click List
  3. Select Blank list
  4. Enter the name: Sites
  5. Click Create

Step 1.1.3: Add the URL Column

The list already has a Title column. You need to add one more column.

  1. Click + Add column
  2. Select Single line of text
  3. Enter the name: URL
  4. Click Save

Step 1.1.4: Add Your Sites

Add one row for each site you want to monitor:

Title URL
Sales Site https://yourtenant.sharepoint.com/sites/sales
HR Site https://yourtenant.sharepoint.com/sites/hr
Projects Site https://yourtenant.sharepoint.com/sites/projects

Step 1.2: Create the Timestamps List

This list tracks when each monitored list was last processed.

Step 1.2.1: Create the List

  1. Click + New in the top left
  2. Click List
  3. Select Blank list
  4. Enter the name: Timestamps
  5. Click Create

Step 1.2.2: Add the Required Columns

Add three columns:

Column 1: listGUID

  1. Click + Add column
  2. Select Single line of text
  3. Enter the name: listGUID
  4. Click Save

Column 2: SiteURL

  1. Click + Add column
  2. Select Single line of text
  3. Enter the name: SiteURL
  4. Click Save

Column 3: LastModificationDateTime

  1. Click + Add column
  2. Select Date and time
  3. Enter the name: LastModificationDateTime
  4. Click Save

You'll populate this list later when the Subscription Flow runs.


Part 2: Create the Handler Flow

You must create the Handler Flow first because you need its URL for the Subscription Flow.

Step 2.1: Create a New Flow

Step 2.1.1: Open Power Automate

  1. Go to https://make.powerautomate.com
  2. Sign in with your Microsoft 365 account

Step 2.1.2: Create the Flow

  1. Click + Create in the left menu
  2. Click Instant cloud flow
  3. Enter the flow name: Webhook Handler
  4. Scroll down and select When a HTTP request is received
  5. Click Create

Step 2.2: Configure the HTTP Trigger

Step 2.2.1: Get the HTTP URL

After creating the flow, you'll see the trigger action open.

  1. Leave Request Body JSON Schema empty for now
  2. Click Save in the top right
  3. After saving, the HTTP POST URL field will show a long URL
  4. Click the copy icon next to the URL
  5. Save this URL somewhere – you'll need it for the Subscription Flow

The URL looks like this:

https://prod-XX.westeurope.logic.azure.com:443/workflows/abc123.../triggers/manual/paths/invoke?api-version=...

Step 2.3: Add the Response Action

SharePoint expects a response within 5 seconds. You must respond immediately.

Step 2.3.1: Add the Response

  1. Click + New step
  2. Search for Response
  3. Select Response (under "Request")
  4. Set Status Code to: 200
  5. Leave Body empty

Step 2.4: Add Variables

You need to initialize variables to store data during processing.

Step 2.4.1: Add Variable for Headers

  1. Click + New step
  2. Search for Initialize variable
  3. Select Initialize variable
  4. Configure:
    • Name: header_nometa
    • Type: Select Object
    • Value: {"Accept": "application/json; odata=nometadata"}

Step 2.4.2: Add Variable for List GUID

  1. Click + New step
  2. Search for Initialize variable
  3. Select Initialize variable
  4. Configure:
    • Name: ListGUID
    • Type: Select String
    • Value: Leave empty

Step 2.4.3: Add Variable for Site URL

  1. Click + New step
  2. Search for Initialize variable
  3. Select Initialize variable
  4. Configure:
    • Name: listSiteURL
    • Type: Select String
    • Value: Leave empty

Step 2.4.4: Add Variable for Timestamp

  1. Click + New step
  2. Search for Initialize variable
  3. Select Initialize variable
  4. Configure:
    • Name: lastModifiedTime
    • Type: Select String
    • Value: Leave empty

Step 2.5: Handle Validation Requests

When creating a subscription, SharePoint sends a validation request first. You must detect and handle this.

Step 2.5.1: Add a Condition

  1. Click + New step
  2. Search for Condition
  3. Select Condition (under "Control")

Step 2.5.2: Configure the Condition

In the condition, you'll check if the Content-Length header is 0 (meaning it's a validation request).

  1. In the first field (left side), click in the box
  2. Click Expression tab
  3. Enter: int(triggerOutputs()?['headers']?['Content-Length'])
  4. Click OK
  5. In the middle dropdown, select is equal to
  6. In the right field, enter: 0

Step 2.6: Configure the "If Yes" Branch (Validation)

When Content-Length is 0, it's a validation request. You must return the validation token.

Step 2.6.1: Add Response in "If Yes"

  1. Click inside the If yes branch
  2. Click Add an action
  3. Search for Response
  4. Select Response
  5. Configure:
    • Status Code: 200
    • Click Show advanced options
    • Under Headers, click + Add new item
    • Key: Content-Type
    • Value: text/plain
    • Body: Click in the box, then click Expression and enter: triggerOutputs()?['queries']?['validationtoken']
    • Click OK

Step 2.6.2: Add Terminate Action

  1. Click Add an action (still in "If yes" branch)
  2. Search for Terminate
  3. Select Terminate (under "Control")
  4. Set Status to: Succeeded

Step 2.7: Configure the "If No" Branch (Change Notification)

When Content-Length is not 0, it's an actual change notification.

Step 2.7.1: Set the ListGUID Variable

  1. Click inside the If no branch
  2. Click Add an action
  3. Search for Set variable
  4. Select Set variable
  5. Configure:
    • Name: Select ListGUID
    • Value: Click Expression and enter: first(triggerBody()?['value'])?['resource']
    • Click OK

Step 2.7.2: Set the listSiteURL Variable

  1. Click Add an action
  2. Search for Set variable
  3. Select Set variable
  4. Configure:
    • Name: Select listSiteURL
    • Value: Click Expression and enter: concat('https://yourtenant.sharepoint.com',first(triggerBody()?['value'])?['siteUrl'])
    • Click OK
    • Important: Replace yourtenant with your actual tenant name

Step 2.7.3: Get the Last Processed Timestamp

  1. Click Add an action
  2. Search for Send an HTTP request to SharePoint
  3. Select Send an HTTP request to SharePoint
  4. Configure:
    • Site Address: Enter your management site URL (e.g., https://yourtenant.sharepoint.com/sites/management)
    • Method: Select GET
    • Uri: _api/web/lists/getbytitle('Timestamps')/items?$filter=listGUID eq '@{variables('ListGUID')}'
    • Headers: Click + Add new item
      • Key: Accept
      • Value: application/json; odata=nometadata

Step 2.7.4: Set the lastModifiedTime Variable

  1. Click Add an action
  2. Search for Set variable
  3. Select Set variable
  4. Configure:
    • Name: Select lastModifiedTime
    • Value: Click Expression and enter: first(body('Send_an_HTTP_request_to_SharePoint')?['value'])?['LastModificationDateTime']
    • Click OK

Step 2.7.5: Update the Timestamp

Update the timestamp before processing to prevent duplicate processing.

  1. Click Add an action
  2. Search for Send an HTTP request to SharePoint
  3. Select Send an HTTP request to SharePoint
  4. Configure:
    • Site Address: Your management site URL
    • Method: Select POST
    • Uri: Click Expression and enter: concat('_api/web/lists/getbytitle(''Timestamps'')/items(',first(body('Send_an_HTTP_request_to_SharePoint')?['value'])?['Id'],')')
    • Headers: Add these items:
      • Accept: application/json;odata=nometadata
      • Content-Type: application/json;odata=nometadata
      • IF-MATCH: *
      • X-HTTP-Method: MERGE
    • Body: {"LastModificationDateTime": "@{utcNow()}"}

Step 2.7.6: Get Modified Items

  1. Click Add an action
  2. Search for Get items
  3. Select Get items (SharePoint)
  4. Configure:
    • Site Address: Click in the box, then select Enter custom value, then select listSiteURL from Dynamic content
    • List Name: Click in the box, then select Enter custom value, then select ListGUID from Dynamic content
    • Click Show advanced options
    • Filter Query: Modified ge '@{variables('lastModifiedTime')}'

Step 2.7.7: Process Each Modified Item

  1. Click Add an action
  2. Search for Apply to each
  3. Select Apply to each (under "Control")
  4. In Select an output from previous steps, select value from the "Get items" action

Inside this loop, add your business logic (send emails, update records, etc.).


Step 2.8: Save the Flow

  1. Click Save in the top right corner
  2. Verify the flow saves without errors

Part 3: Create the Subscription Flow

This flow creates and renews webhook subscriptions for all your lists.

Step 3.1: Create a New Flow

Step 3.1.1: Create the Flow

  1. In Power Automate, click + Create
  2. Click Scheduled cloud flow
  3. Configure:
    • Flow name: Webhook Subscription Manager
    • Starting: Select today's date
    • Repeat every: 1 Month
  4. Click Create

Step 3.2: Initialize Variables

You need several variables for this flow.

Step 3.2.1: Add Variable for Headers

  1. Click + New step
  2. Search for Initialize variable
  3. Select Initialize variable
  4. Configure:
    • Name: header_nometa
    • Type: Select Object
    • Value: {"Accept": "application/json; odata=nometadata"}

Step 3.2.2: Add Variable for Flow Name

  1. Click + New step
  2. Search for Initialize variable
  3. Select Initialize variable
  4. Configure:
    • Name: flowName
    • Type: Select String
    • Value: Click Expression and enter: workflow()?['name']
    • Click OK

Step 3.2.3: Add Variable for Notification URL

  1. Click + New step
  2. Search for Initialize variable
  3. Select Initialize variable
  4. Configure:
    • Name: notificationURL
    • Type: Select String
    • Value: Paste the HTTP POST URL you copied from the Handler Flow

Step 3.2.4: Add Variable for Expiration Date

  1. Click + New step
  2. Search for Initialize variable
  3. Select Initialize variable
  4. Configure:
    • Name: expirationDateTime
    • Type: Select String
    • Value: Click Expression and enter: addDays(utcNow(),60)
    • Click OK

Step 3.2.5: Add Variable for Subscription ID

  1. Click + New step
  2. Search for Initialize variable
  3. Select Initialize variable
  4. Configure:
    • Name: SubscriptionID
    • Type: Select String
    • Value: Leave empty

Step 3.3: Get the Sites to Monitor

Step 3.3.1: Get Items from Sites List

  1. Click + New step
  2. Search for Get items
  3. Select Get items (SharePoint)
  4. Configure:
    • Site Address: Your management site URL
    • List Name: Select Sites

Step 3.4: Loop Through Each Site

Step 3.4.1: Add Apply to Each

  1. Click + New step
  2. Search for Apply to each
  3. Select Apply to each
  4. In Select an output from previous steps, select value from "Get items"

Step 3.5: Get Lists from Each Site

Inside the "Apply to each" loop:

Step 3.5.1: Query Lists Matching Your Criteria

  1. Click Add an action
  2. Search for Send an HTTP request to SharePoint
  3. Select Send an HTTP request to SharePoint
  4. Configure:
    • Site Address: Click in the box, click Dynamic content, select URL from the Sites list
    • Method: Select GET
    • Uri: _api/web/lists?$filter=BaseType eq 0 and Hidden eq false and startswith(Title, 'contracts-')
    • Headers:
      • Key: Accept
      • Value: application/json; odata=nometadata

Customize the filter: Change startswith(Title, 'contracts-') to match your list naming pattern.


Step 3.6: Extract List IDs

Step 3.6.1: Add Select Action

  1. Click Add an action
  2. Search for Select
  3. Select Select (under "Data Operations")
  4. Configure:
    • From: Click Expression and enter: body('Send_an_HTTP_request_to_SharePoint')?['value']
    • Click OK
    • Click Switch to text mode (the icon with a "T")
    • Map: Click Expression and enter: item()?['Id']
    • Click OK

Step 3.7: Build Subscription URIs

Step 3.7.1: Add Another Select Action

  1. Click Add an action
  2. Search for Select
  3. Select Select
  4. Configure:
    • From: Select Output from the previous Select action
    • Click Switch to text mode
    • Map: Enter exactly (including quotes): "_api/web/lists(guid'@{item()}')/Subscriptions"
⚠️
Note: If Power Automate removes the quotes when you save, add them back manually.

Step 3.8: Loop Through Each Subscription URI

Step 3.8.1: Add Nested Apply to Each

  1. Click Add an action
  2. Search for Apply to each
  3. Select Apply to each
  4. In Select an output from previous steps, select Output from the second Select action

Step 3.9: Check for Existing Subscriptions

Inside the nested loop:

Step 3.9.1: Get Existing Subscriptions

  1. Click Add an action
  2. Search for Send an HTTP request to SharePoint
  3. Select Send an HTTP request to SharePoint
  4. Configure:
    • Site Address: Select URL from Dynamic content (from the Sites list)
    • Method: Select GET
    • Uri: Select Current item from Dynamic content (this is the subscription URI)
    • Headers:
      • Key: Accept
      • Value: application/json; odata=nometadata

Step 3.9.2: Filter to This Flow's Subscriptions

  1. Click Add an action
  2. Search for Filter array
  3. Select Filter array (under "Data Operations")
  4. Configure:
    • From: Click Expression and enter: body('Send_an_HTTP_request_to_SharePoint_2')?['value'] (Note: The action name may have a number like _2 or _3 – check your actual action name)
    • Click OK
    • In the condition:
      • Left field: Click Expression and enter: item()?['clientState']
      • Middle: Select is equal to
      • Right field: Select flowName variable

Step 3.9.3: Set the SubscriptionID Variable

  1. Click Add an action
  2. Search for Set variable
  3. Select Set variable
  4. Configure:
    • Name: Select SubscriptionID
    • Value: Click Expression and enter: first(body('Filter_array'))?['id']

Step 3.9.4: Extract the List GUID

  1. Click Add an action
  2. Search for Compose
  3. Select Compose (under "Data Operations")
  4. Rename it to Get_resource_id (click the three dots, then "Rename")
  5. Inputs: Click Expression and enter: replace(replace(items('Apply_to_each_2'),'_api/web/lists(guid''',''),''')/Subscriptions','') (Note: Check your actual loop name – it might be Apply_to_each_2 or similar)

Step 3.10: Create or Update the Subscription

Step 3.10.1: Add a Condition

  1. Click Add an action
  2. Search for Condition
  3. Select Condition
  4. Configure:
    • Left field: Click Expression and enter: length(body('Filter_array'))
    • Middle: Select is greater than
    • Right field: Enter 0

Step 3.11: Configure "If Yes" (Update Existing Subscription)

Step 3.11.1: Update the Subscription

  1. Click inside If yes
  2. Click Add an action
  3. Search for Send an HTTP request to SharePoint
  4. Select Send an HTTP request to SharePoint
  5. Configure:
    • Site Address: Select URL from the Sites list
    • Method: Select PATCH
    • Uri: Click Expression and enter: concat(items('Apply_to_each_2'),'(''',variables('SubscriptionID'),''')')
    • Headers:
      • Accept: application/json; odata=nometadata
      • Content-Type: application/json; odata=nometadata
    • Body:
{
  "notificationUrl": "@{variables('notificationURL')}",
  "expirationDateTime": "@{variables('expirationDateTime')}",
  "clientState": "@{variables('flowName')}"
}

Step 3.12: Configure "If No" (Create New Subscription)

Step 3.12.1: Create the Subscription

  1. Click inside If no
  2. Click Add an action
  3. Search for Send an HTTP request to SharePoint
  4. Select Send an HTTP request to SharePoint
  5. Configure:
    • Site Address: Select URL from the Sites list
    • Method: Select POST
    • Uri: Select Current item from Dynamic content (the subscription URI)
    • Headers:
      • Accept: application/json; odata=nometadata
      • Content-Type: application/json; odata=nometadata
    • Body:
{
  "resource": "@{outputs('Get_resource_id')}",
  "notificationUrl": "@{variables('notificationURL')}",
  "expirationDateTime": "@{variables('expirationDateTime')}",
  "clientState": "@{variables('flowName')}"
}

Step 3.13: Save the Flow

  1. Click Save in the top right corner
  2. Verify the flow saves without errors

Part 4: Initialize the Timestamps List

Before running the Subscription Flow, you need to add entries to the Timestamps list for each list you want to monitor.

Step 4.1: Get List GUIDs

For each list you want to monitor:

  1. Navigate to the list in SharePoint
  2. Click the gear icon (Settings) in the top right
  3. Click List settings
  4. Look at the URL in your browser – find the part that says List=%7B...%7D
  5. The GUID is between %7B and %7D (these are encoded { and })

Step 4.2: Add Entries to Timestamps List

For each monitored list, add a row:

Title listGUID SiteURL LastModificationDateTime
Contracts-Sales abc12345-... https://yourtenant.sharepoint.com/sites/sales (today's date)
Contracts-HR def67890-... https://yourtenant.sharepoint.com/sites/hr (today's date)

Part 5: Test the Solution

Step 5.1: Test the Handler Flow

  1. Open the Handler Flow
  2. Click Test in the top right
  3. Select Manually
  4. Click Test
  5. The flow will wait for a trigger

Step 5.2: Run the Subscription Flow

  1. Open the Subscription Flow
  2. Click Test in the top right
  3. Select Manually
  4. Click Test
  5. Click Run flow

If successful, the Subscription Flow will create webhook subscriptions, which will trigger the Handler Flow's validation.

Step 5.3: Verify Subscriptions Were Created

  1. Check the Subscription Flow run history – all actions should show green checkmarks
  2. Check the Handler Flow run history – you should see validation runs (these are normal)

Step 5.4: Test a Real Change

  1. Go to one of your monitored SharePoint lists
  2. Create or modify an item
  3. Within a few minutes, the Handler Flow should trigger
  4. Check the Handler Flow run history to verify it processed the change

Troubleshooting

Problem Cause Solution
"Failed to validate notification URL" Handler Flow not responding Make sure Handler Flow is saved and enabled
Subscription Flow fails on "Select" action Quotes removed from mapping Re-add the quotes manually and save again
Handler Flow never triggers Subscription expired or invalid Run Subscription Flow manually to renew
No items returned in Handler Flow Wrong timestamp or filter Check that Timestamps list has correct entries
"Action name not found" errors Action names don't match expressions Update expressions to match your actual action names

References


Updated on Jan 4, 2026