This workflow corresponds to n8n.io template #7374 — we link there as the canonical source.
This workflow follows the Emailsend → HTTP Request recipe pattern — see all workflows that pair these two integrations.
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 →
{
"id": "EeqqXkRfJ6ADiRgm",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "AWS Azure GCP Multi-Cloud Cost Monitoring & Alerts for Budget Control",
"tags": [],
"nodes": [
{
"id": "b172287e-8522-4204-af8c-a85554e1b9f8",
"name": "Cron Trigger",
"type": "n8n-nodes-base.cron",
"position": [
140,
-180
],
"parameters": {},
"typeVersion": 1
},
{
"id": "9a9bbc21-a699-499e-8c49-1e93ae8304ff",
"name": "AWS Billing Fetch",
"type": "n8n-nodes-base.httpRequest",
"position": [
360,
-380
],
"parameters": {
"url": "https://ce.us-east-1.amazonaws.com/",
"method": "POST",
"options": {},
"sendBody": true,
"sendHeaders": true,
"authentication": "genericCredentialType",
"bodyParameters": {
"parameters": []
},
"genericAuthType": "httpBasicAuth",
"headerParameters": {
"parameters": [
{
"name": "X-Amz-Target",
"value": "AWSInsightsIndexService.GetCostAndUsage"
},
{
"name": "Content-Type",
"value": "application/x-amz-json-1.1"
}
]
}
},
"credentials": {
"httpBasicAuth": {
"name": "<your credential>"
}
},
"typeVersion": 4.2
},
{
"id": "df146231-83a9-4a21-abcd-d614aeed73d2",
"name": "Azure Billing Fetch",
"type": "n8n-nodes-base.httpRequest",
"position": [
360,
-180
],
"parameters": {
"url": "https://management.azure.com/subscriptions/{{ $vars.AZURE_SUBSCRIPTION_ID }}/providers/Microsoft.CostManagement/query?api-version=2021-10-01",
"method": "POST",
"options": {},
"sendBody": true,
"sendHeaders": true,
"authentication": "genericCredentialType",
"bodyParameters": {
"parameters": [
{}
]
},
"genericAuthType": "oAuth1Api",
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
}
},
"credentials": {
"oAuth1Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.2
},
{
"id": "cc6d124d-c8fe-4da7-ab36-46d5f4d896bf",
"name": "GCP Billing Fetch",
"type": "n8n-nodes-base.httpRequest",
"position": [
360,
20
],
"parameters": {
"url": "https://cloudbilling.googleapis.com/v1/billingAccounts/{{ $vars.GCP_BILLING_ACCOUNT_ID }}/services",
"options": {},
"sendQuery": true,
"authentication": "genericCredentialType",
"genericAuthType": "oAuth1Api",
"queryParameters": {
"parameters": [
{
"name": "filter",
"value": "usage_start_time >= \"{{ $now.minus({hours: 1}).toISO() }}\" AND usage_start_time < \"{{ $now.toISO() }}\""
}
]
}
},
"credentials": {
"oAuth1Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.2
},
{
"id": "51f29b8b-cbc0-41e4-8116-1768cc411073",
"name": "Data Parser",
"type": "n8n-nodes-base.code",
"position": [
580,
-180
],
"parameters": {
"jsCode": "const items = $input.all();\nconst mergedData = [];\n\nfor (const item of items) {\n const platform = item.json.platform || 'unknown';\n const cost = item.json.cost || item.json.totalCost || 0;\n const resourceId = item.json.resourceId || item.json.service || 'unknown';\n \n mergedData.push({\n platform,\n cost: parseFloat(cost),\n resourceId,\n timestamp: new Date().toISOString(),\n owner: item.json.tags?.owner || item.json.owner || 'untagged'\n });\n}\n\nreturn mergedData.map(data => ({ json: data }));"
},
"typeVersion": 2
},
{
"id": "6eb4ef65-cdc4-43eb-86f4-00a063b50e90",
"name": "Cost Spike Detector",
"type": "n8n-nodes-base.code",
"position": [
800,
-180
],
"parameters": {
"jsCode": "const items = $input.all();\nconst alerts = [];\nconst COST_THRESHOLD = parseFloat($vars.COST_THRESHOLD || '50');\nconst SPIKE_MULTIPLIER = parseFloat($vars.SPIKE_MULTIPLIER || '2.0');\n\nfor (const item of items) {\n const cost = item.json.cost;\n const platform = item.json.platform;\n const resourceId = item.json.resourceId;\n \n // Simple spike detection - compare with threshold\n if (cost > COST_THRESHOLD) {\n alerts.push({\n type: 'threshold_exceeded',\n platform,\n resourceId,\n currentCost: cost,\n threshold: COST_THRESHOLD,\n owner: item.json.owner,\n severity: cost > (COST_THRESHOLD * 2) ? 'HIGH' : 'MEDIUM'\n });\n }\n}\n\nreturn alerts.map(alert => ({ json: alert }));"
},
"typeVersion": 2
},
{
"id": "ee98766c-e7e2-4f2c-8d25-9b25a8d9ef24",
"name": "Owner Identifier",
"type": "n8n-nodes-base.if",
"position": [
1020,
-180
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "owner-check",
"operator": {
"type": "string",
"operation": "equals",
"rightType": "manual"
},
"leftValue": "={{ $json.owner }}",
"rightValue": "untagged"
}
]
}
},
"typeVersion": 2
},
{
"id": "8eb36fe2-846e-47db-9771-38648146a629",
"name": "Auto-Tag Resource",
"type": "n8n-nodes-base.code",
"position": [
1240,
-180
],
"parameters": {
"jsCode": "// Auto-tagging logic based on platform\nconst item = $input.first().json;\nconst platform = item.platform;\nconst resourceId = item.resourceId;\n\nlet tagCommand = '';\n\nswitch(platform) {\n case 'aws':\n tagCommand = `aws ec2 create-tags --resources ${resourceId} --tags Key=CostAlert,Value=true Key=AlertTime,Value=${new Date().toISOString()}`;\n break;\n case 'azure':\n tagCommand = `az resource tag --ids ${resourceId} --tags CostAlert=true AlertTime=${new Date().toISOString()}`;\n break;\n case 'gcp':\n tagCommand = `gcloud compute instances add-labels ${resourceId} --labels=cost-alert=true,alert-time=${Date.now()}`;\n break;\n}\n\nreturn [{ json: { ...item, tagCommand } }];"
},
"typeVersion": 2
},
{
"id": "d07764c6-fc5b-4614-ad39-b9373b67daaa",
"name": "Alert Sender On Email",
"type": "n8n-nodes-base.emailSend",
"position": [
1460,
-380
],
"parameters": {
"text": "=\ud83d\udea8 **Cost Alert** \ud83d\udea8|**Platform:** {{ $json.platform }}**Resource:** {{ $json.resourceId }}**Current Cost:** ${{ $json.currentCost }}**Threshold:** ${{ $json.threshold }}**Owner:** {{ $json.owner }}**Severity:** {{ $json.severity }}**Time:** {{ $json.timestamp }}*Auto-tagging command:*```{{ $json.tagCommand }}```",
"options": {},
"subject": "\ud83d\udea8 **Cost Alert** \ud83d\udea8",
"toEmail": "user@example.com,user@example.com",
"fromEmail": "user@example.com",
"emailFormat": "text"
},
"credentials": {
"smtp": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
},
{
"id": "becc8559-a46a-4d31-a2f9-9b92d2de2d55",
"name": "Alert Sender On WhatsApp",
"type": "n8n-nodes-base.whatsApp",
"position": [
1460,
-180
],
"parameters": {
"textBody": "=\ud83d\udea8 **Cost Alert** \ud83d\udea8|**Platform:** {{ $json.platform }}**Resource:** {{ $json.resourceId }}**Current Cost:** ${{ $json.currentCost }}**Threshold:** ${{ $json.threshold }}**Owner:** {{ $json.owner }}**Severity:** {{ $json.severity }}**Time:** {{ $json.timestamp }}*Auto-tagging command:*```{{ $json.tagCommand }}```",
"operation": "send",
"phoneNumberId": "=+919999888877",
"additionalFields": {},
"recipientPhoneNumber": "+1234567890,+1234567890,+1234567890"
},
"credentials": {
"whatsAppApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "7cfa7945-ad77-46aa-9942-30a27bc77d55",
"name": "Alert Sender On Slack",
"type": "n8n-nodes-base.slack",
"position": [
1460,
20
],
"parameters": {
"text": "\ud83d\udea8 **Cost Alert** \ud83d\udea8\n\n**Platform:** {{ $json.platform }}\n**Resource:** {{ $json.resourceId }}\n**Current Cost:** ${{ $json.currentCost }}\n**Threshold:** ${{ $json.threshold }}\n**Owner:** {{ $json.owner }}\n**Severity:** {{ $json.severity }}\n**Time:** {{ $json.timestamp }}\n\n*Auto-tagging command:*\n```{{ $json.tagCommand }}```",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "name",
"value": "{{ $vars.SLACK_CHANNEL_ID }}"
},
"otherOptions": {}
},
"credentials": {
"slackApi": {
"name": "<your credential>"
}
},
"typeVersion": 2
},
{
"id": "e3274f83-533e-4cc9-af50-cb50e7ba5db4",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
620,
-620
],
"parameters": {
"color": 6,
"width": 700,
"height": 300,
"content": "## **How It Works**\n\n1. **Hourly Cron Trigger** \u2013 Starts the workflow every hour to fetch updated billing data.\n2. **AWS Billing Fetch** \u2013 Retrieves latest cost and usage data via AWS Cost Explorer API.\n3. **Azure Billing Fetch** \u2013 Retrieves subscription cost data from Azure Cost Management API.\n4. **GCP Billing Fetch** \u2013 Retrieves project-level spend data using GCP Cloud Billing API.\n5. **Data Parser** \u2013 Combines and cleans data from all three clouds into a unified format.\n6. **Cost Spike Detector** \u2013 Identifies unusual spending patterns or budget overruns.\n7. **Owner Identifier** \u2013 Matches resources to their respective owners or teams.\n8. **Auto-Tag Resource** \u2013 Tags the affected resource for quick identification and follow-up.\n9. **Alert Sender** \u2013 Sends notifications through Email, WhatsApp, and Slack with detailed cost reports."
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "3e35fbfb-6c60-4cf3-a680-bc0fb7e7239e",
"connections": {
"Data Parser": {
"main": [
[
{
"node": "Cost Spike Detector",
"type": "main",
"index": 0
}
]
]
},
"Cron Trigger": {
"main": [
[
{
"node": "AWS Billing Fetch",
"type": "main",
"index": 0
},
{
"node": "Azure Billing Fetch",
"type": "main",
"index": 0
},
{
"node": "GCP Billing Fetch",
"type": "main",
"index": 0
}
]
]
},
"Owner Identifier": {
"main": [
[
{
"node": "Auto-Tag Resource",
"type": "main",
"index": 0
}
],
[
{
"node": "Auto-Tag Resource",
"type": "main",
"index": 0
}
]
]
},
"AWS Billing Fetch": {
"main": [
[
{
"node": "Data Parser",
"type": "main",
"index": 0
}
]
]
},
"Auto-Tag Resource": {
"main": [
[
{
"node": "Alert Sender On Slack",
"type": "main",
"index": 0
},
{
"node": "Alert Sender On WhatsApp",
"type": "main",
"index": 0
},
{
"node": "Alert Sender On Email",
"type": "main",
"index": 0
}
]
]
},
"GCP Billing Fetch": {
"main": [
[
{
"node": "Data Parser",
"type": "main",
"index": 0
}
]
]
},
"Azure Billing Fetch": {
"main": [
[
{
"node": "Data Parser",
"type": "main",
"index": 0
}
]
]
},
"Cost Spike Detector": {
"main": [
[
{
"node": "Owner Identifier",
"type": "main",
"index": 0
}
]
]
},
"Alert Sender On Email": {
"main": [
[]
]
}
}
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
httpBasicAuthoAuth1ApislackApismtpwhatsAppApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This automated n8n workflow tracks hourly cloud spending across AWS, Azure, and GCP. It detects cost spikes or budget overruns in real time, tags affected resources, and sends alerts via email, WhatsApp, or Slack. This ensures proactive cost management and prevents budget…
Source: https://n8n.io/workflows/7374/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Enhance financial oversight with this automated n8n workflow. Triggered every 5 minutes, it fetches real-time bank transactions via an API, enriches and transforms the data, and applies smart logic to
This workflow automates competitive price intelligence using Bright Data's enterprise web scraping API. On a scheduled basis (default: daily at 9 AM), the system loops through configured competitor pr
This n8n workflow proactively scans and aggregates threat intelligence, network logs, and vulnerability data every 15 minutes to detect emerging risks across the infrastructure. It analyzes anomalies,
SEO managers, content marketers, bloggers, and growth teams who want to automatically catch declining content performance before it's too late — without manually checking Google Search Console every w
Automate tax deadline monitoring with AI-powered insights. This workflow checks your tax calendar daily at 8 AM, uses GPT-4 to analyze upcoming deadlines across multiple jurisdictions, detects overdue