How to Build a Multi-App Automation System with n8n (Free Template)

How to Build a Multi-App Automation System with n8n (Free Template)

Managing data across multiple business applications creates bottlenecks. You're copying information from Stripe to Airtable, manually updating Google Sheets, and sending Slack notifications one at a time. This workflow teaches you to build a robust n8n automation that connects these services with webhooks, REST APIs, and JavaScript transformation logic. By the end, you'll have a production-ready template that handles real-time data synchronization across your entire tech stack.

The Problem: Manual Data Management Across Multiple Platforms

Current challenges:

  • Copying payment data from Stripe to Airtable manually wastes 5-10 hours per week
  • Google Sheets reports are outdated by the time you update them
  • Team notifications in Slack arrive late or get forgotten entirely
  • Data transformation between different API formats requires technical knowledge most teams lack
  • Webhook failures go unnoticed for days, creating data gaps

Business impact:

  • Time spent: 10-15 hours per week on manual data entry
  • Error rate: 15-20% from copy-paste mistakes
  • Decision delays: Reports lag by 24-48 hours
  • Lost revenue: Delayed follow-ups on high-value transactions

The Solution Overview

This n8n workflow creates a centralized automation hub that listens for events from Stripe, processes the data using JavaScript, updates Airtable records, syncs Google Sheets, and sends formatted Slack notifications. The system uses webhooks for real-time triggers, HTTP requests for API integration, and Code nodes for data transformation. This approach eliminates manual data entry while maintaining full control over business logic and data formatting across all your connected services.

What You'll Build

Component Technology Purpose
Event Trigger Webhook Node Receives real-time events from Stripe, Airtable, or custom sources
Data Processing JavaScript Code Node Transforms JSON data structures and applies business logic
Database Sync Airtable HTTP Request Creates/updates records with processed data
Reporting Google Sheets API Maintains live dashboards and reports
Notifications Slack Webhook Sends formatted alerts to team channels
Error Handling Error Workflow Catches failures and sends diagnostic information

Key capabilities:

  • Real-time webhook processing with automatic retry logic
  • JSON data transformation using JavaScript
  • Multi-service synchronization (Stripe → Airtable → Sheets → Slack)
  • Custom business rule implementation
  • Automated error notifications and logging

Prerequisites

Before starting, ensure you have:

  • n8n instance (cloud or self-hosted version 0.196.0+)
  • Stripe account with webhook configuration access
  • Airtable workspace with API key (Personal Access Token)
  • Google Sheets API credentials (OAuth2 or Service Account)
  • Slack workspace with incoming webhook URL
  • Basic JavaScript knowledge for Code node customization
  • Understanding of REST API concepts and JSON structure

Step 1: Set Up Webhook Listener

The workflow starts with a Webhook node that receives incoming data from external services. This creates a unique URL endpoint that Stripe, Airtable, or any HTTP client can POST data to.

Configure the Webhook Node:

  1. Add a Webhook node as your workflow trigger
  2. Set HTTP Method to POST (accepts incoming data)
  3. Set Path to something memorable like /automation-hub
  4. Enable "Respond Immediately" to prevent timeout errors
  5. Set Response Code to 200 (confirms receipt)

Node configuration:

{
  "httpMethod": "POST",
  "path": "automation-hub",
  "responseMode": "onReceived",
  "responseCode": 200,
  "responseData": "{ \"status\": \"received\" }"
}

Why this works:

Webhooks provide real-time event notifications instead of polling APIs every few minutes. When Stripe processes a payment, it immediately sends data to your n8n endpoint. The "Respond Immediately" setting prevents the sending service from timing out while n8n processes the workflow, which can take 5-10 seconds for complex operations.

Testing your webhook:

Use curl to send test data:

curl -X POST https://your-n8n-instance.com/webhook/automation-hub \
  -H "Content-Type: application/json" \
  -d '{"test": "data", "amount": 5000}'

Step 2: Transform Data with JavaScript

Raw webhook data rarely matches the format your destination services expect. The Code node lets you write JavaScript to restructure JSON, apply calculations, and implement business logic.

Configure the Code Node:

  1. Add a Code node after your Webhook
  2. Select "Run Once for All Items" mode
  3. Write JavaScript to transform the incoming data structure

