AutomationFlowsWeb Scraping › Venuedesk - Cycle Sweep (daily)

Venuedesk - Cycle Sweep (daily)

VenueDesk - Cycle Sweep (Daily). Uses httpRequest. Scheduled trigger; 10 nodes.

Cron / scheduled trigger★★★★☆ complexity10 nodesHTTP Request
Web Scraping Trigger: Cron / scheduled Nodes: 10 Complexity: ★★★★☆ Added:

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "name": "VenueDesk - Cycle Sweep (Daily)",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 6 * * *"
            }
          ]
        }
      },
      "id": "csc-schedule-001",
      "name": "Schedule: Daily 06:00 UTC",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.1,
      "position": [
        -880,
        0
      ],
      "notes": "Feature C cron sweep. Charges due cycles off-session against saved cards. Runs once a day before business hours so customers wake up to receipts, not failures."
    },
    {
      "parameters": {
        "method": "GET",
        "url": "https://api.venuedesk.co.uk/recurring/cycles/due",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "={{ 'Bearer ' + $env.CYCLE_SWEEP_SERVICE_JWT }}"
            }
          ]
        },
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "days_ahead",
              "value": "0"
            },
            {
              "name": "limit",
              "value": "200"
            }
          ]
        },
        "options": {
          "response": {
            "response": {
              "fullResponse": false,
              "neverError": true
            }
          },
          "timeout": 15000
        }
      },
      "id": "csc-get-due-001",
      "name": "HTTP: GET /recurring/cycles/due",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "continueOnFail": true,
      "position": [
        -680,
        0
      ]
    },
    {
      "parameters": {
        "jsCode": "// Extract the data[] array from the API envelope so Split-Out can iterate.\n// API shape: { success, data: [...], count }\n// Each cycle item becomes a separate workflow item downstream.\nconst body = $input.first().json;\nconst cycles = Array.isArray(body?.data) ? body.data : [];\n\nif (cycles.length === 0) {\n  // Emit a single marker item so the workflow doesn't dead-end with zero items\n  // (audit log node still needs to fire with the 'nothing to do' result).\n  return [{ json: { _no_cycles: true, count: 0 } }];\n}\n\nreturn cycles.map(c => ({ json: c }));"
      },
      "id": "csc-extract-cycles-001",
      "name": "Code: Extract Cycles",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -480,
        0
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "loose"
          },
          "conditions": [
            {
              "id": "no-cycles-guard",
              "leftValue": "={{ $json._no_cycles }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "csc-if-empty-001",
      "name": "IF: No Cycles Today?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        -280,
        0
      ]
    },
    {
      "parameters": {
        "batchSize": 1,
        "options": {}
      },
      "id": "csc-split-batches-001",
      "name": "Split In Batches",
      "type": "n8n-nodes-base.splitInBatches",
      "typeVersion": 3,
      "position": [
        -80,
        100
      ],
      "notes": "One cycle per iteration. Serial processing keeps Stripe rate limits comfortable and makes per-cycle errors easier to trace in execution history."
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.venuedesk.co.uk/stripe/cycle-session",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "={{ 'Bearer ' + $env.CYCLE_SWEEP_SERVICE_JWT }}"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "contentType": "json",
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ cycle_id: $json.cycle_id }) }}",
        "options": {
          "response": {
            "response": {
              "fullResponse": false,
              "neverError": true
            }
          },
          "timeout": 30000
        }
      },
      "id": "csc-post-cycle-session-001",
      "name": "HTTP: POST /stripe/cycle-session",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "continueOnFail": true,
      "position": [
        120,
        100
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "loose"
          },
          "conditions": [
            {
              "id": "success-check",
              "leftValue": "={{ $json.success }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "csc-if-success-001",
      "name": "IF: Charge Succeeded?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        320,
        100
      ],
      "notes": "TRUE \u2192 log success and loop. FALSE \u2192 trigger #122 email workflow (TODO) and log failure. For v1 both paths just log + loop; email branch deferred."
    },
    {
      "parameters": {
        "jsCode": "// Build summary line for audit. Combines cycle context (from Split input)\n// with the API response (from current item). The cycle context isn't on\n// $json after the HTTP node \u2014 pull it from the splitInBatches input.\nconst batch    = $('Split In Batches').item.json;\nconst response = $json;\n\nreturn [{\n  json: {\n    cycle_id:       batch.cycle_id,\n    series_name:    batch.series_name,\n    customer_name:  batch.customer_name,\n    amount_due:     batch.amount_due,\n    outcome:        response.success ? 'CHARGED' : (response.code || 'FAILED'),\n    pi_id:          response.data?.payment_intent_id || null,\n    pi_status:      response.data?.status || null,\n    requires_action: response.data?.requires_action || false,\n    error_message:  response.message || null,\n  }\n}];"
      },
      "id": "csc-format-result-001",
      "name": "Code: Format Result",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        520,
        100
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.venuedesk.co.uk/audit/log",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "={{ 'Bearer ' + $env.CYCLE_SWEEP_SERVICE_JWT }}"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "contentType": "json",
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ action: 'cycle_sweep_result', entity: 'recurring_payment_cycle', entity_id: $json.cycle_id, payload: $json, source: 'cron_sweep' }) }}",
        "options": {
          "response": {
            "response": {
              "fullResponse": false,
              "neverError": true
            }
          },
          "timeout": 10000
        }
      },
      "id": "csc-audit-log-001",
      "name": "HTTP: POST /audit/log",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "continueOnFail": true,
      "position": [
        720,
        100
      ],
      "notes": "Logs to bookings.audit_log via the existing audit-write endpoint. If /audit/log isn't implemented yet, neverError=true means this no-ops cleanly without breaking the sweep."
    },
    {
      "parameters": {
        "jsCode": "// Defensive read \u2014 $items() throws ExpressionError if the referenced node\n// hasn't executed (n8n 1.85.4 behaviour; documented in CLAUDE.md anti-patterns).\n// Wrap in try/catch so the empty-cycles branch (where Format Result never\n// runs) doesn't blow up on the final summary.\nlet items = [];\ntry { items = $items('Code: Format Result'); } catch(e) { items = []; }\n\nconst charged   = items.filter(i => i.json.outcome === 'CHARGED').length;\nconst failed    = items.filter(i => i.json.outcome !== 'CHARGED').length;\nconst needs3ds  = items.filter(i => i.json.requires_action === true).length;\n\nconsole.log('[cycle-sweep] DONE \u2014 charged=' + charged + ' failed=' + failed + ' requires_action=' + needs3ds + ' total=' + items.length);\n\nreturn [{ json: { charged, failed, requires_action: needs3ds, total: items.length, ran_at: new Date().toISOString() } }];"
      },
      "id": "csc-summary-001",
      "name": "Code: Final Summary",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -80,
        -120
      ]
    }
  ],
  "connections": {
    "Schedule: Daily 06:00 UTC": {
      "main": [
        [
          {
            "node": "HTTP: GET /recurring/cycles/due",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP: GET /recurring/cycles/due": {
      "main": [
        [
          {
            "node": "Code: Extract Cycles",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code: Extract Cycles": {
      "main": [
        [
          {
            "node": "IF: No Cycles Today?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF: No Cycles Today?": {
      "main": [
        [
          {
            "node": "Code: Final Summary",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Split In Batches",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split In Batches": {
      "main": [
        [
          {
            "node": "Code: Final Summary",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "HTTP: POST /stripe/cycle-session",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP: POST /stripe/cycle-session": {
      "main": [
        [
          {
            "node": "IF: Charge Succeeded?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF: Charge Succeeded?": {
      "main": [
        [
          {
            "node": "Code: Format Result",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Code: Format Result",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code: Format Result": {
      "main": [
        [
          {
            "node": "HTTP: POST /audit/log",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP: POST /audit/log": {
      "main": [
        [
          {
            "node": "Split In Batches",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "staticData": null,
  "tags": [],
  "triggerCount": 0,
  "versionId": "cycle-sweep-v2-2026-05-24"
}
Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

VenueDesk - Cycle Sweep (Daily). Uses httpRequest. Scheduled trigger; 10 nodes.

Source: https://github.com/AndyJay72/VenueDesk/blob/main/n8n-workflows/CycleSweepCron.json — original creator credit. Request a take-down →

More Web Scraping workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Web Scraping

Birthday Automation - Production (Fixed). Uses stopAndError, httpRequest, emailSend, bannerbear. Scheduled trigger; 86 nodes.

Stop And Error, HTTP Request, Email Send +1
Web Scraping

This template runs two scheduled workflows to govern Microsoft Entra ID (Azure AD) guest accounts by detecting stale users via Microsoft Graph, staging deletions in SharePoint with a 72-hour window, n

Microsoft SharePoint, Microsoft Teams, Microsoft Entra +1
Web Scraping

Jira-Allure-Auto-Qa. Uses httpRequest, jira. Scheduled trigger; 68 nodes.

HTTP Request, Jira
Web Scraping

Spotify-Sync-Surrealdb-V1. Uses httpRequest, n8n-nodes-surrealdb, spotify. Scheduled trigger; 62 nodes.

HTTP Request, N8N Nodes Surrealdb, Spotify
Web Scraping

As n8n instances scale, teams often lose track of sub-workflows—who uses them, where they are referenced, and whether they can be safely updated. This leads to inefficiencies like unnecessary copies o

HTTP Request, n8n, N8N Trigger +1