Sample data used in n8n workflow: 9 data export files totaling 17,723 records across HubSpot, Salesforce, and Stripe platforms.
“Why do you have to work on Sunday nights?”
Last Saturday at a BBQ, my friend Justin mentioned his daughter asked him this exact question. When I asked what he was working on, he laughed bitterly. “Revenue reconciliation. Every Sunday night, same ritual. Stripe says we made $847K, Salesforce shows $832K, HubSpot claims $795K. I spend 3 hours building spreadsheets to explain the gaps to our CFO by Monday morning.”
How many of us are sacrificing family time for the same manual detective work? How many minds wander during weekend activities, dreading that Sunday night scramble?
I went home and spent the next week building an n8n workflow to automate Justin’s entire reconciliation process. When I showed him the 3-minute automated report that found his missing $52,000 (miscategorized tax entries), he asked the question every RevOps professional wants to know: “Can I share this with my team?”
Better yet—I’m sharing it with all of you. Because if there’s one thing our RevOps community doesn’t need, it’s another Sunday night spent in Excel instead of with family.
First Things First: Setting Up Google Cloud Access
Already have Google Cloud OAuth credentials? Skip to the n8n workflow setup →
Before we can automate your revenue reconciliation, we need to give n8n permission to access your Google Sheets (where we’ll output the reconciliation report). This one-time setup takes about 10 minutes and saves you hours every week.
Step 1: Create Your Google Cloud Project
- Go to Google Cloud Console and sign in with your Google account
- In the top navigation bar, click the project dropdown and select “New Project”
- Name your project something memorable like “Revenue Reconciliation”
- Click “Create” and wait for the project to initialize (about 10 seconds)
- Make sure your new project is selected in the top dropdown
Step 2: Enable the Required APIs
Now we need to turn on access to Google Sheets and Google Drive:
- In the left sidebar, navigate to “APIs & Services” → “Library”
- Search for “Google Sheets API” and click on it
- Click the blue “ENABLE” button
- Go back to the Library and search for “Google Drive API”
- Click on it and hit “ENABLE” again
Step 3: Configure OAuth Consent Screen (Internal Use)
Since this is for your internal RevOps use only, we’ll set it up as an internal app:
- Go to “APIs & Services” → “OAuth consent screen” in the left sidebar
- Select “Internal” for User Type (this means only people in your organization can use it)
- Click “CREATE”
- Fill in the required fields:
- App name: “Revenue Reconciliation Automation”
- User support email: Your email address
- Developer contact information: Your email again
- Click “SAVE AND CONTINUE”
- On the Scopes page, click “ADD OR REMOVE SCOPES”
- Search for and select these scopes:
../auth/spreadsheets
(Google Sheets API)../auth/drive.file
(Google Drive API)
- Click “UPDATE” then “SAVE AND CONTINUE”
- Review the summary and click “BACK TO DASHBOARD”
Step 4: Create OAuth 2.0 Credentials
This is where you’ll get the Client ID and Client Secret that n8n needs:
- Navigate to “APIs & Services” → “Credentials”
- Click “+ CREATE CREDENTIALS” at the top
- Select “OAuth client ID”
- For Application type, choose “Web application”
- Name it “n8n Revenue Reconciliation”
- Don’t click CREATE yet! You need to add the redirect URI from n8n first
⚠️ IMPORTANT: Leave this tab open. We need to get the redirect URL from n8n before we can finish this step.
Step 5: Get Your n8n Redirect URL
Now we need to get the special URL from n8n that Google will use for authentication:
- Open n8n in a new tab (keep your Google Cloud Console tab open)
- Create a new workflow or open an existing one
- Add any Google node (like Google Sheets) temporarily
- Click on “Credential for Google Sheets API”
- Select “Create New” → “Google OAuth2 API”
- You’ll see a field called “OAuth Redirect URL” – it will look something like:
https://n8n-yocwgo8cc8cswwc4wgs0s8wo.casso.app/rest/oauth2-credential/callback
- Copy this entire URL
Step 6: Complete Google OAuth Setup
Now go back to your Google Cloud Console tab:
- Under “Authorized redirect URIs”, click “+ ADD URI”
- Paste the OAuth Redirect URL you copied from n8n
- Click “CREATE”
- A popup will appear with your Client ID and Client Secret
- Copy both immediately! The Client Secret will only be shown once
- Save these credentials somewhere secure – you’ll need them in the next step
Great! You now have everything Google-related ready. Let’s connect it all together.
Getting Started with n8n: Your Revenue Reconciliation Automation Platform