Example transformation code:

// Access webhook data
const webhookData = items[0].json;

// Transform Stripe payment data
const transformed = {
  customer_name: webhookData.customer?.name || 'Unknown',
  amount_usd: webhookData.amount / 100, // Convert cents to dollars
  transaction_date: new Date(webhookData.created * 1000).toISOString(),
  status: webhookData.status.toUpperCase(),
  stripe_id: webhookData.id,
  metadata: JSON.stringify(webhookData.metadata)
};

// Return formatted data for next nodes
return [{ json: transformed }];

Why this approach:

Different APIs use different data formats. Stripe stores amounts in cents, Airtable expects dollars. Stripe uses Unix timestamps, Google Sheets needs ISO dates. The Code node acts as a translation layer, ensuring each service receives data in its expected format. This prevents "invalid data type" errors and maintains data consistency.

Variables to customize:

  • amount / 100: Adjust divisor based on currency (JPY uses 1, not 100)
  • status.toUpperCase(): Change to .toLowerCase() if your system uses lowercase
  • metadata: Add conditional logic to extract specific fields

Step 3: Update Airtable Records

Airtable serves as your central database. The HTTP Request node sends transformed data to Airtable's REST API to create or update records.

Configure the HTTP Request Node:

  1. Add HTTP Request node after Code node
  2. Set Method to POST (create) or PATCH (update)
  3. Set URL to https://api.airtable.com/v0/{baseId}/{tableName}
  4. Add Authentication: Bearer Token with your Airtable API key

Request configuration:

{
  "method": "POST",
  "url": "https://api.airtable.com/v0/appXXXXXXXXXXXXXX/Transactions",
  "authentication": "genericCredentialType",
  "genericAuthType": "httpHeaderAuth",
  "headers": {
    "Authorization": "Bearer patXXXXXXXXXXXXXXXX",
    "Content-Type": "application/json"
  },
  "body": {
    "fields": {
      "Customer Name": "={{$json.customer_name}}",
      "Amount": "={{$json.amount_usd}}",
      "Date": "={{$json.transaction_date}}",
      "Status": "={{$json.status}}",
      "Stripe ID": "={{$json.stripe_id}}"
    }
  }
}

Common issues:

  • Using wrong base ID → Results in 404 errors (find in Airtable URL: airtable.com/appXXXXXXXXXXXXXX)
  • Field name mismatches → Use exact field names from Airtable (case-sensitive)
  • Rate limiting → Airtable allows 5 requests/second; add Wait node if processing batches

Why this works:

Airtable's API accepts JSON payloads that map directly to table fields. The ={{$json.field}} syntax pulls data from the previous Code node's output. This creates a live database that updates instantly when webhooks fire, eliminating the need for manual data entry or CSV imports.

Step 4: Sync Google Sheets

Google Sheets provides familiar reporting interfaces for non-technical team members. The Google Sheets node appends new rows or updates existing ones based on your workflow logic.

Configure Google Sheets Node:

  1. Add Google Sheets node
  2. Select "Append" operation to add new rows
  3. Choose your spreadsheet and sheet name
  4. Map fields from previous node output

Field mapping:

Sheet Column n8n Expression Data Type
Customer ={{$json.customer_name}} Text
Amount ={{$json.amount_usd}} Number
Date ={{$json.transaction_date}} Date
Status ={{$json.status}} Text
Stripe Link =HYPERLINK("https://dashboard.stripe.com/payments/{{$json.stripe_id}}") Formula

Authentication setup:

Use Google OAuth2 credentials:

  • Scopes needed: https://www.googleapis.com/auth/spreadsheets
  • Enable Google Sheets API in Google Cloud Console
  • Create OAuth2 credentials and add to n8n

Performance optimization:

For high-volume workflows (>100 transactions/day), use batch operations:

  • Collect items in a Set node
  • Use "Append Multiple Rows" instead of individual appends
  • Reduces API calls from 100 to 1, staying within Google's quota limits

Workflow Architecture Overview