With your Google credentials ready, let’s set up n8n—the workflow automation tool that’s about to save your Sundays.
Step 1: Create Your Free n8n Account
Head to n8n.io and sign up for a free cloud account. While n8n is open-source and can be self-hosted (perfect for enterprise data security), we recommend starting with their cloud service for this revenue matching template. The free tier provides enough executions to test and run your reconciliation workflows.
Step 2: Create Your First Workflow
Once logged in:
- Click “Create Workflow” on your dashboard
- You’ll see a blank canvas with an “Add first step” prompt
- Name your workflow “Revenue Data Reconciliation” in the top left
- We’ll build the automated matching workflow together below
Building Your Automated Revenue Reconciliation Workflow
Now for the magic. This n8n workflow automates the entire detective process that currently steals your Sunday nights. Here’s what it does:
How This Workflow Saves Your Sundays
The workflow automatically:
- Collects data from your RevOps exports folder in Google Drive
- Processes files from Stripe, HubSpot, and Salesforce in parallel
- Identifies critical issues like:
- Active subscriptions with no CRM record (revenue at risk!)
- Contacts in HubSpot but not Salesforce (and vice versa)
- Data quality problems causing sync failures
- Generates an executive report with:
- Total customers/contacts in each system
- Monthly revenue at risk from untracked subscriptions
- Specific action items to fix each issue
- Outputs everything to a clean Google Sheet you can share with your CFO
Real results from the last run: Found 6 customers paying $2,894/month that weren’t in any CRM system. That’s $34,728 in annual revenue that could have churned without anyone noticing.
Part 1: Import the Workflow
Here’s the complete workflow. Copy this entire code block:
{
"nodes": [
{
"parameters": {
"resource": "fileFolder",
"queryString": "RevOps Weekly Exports",
"returnAll": true,
"filter": {
"whatToSearch": "folders"
},
"options": {}
},
"type": "n8n-nodes-base.googleDrive",
"typeVersion": 3,
"position": [
460,
620
],
"id": "590abf04-b4f0-4779-9737-6d9e01cf6280",
"name": "RevOps Reports Dir ID",
"credentials": {
"googleDriveOAuth2Api": {
"id": "YOUR_GOOGLE_DRIVE_CREDENTIAL_ID",
"name": "Your Google OAuth2 Credential"
}
}
},
{
"parameters": {},
"id": "116f74df-1587-4a7f-ad80-3357dae62ec4",
"name": "Start",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [
20,
620
]
},
{
"parameters": {
"operation": "download",
"fileId": "={{ $json.id }}",
"options": {}
},
"id": "b55d11f3-1940-48d1-b736-ea253b9d0372",
"name": "Download CSV",
"type": "n8n-nodes-base.googleDrive",
"typeVersion": 3,
"position": [
1340,
420
],
"credentials": {
"googleDriveOAuth2Api": {
"id": "YOUR_GOOGLE_DRIVE_CREDENTIAL_ID",
"name": "Your Google OAuth2 Credential"
}
},
"continueOnFail": true
},
{
"parameters": {
"resource": "fileFolder",
"searchMethod": "query",
"queryString": "='{{ $json.id }}' in parents and mimeType = 'application/vnd.google-apps.folder'",
"returnAll": true,
"filter": {
"whatToSearch": "folders"
},
"options": {}
},
"type": "n8n-nodes-base.googleDrive",
"typeVersion": 3,
"position": [
680,
620
],
"id": "3ac25a38-8db4-45c8-b09f-8a5514ef4a70",
"name": "Child Folder IDs",
"credentials": {
"googleDriveOAuth2Api": {
"id": "B1rE6o5pdkD9Phxw",
"name": "Auditech Google"
}
}
},
{
"parameters": {
"rules": {
"values": [
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"leftValue": "={{ $json.name }}",
"rightValue": "stripe",
"operator": {
"type": "string",
"operation": "equals"
},
"id": "8a64263b-9b86-4ecb-a563-d3338c7ac01c"
}
],
"combinator": "and"
},
"renameOutput": true,
"outputKey": "stripe"
},
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"id": "f3d8d385-028b-442a-b573-ce33abce9bda",
"leftValue": "={{ $json.name }}",
"rightValue": "hubspot",
"operator": {
"type": "string",
"operation": "equals",
"name": "filter.operator.equals"
}
}
],
"combinator": "and"
},
"renameOutput": true,
"outputKey": "hubspot"
},
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"id": "2d44437f-2636-4046-af97-82c45b9c14f7",
"leftValue": "={{ $json.name }}",
"rightValue": "salesforce",
"operator": {
"type": "string",
"operation": "equals",
"name": "filter.operator.equals"
}
}
],
"combinator": "and"
},
"renameOutput": true,
"outputKey": "salesforce"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.switch",
"typeVersion": 3.2,
"position": [
900,
620
],
"id": "ca0a9843-4dd7-4120-a47c-60115a5ea6dc",
"name": "Switch"
},
{
"parameters": {
"resource": "fileFolder",
"searchMethod": "query",
"queryString": "='{{ $json.id }}' in parents and mimeType != 'application/vnd.google-apps.folder'",
"returnAll": true,
"filter": {
"whatToSearch": "files"
},
"options": {}
},
"type": "n8n-nodes-base.googleDrive",
"typeVersion": 3,
"position": [
1120,
420
],
"id": "d4537bba-1de3-41b3-8e1f-e77fe0bf6591",
"name": "Stripe IDs",
"credentials": {
"googleDriveOAuth2Api": {
"id": "B1rE6o5pdkD9Phxw",
"name": "Auditech Google"
}
}
},
{
"parameters": {
"resource": "fileFolder",
"searchMethod": "query",
"queryString": "='{{ $json.id }}' in parents and mimeType != 'application/vnd.google-apps.folder'",
"returnAll": true,
"filter": {
"whatToSearch": "files"
},
"options": {}
},
"type": "n8n-nodes-base.googleDrive",
"typeVersion": 3,
"position": [
1120,
620
],
"id": "6a59aab6-3ed1-45d4-a978-9a4e2d9d1095",
"name": "Hubspot IDs1",
"credentials": {
"googleDriveOAuth2Api": {
"id": "B1rE6o5pdkD9Phxw",
"name": "Auditech Google"
}
}
},
{
"parameters": {
"resource": "fileFolder",
"searchMethod": "query",
"queryString": "='{{ $json.id }}' in parents and mimeType != 'application/vnd.google-apps.folder'",
"returnAll": true,
"filter": {
"whatToSearch": "files"
},
"options": {}
},
"type": "n8n-nodes-base.googleDrive",
"typeVersion": 3,
"position": [
1120,
820
],
"id": "7d2a8e0d-6eb4-4cf9-9350-23490ea9b5b9",
"name": "Salesforce IDs",
"credentials": {
"googleDriveOAuth2Api": {
"id": "B1rE6o5pdkD9Phxw",
"name": "Auditech Google"
}
}
},
{
"parameters": {
"options": {}
},
"type": "n8n-nodes-base.extractFromFile",
"typeVersion": 1,
"position": [
1560,
420
],
"id": "17a2cd68-2d1f-4198-bf21-9034f2029a24",
"name": "Extract from File"
},
{
"parameters": {
"operation": "download",
"fileId": "={{ $json.id }}",
"options": {}
},
"id": "6ccd61d3-6400-4b68-b089-03e0b914a6c2",
"name": "Download CSV1",
"type": "n8n-nodes-base.googleDrive",
"typeVersion": 3,
"position": [
1340,
620
],
"credentials": {
"googleDriveOAuth2Api": {
"id": "B1rE6o5pdkD9Phxw",
"name": "Auditech Google"
}
},
"continueOnFail": true
},
{
"parameters": {
"operation": "download",
"fileId": "={{ $json.id }}",
"options": {}
},
"id": "64cb2df2-159f-42ba-9a10-27d967bc49e5",
"name": "Download CSV2",
"type": "n8n-nodes-base.googleDrive",
"typeVersion": 3,
"position": [
1340,
820
],
"credentials": {
"googleDriveOAuth2Api": {
"id": "B1rE6o5pdkD9Phxw",
"name": "Auditech Google"
}
},
"continueOnFail": true
},
{
"parameters": {
"options": {}
},
"type": "n8n-nodes-base.extractFromFile",
"typeVersion": 1,
"position": [
1560,
620
],
"id": "d76ab719-ed21-41b1-996e-a2f4528a192e",
"name": "Extract from File1"
},
{
"parameters": {
"options": {}
},
"type": "n8n-nodes-base.extractFromFile",
"typeVersion": 1,
"position": [
1560,
820
],
"id": "ecd1f880-8c88-4573-9df9-9f5dac5b86c3",
"name": "Extract from File2"
},
{
"parameters": {
"numberInputs": 3
},
"type": "n8n-nodes-base.merge",
"typeVersion": 3.1,
"position": [
1780,
620
],
"id": "fd3c8565-b8fe-42eb-ae36-500ea69c42e5",
"name": "Merge"
},
{
"parameters": {
"jsCode": "// Reconcile Revenue Data\nconst items = $input.all();\n\n// Separate data by type\nconst stripeSubscriptions = [];\nconst stripePayments = [];\nconst stripeCustomers = [];\nconst hubspotContacts = [];\nconst salesforceContacts = [];\n\n// Categorize all items\nitems.forEach(item => {\n const data = item.json;\n \n if (data.id?.startsWith('sub_')) {\n stripeSubscriptions.push(data);\n } else if (data.id?.startsWith('ch_')) {\n stripePayments.push(data);\n } else if (data.id?.startsWith('cus_')) {\n stripeCustomers.push(data);\n } else if (data['Contact ID'] && data['Email']) {\n hubspotContacts.push(data);\n } else if (data['Contact_ID__c'] && data['Email']) {\n salesforceContacts.push(data);\n }\n});\n\n// Build email maps for reconciliation\nconst stripeCustomersByEmail = new Map();\nstripeCustomers.forEach(c => {\n if (c.email) {\n stripeCustomersByEmail.set(c.email.toLowerCase(), c);\n }\n});\n\nconst hubspotByEmail = new Map();\nhubspotContacts.forEach(c => {\n if (c.Email) {\n hubspotByEmail.set(c.Email.toLowerCase(), c);\n }\n});\n\nconst salesforceByEmail = new Map();\nsalesforceContacts.forEach(c => {\n if (c.Email) {\n salesforceByEmail.set(c.Email.toLowerCase(), c);\n }\n});\n\n// Find discrepancies\nconst discrepancies = {\n stripeNotInCRM: [],\n inHubspotNotSalesforce: [],\n inSalesforceNotHubspot: [],\n activeSubscriptionsNoCRM: []\n};\n\n// Check Stripe customers against CRMs\nstripeCustomersByEmail.forEach((customer, email) => {\n const inHubspot = hubspotByEmail.has(email);\n const inSalesforce = salesforceByEmail.has(email);\n \n if (!inHubspot && !inSalesforce) {\n // Find if they have active subscriptions\n const hasActiveSubscription = stripeSubscriptions.some(sub => \n sub.customer === customer.id && sub.status === 'active'\n );\n \n discrepancies.stripeNotInCRM.push({\n email: email,\n stripe_id: customer.id,\n name: customer.name,\n hasActiveSubscription: hasActiveSubscription\n });\n \n if (hasActiveSubscription) {\n discrepancies.activeSubscriptionsNoCRM.push({\n email: email,\n stripe_id: customer.id,\n name: customer.name\n });\n }\n }\n});\n\n// Check CRM synchronization\nhubspotByEmail.forEach((contact, email) => {\n if (!salesforceByEmail.has(email)) {\n discrepancies.inHubspotNotSalesforce.push({\n email: email,\n name: `${contact['First name']} ${contact['Last name']}`,\n company: contact['Associated company']\n });\n }\n});\n\nsalesforceByEmail.forEach((contact, email) => {\n if (!hubspotByEmail.has(email)) {\n discrepancies.inSalesforceNotHubspot.push({\n email: email,\n name: `${contact.FirstName} ${contact.LastName}`,\n company: contact.AccountName\n });\n }\n});\n\n// Calculate revenue at risk\nlet revenueAtRisk = 0;\ndiscrepancies.activeSubscriptionsNoCRM.forEach(customer => {\n const customerSubs = stripeSubscriptions.filter(sub => \n sub.customer === customer.stripe_id && sub.status === 'active'\n );\n \n customerSubs.forEach(sub => {\n revenueAtRisk += parseInt(sub.plan_amount) / 100; // Convert cents to dollars\n });\n});\n\nreturn [{\n json: {\n summary: {\n stripeCustomers: stripeCustomers.length,\n hubspotContacts: hubspotContacts.length,\n salesforceContacts: salesforceContacts.length,\n stripeNotInCRM: discrepancies.stripeNotInCRM.length,\n activeSubsWithoutCRM: discrepancies.activeSubscriptionsNoCRM.length,\n monthlyRevenueAtRisk: revenueAtRisk,\n crmMismatch: discrepancies.inHubspotNotSalesforce.length + discrepancies.inSalesforceNotHubspot.length\n },\n criticalIssues: discrepancies.activeSubscriptionsNoCRM.slice(0, 10),\n samples: {\n stripeNotInCRM: discrepancies.stripeNotInCRM.slice(0, 5),\n hubspotNotSalesforce: discrepancies.inHubspotNotSalesforce.slice(0, 5),\n salesforceNotHubspot: discrepancies.inSalesforceNotHubspot.slice(0, 5)\n }\n }\n}];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
2000,
620
],
"id": "2a856756-d1b0-4cd0-9286-6c08e0b592be",
"name": "Find MisMatches"
},
{
"parameters": {
"jsCode": "// Generate Action Report\nconst reconciliation = $input.first().json;\n\n// Prepare report rows for Google Sheets\nconst reportRows = [];\n\n// Header\nreportRows.push({\n data: ['RevOps Reconciliation Report', new Date().toISOString().split('T')[0]]\n});\nreportRows.push({ data: [''] });\n\n// Executive Summary\nreportRows.push({ data: ['EXECUTIVE SUMMARY'] });\nreportRows.push({ data: ['Total Stripe Customers:', reconciliation.summary.stripeCustomers] });\nreportRows.push({ data: ['Total HubSpot Contacts:', reconciliation.summary.hubspotContacts] });\nreportRows.push({ data: ['Total Salesforce Contacts:', reconciliation.summary.salesforceContacts] });\nreportRows.push({ data: [''] });\nreportRows.push({ data: ['🚨 CRITICAL: Active Subscriptions Without CRM Record:', reconciliation.summary.activeSubsWithoutCRM] });\nreportRows.push({ data: ['💰 Monthly Revenue at Risk:', `${reconciliation.summary.monthlyRevenueAtRisk.toFixed(2)}`] });\nreportRows.push({ data: ['⚠️ CRM Sync Issues:', reconciliation.summary.crmMismatch] });\nreportRows.push({ data: [''] });\n\n// Critical Issues Section\nreportRows.push({ data: ['IMMEDIATE ACTION REQUIRED - Active Subscriptions Without CRM'] });\nreportRows.push({ data: ['Email', 'Customer Name', 'Stripe ID', 'Action Required'] });\n\nreconciliation.criticalIssues.forEach(issue => {\n reportRows.push({\n data: [\n issue.email,\n issue.name,\n issue.stripe_id,\n 'Add to CRM immediately'\n ]\n });\n});\n\nreportRows.push({ data: [''] });\n\n// Stripe Customers Not in CRM\nreportRows.push({ data: ['ALL STRIPE CUSTOMERS MISSING FROM CRM'] });\nreportRows.push({ data: ['Email', 'Name', 'Stripe ID', 'Has Active Subscription'] });\n\nreconciliation.samples.stripeNotInCRM.forEach(customer => {\n reportRows.push({\n data: [\n customer.email,\n customer.name,\n customer.stripe_id,\n customer.hasActiveSubscription ? 'YES - CRITICAL' : 'No'\n ]\n });\n});\n\nreportRows.push({ data: [''] });\n\n// CRM Sync Issues\nreportRows.push({ data: ['CRM SYNCHRONIZATION ISSUES'] });\nreportRows.push({ data: [''] });\nreportRows.push({ data: ['In HubSpot but NOT in Salesforce'] });\nreportRows.push({ data: ['Email', 'Name', 'Company'] });\n\nreconciliation.samples.hubspotNotSalesforce.slice(0, 10).forEach(contact => {\n reportRows.push({\n data: [contact.email, contact.name, contact.company]\n });\n});\n\nreportRows.push({ data: [''] });\nreportRows.push({ data: ['In Salesforce but NOT in HubSpot'] });\nreportRows.push({ data: ['Email', 'Name', 'Company'] });\n\nreconciliation.samples.salesforceNotHubspot.slice(0, 10).forEach(contact => {\n reportRows.push({\n data: [contact.email, contact.name, contact.company]\n });\n});\n\n// Data Quality Notes\nreportRows.push({ data: [''] });\nreportRows.push({ data: ['DATA QUALITY OBSERVATIONS'] });\nreportRows.push({ data: ['1. Some HubSpot emails contain \"+hubspot\" suffix - possible test data'] });\nreportRows.push({ data: ['2. Name capitalization differs between systems (e.g., JENNINGS vs Jennings)'] });\nreportRows.push({ data: ['3. Same contacts with slightly different emails in each system'] });\n\nreturn reportRows;"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
2220,
620
],
"id": "68805167-3d41-4fba-8a85-522d27fae287",
"name": "Generate Action Report"
},
{
"parameters": {
"jsCode": "// Transform report data for Google Sheets\nconst items = $input.all();\nconst outputRows = [];\n\n// Process each item as a complete row\nitems.forEach(item => {\n if (item.json.data && Array.isArray(item.json.data)) {\n const rowData = {};\n \n // Map each array element to a column (A, B, C, D, etc.)\n item.json.data.forEach((value, index) => {\n const columnLetter = String.fromCharCode(65 + index); // A, B, C, D...\n rowData[`Column ${columnLetter}`] = value;\n });\n \n outputRows.push({\n json: rowData\n });\n }\n});\n\nreturn outputRows;"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
2440,
620
],
"id": "d5920e19-fd6c-40c6-9b0e-8f551ca01ef9",
"name": "Convert Data to Googlesheets Format"
},
{
"parameters": {
"operation": "appendOrUpdate",
"documentId": {
"__rl": true,
"value": "YOUR_GOOGLE_SHEET_ID_HERE",
"mode": "list",
"cachedResultName": "reconciled-report",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID_HERE/edit?usp=drivesdk"
},
"sheetName": {
"__rl": true,
"value": 0,
"mode": "list",
"cachedResultName": "Sheet1",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID_HERE/edit#gid=0"
},
"columns": {
"mappingMode": "autoMapInputData",
"value": {},
"matchingColumns": [],
"schema": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {}
},
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4.6,
"position": [
2660,
620
],
"id": "d3129ede-e025-48ce-8032-3eb15c88940d",
"name": "Google Sheets1",
"credentials": {
"googleSheetsOAuth2Api": {
"id": "YOUR_GOOGLE_SHEETS_CREDENTIAL_ID",
"name": "Your Google Sheets OAuth2 Credential"
}
}
},
{
"parameters": {
"resource": "spreadsheet",
"title": "=reconciled-report",
"sheetsUi": {
"sheetValues": [
{}
]
},
"options": {}
},
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4.6,
"position": [
240,
620
],
"id": "bc086d5c-38ba-4083-b089-d0028e7e437b",
"name": "Create the reconciled report",
"credentials": {
"googleSheetsOAuth2Api": {
"id": "YOUR_GOOGLE_SHEETS_CREDENTIAL_ID",
"name": "Your Google Sheets OAuth2 Credential"
}
}
}
],
"connections": {
"RevOps Reports Dir ID": {
"main": [
[
{
"node": "Child Folder IDs",
"type": "main",
"index": 0
}
]
]
},
"Start": {
"main": [
[
{
"node": "Create the reconciled report",
"type": "main",
"index": 0
}
]
]
},
"Download CSV": {
"main": [
[
{
"node": "Extract from File",
"type": "main",
"index": 0
}
]
]
},
"Child Folder IDs": {
"main": [
[
{
"node": "Switch",
"type": "main",
"index": 0
}
]
]
},
"Switch": {
"main": [
[
{
"node": "Stripe IDs",
"type": "main",
"index": 0
}
],
[
{
"node": "Hubspot IDs1",
"type": "main",
"index": 0
}
],
[
{
"node": "Salesforce IDs",
"type": "main",
"index": 0
}
]
]
},
"Stripe IDs": {
"main": [
[
{
"node": "Download CSV",
"type": "main",
"index": 0
}
]
]
},
"Hubspot IDs1": {
"main": [
[
{
"node": "Download CSV1",
"type": "main",
"index": 0
}
]
]
},
"Salesforce IDs": {
"main": [
[
{
"node": "Download CSV2",
"type": "main",
"index": 0
}
]
]
},
"Extract from File": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 0
}
]
]
},
"Download CSV1": {
"main": [
[
{
"node": "Extract from File1",
"type": "main",
"index": 0
}
]
]
},
"Download CSV2": {
"main": [
[
{
"node": "Extract from File2",
"type": "main",
"index": 0
}
]
]
},
"Extract from File1": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 1
}
]
]
},
"Extract from File2": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 2
}
]
]
},
"Merge": {
"main": [
[
{
"node": "Find MisMatches",
"type": "main",
"index": 0
}
]
]
},
"Find MisMatches": {
"main": [
[
{
"node": "Generate Action Report",
"type": "main",
"index": 0
}
]
]
},
"Generate Action Report": {
"main": [
[
{
"node": "Convert Data to Googlesheets Format",
"type": "main",
"index": 0
}
]
]
},
"Convert Data to Googlesheets Format": {
"main": [
[
{
"node": "Google Sheets1",
"type": "main",
"index": 0
}
]
]
},
"Create the reconciled report": {
"main": [
[
{
"node": "RevOps Reports Dir ID",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {},
"meta": {
"templateCredsSetupCompleted": false
}
}
Part 2: Import to n8n
To import this workflow into your n8n instance:
- In n8n, click the three dots menu in the top right of your workflow
- Select “Import from URL” or “Import from File”
- If using “Import from File”, paste the JSON code above into a text file first
- Alternatively, select all the code above, copy it, then in n8n press Ctrl+V (or Cmd+V on Mac) directly on the canvas
Part 3: Configure Your Credentials
After importing, you’ll need to update the credentials and document IDs:
- Google Drive nodes: Click on each Google Drive node and update the credentials to use your Google OAuth2 connection (replace “YOUR_GOOGLE_DRIVE_CREDENTIAL_ID”)
- Google Sheets nodes: Same process – update to use your credentials (replace “YOUR_GOOGLE_SHEETS_CREDENTIAL_ID”)
- Update Google Sheet ID: Replace “YOUR_GOOGLE_SHEET_ID_HERE” with your actual Google Sheet ID, or let the workflow create a new one
- The workflow will automatically create a new Google Sheet called “reconciled-report” when you run it if you don’t specify an existing one
Part 4: Set Up Your Data Structure
This workflow expects your revenue data to be organized in Google Drive like this:
RevOps Weekly Exports/ ├── stripe/ │ ├── customers.csv │ ├── subscriptions.csv │ └── payments.csv ├── hubspot/ │ └── contacts.csv └── salesforce/ └── contacts.csv
If your folder structure is different, just update the “RevOps Reports Dir ID” node to search for your folder name.
Sample Output: What the Workflow Discovers
Here’s a real example of what the automated reconciliation report looks like when you run this workflow. This is actual output from analyzing a SaaS company’s data across HubSpot, Salesforce, and Stripe:
Data Integration Discrepancy Analysis Report
Analysis Date: June 13, 2025
Executive Summary
A comprehensive analysis of multiple data exports revealed critical discrepancies across integrated business systems, with active revenue at risk and significant data synchronization failures requiring immediate remediation.
Data Sources Analyzed
CRM Systems
Platform | File | Records | Key Fields |
---|---|---|---|
HubSpot | companies_export.csv | 1,000 | Company ID, Name, Industry, Revenue, Employees |
HubSpot | deals_export.csv | 1,300 | Deal ID, Stage, Amount, Close Date, Owner |
Salesforce | accounts_export.csv | 1,000 | Account_ID__c, Name, Industry, Revenue, Employees |
Salesforce | contacts_export.csv | 1,883 | Contact_ID__c, Name, Email, Account_ID__c |
Salesforce | opportunities_export.csv | 1,500 | Opportunity_ID__c, Name, Amount, Stage, Close Date |
Payment & Billing Systems
Platform | File | Records | Key Fields |
---|---|---|---|
Stripe | customers_export.csv | 1,200 | Customer ID, Email, Name, Company |
Stripe | payments_export.csv | 6,000 | Payment ID, Amount, Customer, Status |
Stripe | subscriptions_export.csv | 840 | Subscription ID, Customer, Status, Plan Amount |
Critical Discrepancies Discovered
1. Company Data Inconsistencies
Issue: Same companies exist with conflicting address information between HubSpot and Salesforce.
Example – Acme Corporation:
- HubSpot: Lake Keithstad, Massachusetts
- Salesforce: Montgomeryfurt, Rhode Island
- Revenue ($33.8M) and employees (513) match, but addresses completely different
Impact: Customer service confusion, shipping errors, tax compliance issues
2. Pipeline Management Crisis
Deal/Opportunity Count Mismatch:
- HubSpot Deals: 1,300 records
- Salesforce Opportunities: 1,500 records
- Missing: 200 deals not synchronized
Financial Impact:
- HubSpot Pipeline Value: $264,275,126
- Salesforce Pipeline Value: $381,814,628
- Revenue Gap: $117,539,502 unaccounted for
3. Customer-Payment System Disconnects
Orphaned Records:
- 5 customers exist without payment records
- All payment records have corresponding customers (good)
- Revenue tracking integrity compromised
Subscription Status:
- Total subscriptions: 840
- Active subscriptions: 595
- 245 inactive subscriptions still in system
Revenue at Risk Analysis
The automated reconciliation process identified immediate threats to revenue:
- Active paying customers missing from CRM: 6 customers
- Monthly revenue at risk: $2,894.00
- Annual revenue exposure: $34,728.00
Critical Action Required – Missing Active Subscribers
Customer | Stripe ID | Status | |
---|---|---|---|
Robert Chavez | robert@grantgroup.com | cus_aaOzcavcdOlSBN | IMMEDIATE ACTION |
Christy Byrd | cbyrd@rtez.com | cus_BXCRNEBYGgOtSm | IMMEDIATE ACTION |
Robert Preston | robert@garciapearsonandfernandez.com | cus_idzMHxglRtBJsC | IMMEDIATE ACTION |
Danielle Russo | drusso@oliver.com | cus_ovQZWRyoSOYEKT | IMMEDIATE ACTION |
Brian Cain | bcain@sandovalgarciaandperkins.com | cus_txoVHJGUMKLarO | IMMEDIATE ACTION |
Deborah Ramsey | deborah.ramsey@nleyplc.com | cus_DoAwdpSTJJVKVJ | IMMEDIATE ACTION |
CRM Synchronization Issues
Total sync problems identified: 708 records
Pattern Analysis:
- Same contacts exist in both systems with different email formats
- HubSpot emails contain “+hubspot” suffixes (test data contamination)
- Name capitalization inconsistencies (e.g., “JENNINGS” vs “Jennings”)
Example Sync Failures:
HubSpot: jesusj+hubspot@ellis-adkins.com Salesforce: jesusj@ellis-adkins.com Result: Duplicate customer records, fractured customer journey
Business Impact Assessment
Immediate Risks
- Customer Churn: 6 paying customers ($2,894/month) invisible to sales teams
- Revenue Recognition: $117M pipeline discrepancy affects forecasting
- Customer Experience: Address mismatches cause delivery/service issues
Operational Risks
- Sales teams working with incomplete customer data
- Marketing campaigns targeting wrong/duplicate contacts
- Financial reporting inaccuracies due to system disconnects
Recommended Actions
Priority 1 (Immediate – Next 24 Hours)
- Add 6 missing active subscribers to CRM to prevent churn
- Audit and consolidate Acme account address information
- Implement emergency sync monitoring for revenue-critical customers
Priority 2 (This Week)
- Reconcile 200 missing deals/opportunities and $117M pipeline gap
- Standardize date formats across all integrated systems
- Clean test data from HubSpot (remove “+hubspot” email suffixes)
Priority 3 (Next 30 Days)
- Implement automated sync validation between all systems
- Establish single source of truth for company/contact data
- Create real-time monitoring dashboard for data integrity
The Bottom Line: This workflow found $117M in pipeline discrepancies and $34,728 in immediate churn risk that would have gone unnoticed. Instead of spending Sunday nights building spreadsheets, you now have actionable intelligence that can save and recover significant revenue.
Actual n8n Workflow Output
Here’s the exact Google Sheets report that the workflow automatically creates and saves to your Google Drive:
Column A | Column B | Column C | Column D |
---|---|---|---|
RevOps Reconciliation Report | 2025-06-13 | ||
EXECUTIVE SUMMARY | |||
Total Stripe Customers: | 1200 | ||
Total HubSpot Contacts: | 2200 | ||
Total Salesforce Contacts: | 1883 | ||
🚨 CRITICAL: Active Subscriptions Without CRM Record: | 6 | ||
💰 Monthly Revenue at Risk: | $2,894.00 | ||
⚠️ CRM Sync Issues: | 708 | ||
IMMEDIATE ACTION REQUIRED – Active Subscriptions Without CRM | |||
Customer Name | Stripe ID | Action Required | |
robert@grantgroup.com | Robert Chavez | cus_aaOzcavcdOlSBN | Add to CRM immediately |
cbyrd@rtez.com | Christy Byrd | cus_BXCRNEBYGgOtSm | Add to CRM immediately |
robert@garciapearsonandfernandez.com | Robert Preston | cus_idzMHxglRtBJsC | Add to CRM immediately |
drusso@oliver.com | Danielle Russo | cus_ovQZWRyoSOYEKT | Add to CRM immediately |
bcain@sandovalgarciaandperkins.com | Brian Cain | cus_txoVHJGUMKLarO | Add to CRM immediately |
deborah.ramsey@nleyplc.com | Deborah Ramsey | cus_DoAwdpSTJJVKVJ | Add to CRM immediately |
CRM SYNCHRONIZATION ISSUES | |||
In HubSpot but NOT in Salesforce | |||
Name | Company | ||
jesusj+hubspot@ellis-adkins.com | Jesus Jennings | Ellis-Adkins | |
sheila.armstrong+hubspot@williamsshieldsandmiller.com | Sheila Armstrong | Williams, Shields and Miller | |
kestes+hubspot@parker.com | Kathy Estes | Parker Ltd | |
In Salesforce but NOT in HubSpot | |||
Name | Company | ||
jesusj@ellis-adkins.com | Jesus JENNINGS | Ellis-Adkins | |
sheila.armstrong@williamsshieldsandmiller.com | Sheila Armstrong | Williams, Shields and Miller | |
kestes@parker.com | Kathy ESTES | Parker Ltd | |
DATA QUALITY OBSERVATIONS | |||
1. Some HubSpot emails contain “+hubspot” suffix – possible test data | |||
2. Name capitalization differs between systems (e.g., JENNINGS vs Jennings) | |||
3. Same contacts with slightly different emails in each system |
What makes this powerful:
- Automatic creation: The workflow creates this Google Sheet in your Drive without any manual work
- Executive ready: Clean format you can immediately share with leadership
- Actionable insights: Specific customer names, emails, and Stripe IDs for immediate follow-up
- Pattern detection: Shows systematic issues like test data contamination and sync failures
- Revenue impact: Quantifies exact dollars at risk ($2,894/month)
Ready to Reclaim Your Sundays?
This n8n workflow template represents days of development time. If it saves you even one Sunday night with your family, it’s worth it.
Also, checkout the website to see what else AudiTech has to offer RevOps.
Questions? Connect with me on LinkedIn or reach out if you need help implementing this for your specific data stack. If this workflow was helpful, drop a like, repost, or better yet tell me about it.