This workflow consists of 6 core nodes organized into 3 main sections:

  1. Data ingestion (Nodes 1-2): Webhook receives events, Code node transforms JSON structure
  2. Database operations (Nodes 3-4): HTTP Request updates Airtable, Google Sheets node syncs reporting
  3. Notification delivery (Node 5): Slack webhook sends formatted team alerts

Execution flow:

  • Trigger: Webhook receives POST request from Stripe/Airtable/custom source
  • Average run time: 2-4 seconds for single item processing
  • Key dependencies: Airtable API, Google Sheets API, Slack webhook must be configured

Critical nodes:

  • Code Node: Handles data transformation, business logic, and format conversion
  • HTTP Request: Processes Airtable API calls with error handling and retry logic
  • Google Sheets: Maintains live reporting dashboard with automatic row appends
  • Slack Webhook: Delivers formatted notifications with transaction details

The complete n8n workflow JSON template is available at the bottom of this article.

Step 5: Send Slack Notifications

Team notifications keep everyone informed about important events. The HTTP Request node (configured for Slack's webhook API) sends formatted messages to designated channels.

Configure Slack Webhook Node:

  1. Add HTTP Request node
  2. Set Method to POST
  3. Set URL to your Slack webhook URL (get from Slack App settings)
  4. Format message body as JSON

Message formatting:

{
  "text": "New Transaction Recorded",
  "blocks": [
    {
      "type": "section",
      "text": {
        "type": "mrkdwn",
        "text": "*Customer:* {{$json.customer_name}}
*Amount:* ${{$json.amount_usd}}
*Status:* {{$json.status}}"
      }
    },
    {
      "type": "actions",
      "elements": [
        {
          "type": "button",
          "text": {
            "type": "plain_text",
            "text": "View in Stripe"
          },
          "url": "https://dashboard.stripe.com/payments/{{$json.stripe_id}}"
        }
      ]
    }
  ]
}

Why this approach:

Slack's Block Kit format creates rich, interactive messages instead of plain text. Team members can click directly to Stripe dashboards without searching for transaction IDs. This reduces response time from 10+ minutes (finding the transaction) to under 30 seconds (immediate access).

Conditional notifications:

Add an IF node before Slack to filter:

  • Only notify for amounts >$500
  • Only send during business hours (9am-5pm)
  • Skip notifications for refunds or test transactions

Key Configuration Details

Critical Configuration Settings

Webhook Security

Add authentication to prevent unauthorized access:

{
  "headerAuth": {
    "name": "X-Webhook-Secret",
    "value": "your-secret-key-here"
  }
}

Configure Stripe to send this header in webhook settings. Reject requests without matching secret.

Error Handling Strategy

Add an Error Trigger workflow:

  1. Create new workflow with Error Trigger node
  2. Configure to catch errors from main workflow
  3. Add Slack notification with error details
  4. Include failed item data for debugging

Error notification format:

{
  "error_message": "={{$json.error.message}}",
  "failed_node": "={{$json.error.node.name}}",
  "timestamp": "={{$now}}",
  "input_data": "={{JSON.stringify($json.error.context.itemIndex)}}"
}

Rate Limiting Protection

APIs have request limits. Add these safeguards:

Service Limit Protection Strategy
Airtable 5 req/sec Add Wait node (250ms) between requests
Google Sheets 100 req/100sec Batch operations, use "Append Multiple"
Slack 1 req/sec Queue messages, send every 2 seconds

Data Validation

Add validation before API calls:

// Validate required fields exist
const required = ['customer_name', 'amount_usd', 'stripe_id'];
const missing = required.filter(field => !items[0].json[field]);

if (missing.length > 0) {
  throw new Error(`Missing required fields: ${missing.join(', ')}`);
}

// Validate data types
if (typeof items[0].json.amount_usd !== 'number') {
  throw new Error('Amount must be a number');
}

return items;

This prevents "invalid field" errors from reaching external APIs.

Testing & Validation

Component Testing

Test each node individually:

  1. Webhook: Use curl or Postman to send test payloads
  2. Code Node: Add console.log() statements, check execution logs
  3. Airtable: Verify record creation in Airtable interface
  4. Google Sheets: Check new row appears with correct formatting
  5. Slack: Confirm message format and channel delivery

Integration Testing

Run end-to-end tests with real data:

  1. Trigger actual Stripe test payment
  2. Verify data flows through all nodes
  3. Check Airtable record matches Stripe data
  4. Confirm Google Sheets row contains all fields
  5. Validate Slack message includes clickable links

Common Troubleshooting

Issue Cause Solution
Webhook not receiving data Incorrect URL in Stripe Copy exact webhook URL from n8n, paste in Stripe settings
Airtable 422 error Field type mismatch Check Airtable field types match data types (number vs text)
Google Sheets auth failure Expired OAuth token Reconnect Google account in n8n credentials
Slack message not formatted Invalid JSON structure Validate JSON in Slack Block Kit Builder

Execution Logs

Enable detailed logging:

  • Go to Workflow Settings → Enable "Save Execution Progress"
  • Review failed executions in Executions tab
  • Check input/output data for each node
  • Look for error messages in node details

Production Deployment Checklist

Area Requirement Why It Matters
Error Handling Error Trigger workflow with Slack alerts Detect failures within 5 minutes vs discovering issues days later
Monitoring Webhook health checks every 15 min Catch API downtime before customers report issues
Documentation Node-by-node comments explaining logic Reduces modification time from 4 hours to 30 minutes
Credentials Use n8n credential system, never hardcode Prevents API key exposure in workflow exports
Backup Export workflow JSON weekly Enables rollback if changes break production
Rate Limits Implement queuing for high-volume scenarios Prevents API bans during traffic spikes

Production Environment Setup

Self-hosted n8n requirements:

  • Minimum 2GB RAM for reliable operation
  • PostgreSQL database (SQLite not recommended for production)
  • SSL certificate for webhook security
  • Automated backups of n8n database
  • Process manager (PM2 or systemd) for auto-restart

Scaling Considerations

For workflows processing >1000 items/day:

  • Split into multiple workflows by data type
  • Use Queue nodes to prevent memory issues
  • Implement batch processing (process 100 items at once)
  • Add caching layer for repeated API lookups
  • Monitor execution times and optimize slow nodes

Real-World Use Cases

Use Case 1: E-commerce Order Processing

  • Industry: Online retail
  • Scale: 200-500 orders/day
  • Modifications needed: Add inventory check before Airtable update, connect to shipping API for tracking numbers, send customer confirmation emails via SendGrid node

Use Case 2: SaaS Subscription Management

  • Industry: Software-as-a-Service
  • Scale: 50-100 new subscriptions/day
  • Modifications needed: Replace Stripe webhook with Paddle/Chargebee, add trial expiration logic, sync to CRM (HubSpot/Salesforce) instead of Airtable

Use Case 3: Lead Qualification System

  • Industry: B2B Sales
  • Scale: 300-400 leads/day
  • Modifications needed: Webhook receives form submissions, Code node scores leads based on criteria, high-value leads go to Slack + CRM, low-value to nurture campaign

Use Case 4: Financial Reporting Automation

  • Industry: Accounting/Finance
  • Scale: Daily reconciliation of 1000+ transactions
  • Modifications needed: Pull data from multiple payment processors, aggregate in Code node, generate PDF reports, email to finance team, archive in Google Drive

Customizing This Workflow

Alternative Integrations

Instead of Airtable:

  • PostgreSQL/Supabase: Best for high-volume data (>10k records) - requires HTTP Request node with SQL queries
  • Notion: Better for team collaboration - use Notion API node, swap field mapping
  • MongoDB: Use when handling complex nested data structures - requires MongoDB node and JSON schema design

Instead of Google Sheets:

  • Excel Online: Better for Microsoft 365 environments - use Microsoft Excel node with same field mapping
  • Tableau: For advanced analytics - requires Tableau API and data prep in Code node
  • Power BI: Executive dashboards - use Power BI REST API with authentication setup

Workflow Extensions

Add automated reporting:

  • Add Schedule node to run daily at 9am
  • Aggregate previous day's data in Code node
  • Generate summary statistics (total revenue, transaction count, average order value)
  • Send formatted email via Gmail node
  • Nodes needed: +4 (Schedule, Code, Gmail, Set)

Scale to handle batch imports:

  • Replace Webhook with Google Sheets trigger (monitors for new rows)
  • Add Split in Batches node (process 50 rows at a time)
  • Implement rate limiting with Wait node
  • Add progress tracking to separate sheet
  • Performance improvement: Handle 5000+ rows without timeout errors

Integration possibilities:

Add This To Get This Complexity
Twilio SMS Customer transaction alerts Easy (2 nodes: IF + Twilio)
QuickBooks Automated accounting entries Medium (5 nodes: auth + data mapping)
Zapier Webhook Connect to 3000+ apps Easy (1 node: Webhook out)
OpenAI AI-powered data categorization Medium (3 nodes: Code + HTTP + logic)
Stripe Radar Fraud detection integration Medium (4 nodes: API calls + scoring)

Advanced Customizations

Implement duplicate detection:

// Check if Stripe ID already exists in Airtable
const stripeId = items[0].json.stripe_id;
const existingRecords = await this.helpers.httpRequest({
  method: 'GET',
  url: `https://api.airtable.com/v0/${baseId}/${tableName}`,
  qs: {
    filterByFormula: `{Stripe ID} = '${stripeId}'`
  }
});

if (existingRecords.records.length > 0) {
  // Update existing record instead of creating new
  return [{ json: { action: 'update', recordId: existingRecords.records[0].id } }];
}

return [{ json: { action: 'create' } }];

Add multi-currency support:

// Convert amounts to USD using exchange rate API
const currency = items[0].json.currency;
const amount = items[0].json.amount;

if (currency !== 'USD') {
  const rates = await this.helpers.httpRequest({
    method: 'GET',
    url: `https://api.exchangerate-api.com/v4/latest/${currency}`
  });
  
  const amountUSD = amount * rates.rates.USD;
  return [{ json: { ...items[0].json, amount_usd: amountUSD } }];
}

return items;

Get Started Today

Ready to automate your multi-app workflows?

  1. Download the template: Scroll to the bottom of this article to copy the n8n workflow JSON
  2. Import to n8n: Go to Workflows → Import from File, paste the JSON
  3. Configure your services: Add API credentials for Stripe, Airtable, Google Sheets, and Slack
  4. Test with sample data: Send test webhook payload, verify all nodes execute successfully
  5. Deploy to production: Activate workflow, configure Stripe webhooks to point to your n8n URL

Next steps for customization:

  • Modify Code node logic for your specific business rules
  • Add conditional routing based on transaction amounts or customer types
  • Extend with additional services (CRM, email marketing, analytics)
  • Implement advanced error handling and retry strategies

Need help customizing this workflow for your specific needs? Schedule an intro call with Atherial at https://atherial.ai/contact to discuss your automation requirements and get expert guidance on building production-ready n8n solutions.


N8N Workflow JSON Template

{
  "name": "Multi-App Automation Hub",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "automation-hub",
        "responseMode": "onReceived",
        "responseCode": 200,
        "responseData": "{ \"status\": \"received\" }"
      },
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 1,
      "position": [250, 300]
    },
    {
      "parameters": {
        "jsCode": "const webhookData = items[0].json;

const transformed = {
  customer_name: webhookData.customer?.name || 'Unknown',
  amount_usd: webhookData.amount / 100,
  transaction_date: new Date(webhookData.created * 1000).toISOString(),
  status: webhookData.status.toUpperCase(),
  stripe_id: webhookData.id,
  metadata: JSON.stringify(webhookData.metadata)
};

return [{ json: transformed }];"
      },
      "name": "Transform Data",
      "type": "n8n-nodes-base.code",
      "typeVersion": 1,
      "position": [450, 300]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.airtable.com/v0/appXXXXXXXXXXXXXX/Transactions",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "fields",
              "value": "={\"Customer Name\": \"{{$json.customer_name}}\", \"Amount\": {{$json.amount_usd}}, \"Date\": \"{{$json.transaction_date}}\", \"Status\": \"{{$json.status}}\", \"Stripe ID\": \"{{$json.stripe_id}}\"}"
            }
          ]
        }
      },
      "name": "Update Airtable",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 3,
      "position": [650, 200]
    },
    {
      "parameters": {
        "operation": "append",
        "documentId": "YOUR_SHEET_ID",
        "sheetName": "Transactions",
        "columns": {
          "mappings": [
            { "column": "Customer", "value": "={{$json.customer_name}}" },
            { "column": "Amount", "value": "={{$json.amount_usd}}" },
            { "column": "Date", "value": "={{$json.transaction_date}}" },
            { "column": "Status", "value": "={{$json.status}}" }
          ]
        }
      },
      "name": "Sync Google Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 3,
      "position": [650, 400]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "YOUR_SLACK_WEBHOOK_URL",
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "text",
              "value": "New Transaction: {{$json.customer_name}} - ${{$json.amount_usd}}"
            }
          ]
        }
      },
      "name": "Send Slack Alert",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 3,
      "position": [850, 300]
    }
  ],
  "connections": {
    "Webhook": {
      "main": [[{ "node": "Transform Data", "type": "main", "index": 0 }]]
    },
    "Transform Data": {
      "main": [
        [
          { "node": "Update Airtable", "type": "main", "index": 0 },
          { "node": "Sync Google Sheets", "type": "main", "index": 0 }
        ]
      ]
    },
    "Update Airtable": {
      "main": [[{ "node": "Send Slack Alert", "type": "main", "index": 0 }]]
    }
  }
}

Replace placeholder values (YOUR_SHEET_ID, YOUR_SLACK_WEBHOOK_URL, Airtable base ID) with your actual credentials before importing.

Complete N8N Workflow Template

Copy the JSON below and import it into your N8N instance via Workflows → Import from File

{
  "name": "Multi-App Data Sync Automation",
  "nodes": [
    {
      "id": "1",
      "name": "Webhook Trigger",
      "type": "n8n-nodes-base.webhook",
      "onError": "continueRegularOutput",
      "position": [
        50,
        100
      ],
      "parameters": {
        "path": "automation/sync",
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "typeVersion": 2.1
    },
    {
      "id": "2",
      "name": "Validate Incoming Data",
      "type": "n8n-nodes-base.code",
      "onError": "continueRegularOutput",
      "position": [
        250,
        100
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const validateData = (items) => {\n  return items.map(item => {\n    const body = item.body || {};\n    return {\n      ...item,\n      validated: true,\n      timestamp: new Date().toISOString(),\n      dataQuality: {\n        hasRequiredFields: Boolean(body.email && body.amount),\n        isEmpty: Object.keys(body).length === 0,\n        isValid: Boolean(body.email && typeof body.amount === 'number')\n      }\n    };\n  });\n};\nreturn validateData($input.all());",
        "language": "javaScript"
      },
      "typeVersion": 2
    },
    {
      "id": "3",
      "name": "Quality Check",
      "type": "n8n-nodes-base.if",
      "onError": "continueErrorOutput",
      "position": [
        450,
        100
      ],
      "parameters": {
        "value1": "=$json.dataQuality.isValid",
        "value2": true,
        "combinator": "or",
        "conditions": {
          "pass": {
            "type": "any",
            "value": [],
            "combinator": "or",
            "conditions": []
          },
          "catch": {
            "type": "any",
            "value": [],
            "combinator": "or",
            "conditions": []
          }
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "4",
      "name": "Transform for Stripe",
      "type": "n8n-nodes-base.code",
      "onError": "continueRegularOutput",
      "position": [
        650,
        50
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "return $input.all().map(item => ({\n  customerId: item.body?.customerId || item.body?.email,\n  amount: Math.round(item.body?.amount * 100),\n  currency: item.body?.currency || 'USD',\n  description: item.body?.description || 'Automated transaction',\n  source: 'tok_visa',\n  metadata: {\n    sourceApp: item.body?.source || 'webhook',\n    processedAt: new Date().toISOString(),\n    email: item.body?.email\n  }\n}));",
        "language": "javaScript"
      },
      "typeVersion": 2
    },
    {
      "id": "5",
      "name": "Create Stripe Charge",
      "type": "n8n-nodes-base.stripe",
      "onError": "continueRegularOutput",
      "position": [
        850,
        50
      ],
      "parameters": {
        "amount": "={{$json.amount}}",
        "source": "={{$json.source}}",
        "currency": "={{$json.currency}}",
        "resource": "charge",
        "operation": "create",
        "customerId": {
          "__rl": true,
          "mode": "expression",
          "value": "={{$json.customerId}}"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "6",
      "name": "Transform for Airtable",
      "type": "n8n-nodes-base.code",
      "onError": "continueRegularOutput",
      "position": [
        650,
        150
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "return $input.all().map(item => ({\n  fields: {\n    email: item.body?.email || 'unknown@example.com',\n    name: item.body?.name || 'Unknown Customer',\n    amount: item.body?.amount || 0,\n    status: 'processed',\n    source: item.body?.source || 'webhook',\n    date: new Date().toISOString().split('T')[0],\n    notes: item.body?.notes || ''\n  }\n}));",
        "language": "javaScript"
      },
      "typeVersion": 2
    },
    {
      "id": "7",
      "name": "Create Airtable Record",
      "type": "n8n-nodes-base.airtable",
      "onError": "continueRegularOutput",
      "position": [
        850,
        150
      ],
      "parameters": {
        "base": "appXXXXXXXXXXXXXX",
        "table": "Transactions",
        "resource": "record",
        "typecast": true,
        "operation": "create"
      },
      "typeVersion": 2.1
    },
    {
      "id": "8",
      "name": "Format Success Message",
      "type": "n8n-nodes-base.code",
      "onError": "continueRegularOutput",
      "position": [
        1050,
        100
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "return $input.all().map(item => ({\n  text: `:white_check_mark: *Workflow Sync Success*\\n\\n*Customer:* ${item.body?.email || 'unknown'}\\n*Amount:* $${item.body?.amount}\\n*Status:* Data synced to Stripe & Airtable\\n*Time:* ${new Date().toLocaleString()}\\n\\nAll integrations operational.`,\n  status: 'success'\n}));",
        "language": "javaScript"
      },
      "typeVersion": 2
    },
    {
      "id": "9",
      "name": "Post to Slack",
      "type": "n8n-nodes-base.slack",
      "onError": "continueRegularOutput",
      "position": [
        1250,
        100
      ],
      "parameters": {
        "text": "={{$json.text}}",
        "resource": "message",
        "channelId": "C0XXXXXX",
        "operation": "post"
      },
      "typeVersion": 2.3
    },
    {
      "id": "10",
      "name": "Send Validation Error",
      "type": "n8n-nodes-base.respondToWebhook",
      "onError": "continueRegularOutput",
      "position": [
        650,
        300
      ],
      "parameters": {
        "responseCode": 400,
        "responseData": "={{{'success': false, 'error': 'Data validation failed. Required fields: email and amount', 'timestamp': new Date().toISOString()}}}"
      },
      "typeVersion": 1.4
    },
    {
      "id": "11",
      "name": "Send Success Response",
      "type": "n8n-nodes-base.respondToWebhook",
      "onError": "continueRegularOutput",
      "position": [
        1450,
        100
      ],
      "parameters": {
        "responseCode": 200,
        "responseData": "={{{'success': true, 'message': 'Data synchronized successfully across all platforms', 'synced_to': ['Stripe', 'Airtable', 'Slack'], 'timestamp': new Date().toISOString()}}}"
      },
      "typeVersion": 1.4
    }
  ],
  "connections": {
    "Post to Slack": {
      "main": [
        [
          {
            "node": "Send Success Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Quality Check": {
      "main": [
        [
          {
            "node": "Transform for Stripe",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Send Validation Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook Trigger": {
      "main": [
        [
          {
            "node": "Validate Incoming Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Stripe Charge": {
      "main": [
        [
          {
            "node": "Transform for Airtable",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Transform for Stripe": {
      "main": [
        [
          {
            "node": "Create Stripe Charge",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Success Response": {
      "main": []
    },
    "Send Validation Error": {
      "main": []
    },
    "Create Airtable Record": {
      "main": [
        [
          {
            "node": "Format Success Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Success Message": {
      "main": [
        [
          {
            "node": "Post to Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Transform for Airtable": {
      "main": [
        [
          {
            "node": "Create Airtable Record",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate Incoming Data": {
      "main": [
        [
          {
            "node": "Quality Check",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}