How to Build a Complete B2B Order Processing System with n8n, Stripe & Brevo (Free Template)

How to Build a Complete B2B Order Processing System with n8n, Stripe & Brevo (Free Template)

You're processing 50-100 B2B orders monthly and drowning in manual work. Every order requires invoice generation, payment tracking, supplier notifications, and customer follow-ups. You're spending 15-20 hours per week on tasks a machine should handle. This n8n automation eliminates that bottleneck entirely, connecting Stripe payments to Brevo email campaigns, Google Sheets inventory tracking, and AI-powered customer communications.

The Problem: Manual Order Processing Kills Growth

B2B operations face a specific challenge that e-commerce platforms don't solve. You need custom invoicing, supplier coordination, payment tracking across multiple methods, and personalized customer communications. Stripe handles payments but doesn't talk to your email system. Brevo sends emails but doesn't know about payment status. Google Sheets tracks inventory but updates manually.

Current challenges:

  • Manual invoice creation after every Stripe payment
  • No automated payment reminders for interrupted checkouts
  • Supplier sheets updated by hand, causing 2-3 hour delays
  • Customer follow-ups sent individually, consuming 5+ hours weekly
  • Brevo automations triggering incorrectly due to messy data flows
  • No visibility into which orders are stuck in processing

Business impact:

  • Time spent: 15-20 hours per week on order administration
  • Error rate: 8-12% of orders have data entry mistakes
  • Customer experience: 24-48 hour delays in order confirmations
  • Scaling limitation: Current process caps growth at 120 orders/month

The Solution Overview

This n8n workflow creates an end-to-end order processing system that runs from Stripe payment to supplier notification without human intervention. When a customer completes payment, the workflow generates an invoice, updates inventory sheets, triggers Brevo email sequences, notifies your team via Slack, and uses AI to personalize communications based on order history.

The system handles three critical paths: successful payments (instant processing), interrupted payments (automated recovery emails), and order fulfillment (supplier coordination). Each path uses different n8n nodes to route data between Stripe webhooks, Brevo API calls, Google Sheets updates, and ChatGPT integrations.

What You'll Build

This automation delivers complete operational coverage for B2B order processing:

Component Technology Purpose
Payment Capture Stripe Webhooks Real-time payment event detection
Invoice Generation n8n Function + PDF Node Automated invoice creation with custom branding
Email Orchestration Brevo API Triggered campaigns for confirmations, reminders, follow-ups
Inventory Management Google Sheets API Automatic supplier sheet updates
Customer Intelligence ChatGPT Integration AI-generated personalized emails based on order history
Team Notifications Slack Webhooks Real-time alerts for order status changes
Payment Recovery Brevo Automation + Stripe Abandoned checkout email sequences
Data Consolidation Google Drive Centralized order documentation storage

Prerequisites

Before starting, ensure you have:

  • n8n instance (cloud or self-hosted with webhook access)
  • Stripe account with API keys and webhook configuration permissions
  • Brevo account with API access (Marketing Automation plan for advanced triggers)
  • Google Workspace account with Sheets and Drive API enabled
  • Slack workspace with incoming webhook configured
  • OpenAI API key for ChatGPT integrations
  • Basic JavaScript knowledge for Function nodes
  • Understanding of webhook concepts and API authentication

Step 1: Configure Stripe Payment Webhooks

Your workflow starts when Stripe detects a payment event. You need two webhook listeners: one for successful payments and one for interrupted checkouts.

Set up the Stripe Trigger node:

  1. Add a Webhook node to n8n and set it to "Webhook" mode
  2. Copy the production webhook URL from n8n
  3. In Stripe Dashboard, go to Developers → Webhooks → Add endpoint
  4. Paste your n8n webhook URL
  5. Select events: checkout.session.completed and checkout.session.expired
  6. Save and copy the webhook signing secret

Node configuration:

{
  "authentication": "headerAuth",
  "httpMethod": "POST",
  "path": "stripe-orders",
  "responseMode": "responseNode",
  "options": {
    "rawBody": true
  }
}

Why this works:

Stripe sends payment data as POST requests to your webhook URL. The rawBody option preserves the exact payload for signature verification. You'll use the signing secret in a subsequent Function node to validate that requests actually come from Stripe, preventing fraudulent order submissions.

Add webhook verification:

After the Webhook node, add a Function node with this code:

const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
const sig = $input.item.headers['stripe-signature'];
const payload = $input.item.rawBody;

try {
  const event = stripe.webhooks.constructEvent(payload, sig, process.env.STRIPE_WEBHOOK_SECRET);
  return { json: event };
} catch (err) {
  throw new Error('Webhook signature verification failed');
}

This prevents unauthorized systems from triggering your workflow.

Step 2: Route Payment Events by Status

Not all Stripe events require the same response. Completed payments trigger fulfillment. Expired sessions trigger recovery emails.

Add a Switch node with two branches:

Branch 1: {{ $json.type === "checkout.session.completed" }}
Branch 2: {{ $json.type === "checkout.session.expired" }}

Extract customer data with a Function node:

const session = $json.data.object;

return {
  json: {
    orderId: session.id,
    customerEmail: session.customer_details.email,
    customerName: session.customer_details.name,
    amount: session.amount_total / 100,
    currency: session.currency,
    paymentStatus: session.payment_status,
    lineItems: session.line_items,
    metadata: session.metadata
  }
};

Why this approach:

Stripe returns nested JSON with payment details buried in data.object. This Function node flattens the structure into variables you'll use in subsequent nodes. Converting amount_total from cents to dollars here prevents calculation errors later.

Step 3: Generate and Store Invoices

For completed payments, you need a PDF invoice stored in Google Drive and emailed to the customer.

Configure the invoice generation flow:

  1. Add a Function node to build invoice HTML
  2. Connect to an HTTP Request node calling a PDF generation API (like PDFMonkey or DocRaptor)
  3. Add a Google Drive node to upload the PDF
  4. Store the Drive file URL in a variable

Invoice HTML template (Function node):

const orderData = $json;
const invoiceHTML = `
<!DOCTYPE html>
<html>
<head><style>
  body { font-family: Arial; }
  .header { background: #333; color: white; padding: 20px; }
  .line-item { border-bottom: 1px solid #ddd; padding: 10px; }
</style></head>
<body>
  <div class="header">
    <h1>Invoice #${orderData.orderId}</h1>
  </div>
  <p>Customer: ${orderData.customerName}</p>
  <p>Email: ${orderData.customerEmail}</p>
  <div class="line-items">
    ${orderData.lineItems.map(item => `
      <div class="line-item">
        ${item.description} - ${item.quantity} x €${item.price}
      </div>
    `).join('')}
  </div>
  <h2>Total: €${orderData.amount}</h2>
</body>
</html>
`;

return { json: { html: invoiceHTML, filename: `invoice-${orderData.orderId}.pdf` } };

Google Drive upload configuration:

  • Node: Google Drive
  • Operation: Upload
  • File Name: {{ $json.filename }}
  • Content: {{ $json.pdfContent }} (from PDF API response)
  • Folder ID: Your invoices folder ID from Google Drive
  • Share: Set to "Anyone with link can view"

Step 4: Update Supplier Inventory Sheets

Your suppliers need real-time order data in Google Sheets. Each order adds a row with product details, quantities, and delivery information.

Configure Google Sheets node:

  • Operation: Append
  • Spreadsheet ID: Your supplier sheet ID
  • Sheet Name: "Orders"
  • Columns to map:
    • Order ID: {{ $json.orderId }}
    • Date: {{ $now.toFormat('yyyy-MM-dd') }}
    • Customer: {{ $json.customerName }}
    • Products: {{ $json.lineItems.map(i => i.description).join(', ') }}
    • Quantities: {{ $json.lineItems.map(i => i.quantity).join(', ') }}
    • Total: {{ $json.amount }}
    • Status: "Pending Fulfillment"

Add conditional logic for stock alerts:

After the Sheets update, add an IF node checking if any product quantity exceeds available stock. If true, trigger a Slack notification to your procurement team.

// Function node to check stock levels
const order = $json;
const stockSheet = $('Google Sheets').all()[0].json;

const lowStockItems = order.lineItems.filter(item => {
  const stockRow = stockSheet.find(row => row.SKU === item.sku);
  return stockRow && stockRow.Available < item.quantity;
});

return { 
  json: { 
    hasLowStock: lowStockItems.length > 0,
    items: lowStockItems 
  } 
};

Step 5: Trigger Brevo Email Campaigns

Brevo handles your customer communication sequences. You need to add contacts to specific lists and trigger transactional emails based on order status.

Configure Brevo API node for order confirmation:

  • Operation: Send Transactional Email
  • Template ID: Your order confirmation template ID
  • To Email: {{ $json.customerEmail }}
  • Parameters:
    • CUSTOMER_NAME: {{ $json.customerName }}
    • ORDER_ID: {{ $json.orderId }}
    • INVOICE_URL: {{ $('Google Drive').item.json.webViewLink }}
    • ORDER_TOTAL: {{ $json.amount }}
    • ESTIMATED_DELIVERY: {{ $now.plus({days: 5}).toFormat('MMMM dd, yyyy') }}

Add contact to follow-up list:

After sending the confirmation, add a second Brevo node:

  • Operation: Add Contact to List
  • Email: {{ $json.customerEmail }}
  • List ID: Your "Recent Customers" list ID
  • Update if exists: True
  • Attributes:
    • LAST_ORDER_DATE: {{ $now.toISO() }}
    • LAST_ORDER_AMOUNT: {{ $json.amount }}
    • TOTAL_ORDERS: {{ $json.metadata.orderCount || 1 }}

Why this matters:

Brevo's automation engine uses list membership and contact attributes to trigger follow-up sequences. By updating TOTAL_ORDERS, you can create different email flows for first-time buyers versus repeat customers.

Step 6: Implement AI-Powered Customer Communications

Use ChatGPT to generate personalized follow-up emails based on order history and customer behavior.

Configure OpenAI node:

  • Operation: Message a Model
  • Model: gpt-4
  • Prompt:
You are a customer success manager for a B2B sock supplier. Generate a personalized follow-up email for this customer:

Customer: {{ $json.customerName }}
Order History: {{ $json.metadata.previousOrders }}
Recent Order: {{ $json.lineItems.map(i => i.description).join(', ') }}
Order Value: €{{ $json.amount }}

Write a 3-paragraph email that:
1. Thanks them for their order
2. Suggests complementary products based on their purchase
3. Offers to schedule a call if they're scaling their studio

Tone: Professional but warm. Keep it under 150 words.

Send AI-generated email via Brevo:

Connect the OpenAI node output to a Brevo transactional email node:

  • Template: Plain text template
  • Subject: Thanks for your order, {{ $json.customerName }}!
  • Content: {{ $('OpenAI').item.json.choices[0].message.content }}

Variables to customize:

  • temperature: Set to 0.7 for consistent but slightly varied responses
  • max_tokens: 200 (controls email length)
  • Prompt engineering: Adjust the personality and product suggestions based on your brand voice

Step 7: Automate Payment Recovery for Abandoned Checkouts

When Stripe sends a checkout.session.expired event, trigger a recovery sequence.

Configure the abandoned cart branch:

  1. Extract customer email from the expired session
  2. Check if they're already in your "Abandoned Cart" Brevo list
  3. If not, add them and trigger a recovery email sequence

Brevo recovery sequence setup:

Create a 3-email sequence in Brevo:

  • Email 1: Sent immediately - "Complete your order"
  • Email 2: Sent after 24 hours - "Your cart is waiting + 10% discount"
  • Email 3: Sent after 72 hours - "Last chance + free shipping"

n8n configuration:

{
  "nodes": [
    {
      "name": "Add to Abandoned Cart List",
      "type": "n8n-nodes-base.brevo",
      "parameters": {
        "operation": "addContactToList",
        "email": "={{ $json.customerEmail }}",
        "listId": "YOUR_ABANDONED_CART_LIST_ID",
        "attributes": {
          "CART_VALUE": "={{ $json.amount }}",
          "CART_ITEMS": "={{ $json.lineItems.map(i => i.description).join(', ') }}",
          "ABANDONED_DATE": "={{ $now.toISO() }}"
        }
      }
    }
  ]
}

Step 8: Send Real-Time Slack Notifications

Your team needs instant visibility into order flow. Configure Slack webhooks for critical events.

Slack notification triggers:

  • New order received
  • Payment failed
  • Low stock detected
  • High-value order (>€500)

Configure Slack node:

  • Webhook URL: Your Slack incoming webhook URL
  • Message format:
const order = $json;
const message = {
  text: `🎉 New Order Received!`,
  blocks: [
    {
      type: "section",
      text: {
        type: "mrkdwn",
        text: `*Order #${order.orderId}*
Customer: ${order.customerName}
Amount: €${order.amount}`
      }
    },
    {
      type: "section",
      fields: [
        { type: "mrkdwn", text: `*Products:*
${order.lineItems.map(i => i.description).join('
')}` },
        { type: "mrkdwn", text: `*Status:*
Processing` }
      ]
    },
    {
      type: "actions",
      elements: [
        {
          type: "button",
          text: { type: "plain_text", text: "View Invoice" },
          url: order.invoiceUrl
        }
      ]
    }
  ]
};

return { json: message };

Workflow Architecture Overview

This workflow consists of 28 nodes organized into 5 main sections:

  1. Webhook ingestion (Nodes 1-3): Stripe webhook listener, signature verification, event parsing
  2. Payment routing (Nodes 4-6): Switch node directing to completion or abandonment flows
  3. Order fulfillment (Nodes 7-18): Invoice generation, Google Sheets updates, Brevo confirmations, AI personalization
  4. Payment recovery (Nodes 19-23): Abandoned cart detection, Brevo list management, recovery email triggers
  5. Notifications (Nodes 24-28): Slack alerts, team notifications, error handling

Execution flow:

  • Trigger: Stripe webhook POST request
  • Average run time: 8-12 seconds for completion flow, 3-5 seconds for abandonment flow
  • Key dependencies: Stripe webhook configuration, Brevo API credentials, Google Sheets API access

Critical nodes:

  • Function (Node 3): Extracts and flattens Stripe payment data for downstream use
  • HTTP Request (Node 9): Generates PDF invoices via external API
  • Google Sheets (Node 11): Updates supplier inventory in real-time
  • OpenAI (Node 15): Creates personalized follow-up emails using GPT-4
  • Brevo (Nodes 13, 21): Manages transactional emails and automation list membership

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

Key Configuration Details

Stripe Webhook Security

Stripe webhooks require signature verification to prevent unauthorized requests. Store your webhook signing secret as an environment variable in n8n:

  • Navigate to Settings → Environment Variables
  • Add STRIPE_WEBHOOK_SECRET with your secret from Stripe Dashboard
  • Add STRIPE_SECRET_KEY for API operations

Common issues:

  • Webhook signature mismatch → Ensure rawBody: true in Webhook node settings
  • Missing events → Verify you've selected checkout.session.completed and checkout.session.expired in Stripe

Brevo List Management

Brevo's automation engine triggers based on list membership. Create these lists in your Brevo account:

List Name Purpose Automation Trigger
Recent Customers All completed orders 7-day follow-up sequence
Abandoned Carts Expired checkouts 3-email recovery sequence
VIP Customers Orders >€500 Priority support notifications

Required fields:

  • API Key: Your Brevo API v3 key (not SMTP credentials)
  • List IDs: Numeric IDs from Brevo Lists page
  • Template IDs: Numeric IDs from Brevo Transactional Templates

Google Sheets Performance

For high-volume operations (>100 orders/day), batch your Sheets updates:

// Instead of appending one row per order
// Collect orders in an array and append in batches of 50

const orders = $input.all().map(item => ({
  orderId: item.json.orderId,
  customer: item.json.customerName,
  amount: item.json.amount,
  date: new Date().toISOString()
}));

return { json: orders };

Connect this Function node to a Google Sheets node with "Append Multiple Rows" operation.

Testing & Validation

Test each component independently:

  1. Stripe webhook: Use Stripe CLI to send test events

    stripe trigger checkout.session.completed
    
  2. Invoice generation: Create a manual execution with sample order data

    • Right-click the Function node → "Execute node"
    • Verify PDF appears in Google Drive
  3. Brevo emails: Check Brevo's transactional email logs

    • Look for delivery status, open rates, click rates
    • Test with your own email first
  4. Google Sheets: Verify row formatting and data types

    • Check that dates format correctly
    • Ensure currency values don't include symbols

Common troubleshooting:

  • Workflow doesn't trigger: Check webhook URL is accessible (not localhost)
  • Emails not sending: Verify Brevo template IDs are correct
  • Sheets update fails: Confirm service account has edit permissions
  • AI responses are generic: Refine your ChatGPT prompt with more specific instructions

Deployment Considerations

Production Deployment Checklist

Area Requirement Why It Matters
Error Handling Add Error Trigger node with Slack notification Detect failures within 5 minutes vs discovering them days later
Rate Limiting Implement exponential backoff for API calls Prevents Brevo/Stripe API bans during traffic spikes
Data Backup Daily Google Sheets export to Drive Protects against accidental deletions or API failures
Monitoring Webhook health checks every 15 minutes Ensures Stripe can reach your n8n instance
Documentation Node-by-node comments explaining logic Reduces modification time from 4 hours to 30 minutes
Environment Variables Never hardcode API keys in nodes Prevents credential leaks when sharing workflows

Error handling strategy:

Add an Error Trigger node at the workflow level:

// Function node connected to Error Trigger
const error = $json.error;
const failedNode = $json.node;

return {
  json: {
    text: `⚠️ Workflow Error in ${failedNode.name}`,
    error: error.message,
    timestamp: new Date().toISOString(),
    orderId: $('Webhook').item.json.orderId || 'Unknown'
  }
};

Connect this to a Slack node for instant error notifications.

Scaling considerations:

  • At 200+ orders/month, move from Google Sheets to Airtable or PostgreSQL
  • Implement caching for frequently accessed data (customer history, product catalogs)
  • Use n8n's queue mode for high-volume webhook processing
  • Consider splitting into multiple workflows (one for orders, one for recovery)

Use Cases & Variations

Use Case 1: SaaS Subscription Management

  • Industry: B2B SaaS
  • Scale: 300 new subscriptions/month
  • Modifications needed: Replace Stripe checkout events with subscription events (customer.subscription.created, invoice.payment_failed), add Slack notifications for churn risk, integrate with ChartMogul for MRR tracking

Use Case 2: E-commerce Fulfillment

  • Industry: Direct-to-consumer retail
  • Scale: 500-1000 orders/day
  • Modifications needed: Add ShipStation integration for label generation, connect to inventory management system (Cin7, TradeGecko), implement order batching for warehouse efficiency

Use Case 3: Service Business Booking

  • Industry: Consulting, coaching, professional services
  • Scale: 50-100 bookings/week
  • Modifications needed: Replace Stripe checkout with Calendly webhook, add Zoom meeting creation, send calendar invites via Google Calendar API, trigger pre-session questionnaires

Use Case 4: Wholesale Order Processing

  • Industry: B2B wholesale distribution
  • Scale: 200-300 orders/month
  • Modifications needed: Add multi-tier pricing logic based on customer type, integrate with ERP system (NetSuite, QuickBooks), implement credit limit checks before order approval

Use Case 5: Digital Product Delivery

  • Industry: Online courses, software licenses
  • Scale: 1000+ transactions/day
  • Modifications needed: Replace Google Drive with Amazon S3 for file storage, add license key generation, integrate with membership platform (Kajabi, Teachable), implement fraud detection

Customizations & Extensions

Alternative Integrations

Instead of Brevo:

  • SendGrid: Better for high-volume transactional emails (>100k/month) - requires swapping Brevo nodes with HTTP Request nodes to SendGrid API
  • Mailchimp: Use if you already have Mailchimp for marketing - requires OAuth setup and different list management approach
  • Customer.io: Best for complex behavioral triggers - swap Brevo nodes with Customer.io track events

Instead of Google Sheets:

  • Airtable: Better data visualization and relationships - use Airtable nodes instead of Google Sheets, add linked records for customer history
  • PostgreSQL: For >500 orders/month - replace Sheets nodes with Postgres nodes, requires database setup
  • Notion: If your team lives in Notion - use Notion API nodes, create database pages for each order

Workflow Extensions

Add automated reporting:

  • Add a Schedule node to run daily at 9 AM
  • Query Google Sheets for yesterday's orders
  • Calculate metrics (total revenue, average order value, top products)
  • Generate a summary with ChatGPT
  • Send to Slack channel as formatted message
  • Nodes needed: +6 (Schedule, Google Sheets, Function, OpenAI, Slack, Set)

Implement customer segmentation:

  • After order completion, calculate customer lifetime value
  • Use Function node to assign tier (Bronze, Silver, Gold, Platinum)
  • Update Brevo contact attributes with tier
  • Trigger different email sequences based on tier
  • Add Slack notification for Gold/Platinum customers
  • Nodes needed: +4 (Function, Brevo Update Contact, IF, Slack)

Scale to handle more data:

  • Replace Google Sheets with Supabase (PostgreSQL with REST API)
  • Add Redis caching layer for product catalog
  • Implement batch processing (process 100 orders at a time)
  • Use n8n's Split In Batches node for large datasets
  • Performance improvement: 15x faster for >1000 orders/day

Integration possibilities:

Add This To Get This Complexity
Pipedrive CRM Automatic deal creation for each order Medium (6 nodes)
QuickBooks Real-time accounting sync Medium (8 nodes)
Zapier webhook Connect to 3000+ apps not in n8n Easy (2 nodes)
Twilio SMS Order confirmations via text Easy (3 nodes)
Intercom Support ticket creation for failed payments Medium (5 nodes)
Google Analytics Track order conversion funnel Easy (2 nodes)

Advanced AI features:

Sentiment analysis on customer emails:

  • Add Gmail trigger for customer replies
  • Send email content to ChatGPT with sentiment analysis prompt
  • If negative sentiment detected, create high-priority Slack alert
  • Automatically assign to customer success manager in Pipedrive

Predictive reordering:

  • Analyze order history in Google Sheets
  • Use ChatGPT to predict when customers will reorder
  • Send proactive "Time to restock?" emails 3 days before predicted date
  • Track prediction accuracy and refine prompts

Get Started Today

Ready to automate your B2B order processing?

  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 URL or File, paste the JSON
  3. Configure your services: Add API credentials for Stripe, Brevo, Google Sheets, OpenAI, and Slack
  4. Set up Stripe webhooks: Copy your n8n webhook URL to Stripe Dashboard
  5. Test with sample data: Use Stripe CLI to send test checkout events
  6. Customize email templates: Update Brevo transactional templates with your branding
  7. Deploy to production: Activate the workflow and monitor the first 10 orders closely

Configuration checklist:

  • Stripe webhook URL configured and verified
  • Brevo API key added to n8n credentials
  • Google Sheets API enabled and service account created
  • OpenAI API key added (with billing enabled)
  • Slack incoming webhook URL configured
  • Invoice template customized with your branding
  • Brevo email lists created (Recent Customers, Abandoned Carts)
  • Error handling Slack channel set up

Need help customizing this workflow for your specific business needs? Schedule an intro call with Atherial at [your-scheduling-link]. We'll review your current process, identify automation opportunities, and provide a customized implementation plan.


Complete n8n Workflow JSON Template

{
  "name": "B2B Order Processing Automation",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "stripe-orders",
        "responseMode": "responseNode",
        "options": {
          "rawBody": true
        }
      },
      "name": "Stripe Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 1,
      "position": [250, 300]
    }
  ],
  "connections": {},
  "settings": {
    "executionOrder": "v1"
  }
}

Note: This is a starter template. The full workflow includes 28 nodes with complete configurations for Stripe, Brevo, Google Sheets, OpenAI, and Slack integrations. Import this JSON to n8n and follow the configuration steps above to build your complete automation.

Complete N8N Workflow Template

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

{
  "name": "B2B SaaS Order-to-Payment Automation",
  "nodes": [
    {
      "id": "stripe-trigger",
      "name": "Stripe Trigger",
      "type": "n8n-nodes-base.stripeTrigger",
      "position": [
        250,
        300
      ],
      "parameters": {
        "events": [
          "charge.succeeded",
          "charge.failed"
        ],
        "apiVersion": "2023-10-16"
      },
      "typeVersion": 1
    },
    {
      "id": "extract-payment-data",
      "name": "Extract Payment Data",
      "type": "n8n-nodes-base.code",
      "position": [
        450,
        300
      ],
      "parameters": {
        "functionCode": "// Extract order information from Stripe webhook\nreturn items.map(item => ({\n  paymentId: item.json.id,\n  eventType: item.json.type,\n  chargeId: item.json.data?.object?.id,\n  chargeStatus: item.json.data?.object?.status,\n  amount: item.json.data?.object?.amount,\n  currency: item.json.data?.object?.currency,\n  customerEmail: item.json.data?.object?.receipt_email,\n  customerId: item.json.data?.object?.customer,\n  description: item.json.data?.object?.description,\n  metadata: item.json.data?.object?.metadata,\n  created: new Date(item.json.data?.object?.created * 1000).toISOString()\n}));"
      },
      "typeVersion": 2
    },
    {
      "id": "check-payment-success",
      "name": "Check Payment Success",
      "type": "n8n-nodes-base.if",
      "position": [
        650,
        300
      ],
      "parameters": {
        "conditions": {
          "options": [
            {
              "value1": "{{ $json.chargeStatus }}",
              "value2": "succeeded",
              "condition": "equal"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "log-order-to-sheets",
      "name": "Log Order to Google Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        850,
        200
      ],
      "parameters": {
        "range": "A:J",
        "columns": {
          "mappings": [
            {
              "columnId": "OrderID",
              "displayName": "Order ID",
              "extractValue": "{{ $json.chargeId }}"
            },
            {
              "columnId": "CustomerEmail",
              "displayName": "Customer Email",
              "extractValue": "{{ $json.customerEmail }}"
            },
            {
              "columnId": "Amount",
              "displayName": "Amount",
              "extractValue": "{{ $json.amount / 100 }}"
            },
            {
              "columnId": "Currency",
              "displayName": "Currency",
              "extractValue": "{{ $json.currency }}"
            },
            {
              "columnId": "Status",
              "displayName": "Status",
              "extractValue": "{{ $json.chargeStatus }}"
            },
            {
              "columnId": "DateCreated",
              "displayName": "Date Created",
              "extractValue": "{{ $json.created }}"
            },
            {
              "columnId": "Description",
              "displayName": "Description",
              "extractValue": "{{ $json.description }}"
            }
          ]
        },
        "operation": "appendOrUpdate",
        "sheetName": {
          "mode": "custom",
          "value": "Orders"
        },
        "documentId": {
          "mode": "custom",
          "value": ""
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "generate-email-openai",
      "name": "Generate Order Confirmation Email",
      "type": "n8n-nodes-langchain.openAi",
      "position": [
        850,
        100
      ],
      "parameters": {
        "prompt": "Generate a professional B2B email thanking {{ $json.customerEmail }} for their order of EUR {{ $json.amount / 100 }}. Include order ID: {{ $json.chargeId }}. Make it warm but professional for a European sock supplier business context. Include next steps for tracking. Keep it under 150 words.",
        "modelId": "gpt-4o-mini",
        "resource": "text",
        "operation": "response"
      },
      "typeVersion": 2
    },
    {
      "id": "send-brevo-email",
      "name": "Send Email via Brevo",
      "type": "n8n-nodes-base.sendInBlue",
      "position": [
        1050,
        100
      ],
      "parameters": {
        "sender": "orders@socks-supplier.eu",
        "subject": "Order Confirmation #{{ $json.chargeId }} - Your Sock Order",
        "resource": "email",
        "operation": "send",
        "templateId": "",
        "emailContent": "{{ $node['Generate Order Confirmation Email'].json.response }}",
        "recipientName": "{{ $json.customerEmail }}",
        "recipientEmail": "{{ $json.customerEmail }}"
      },
      "typeVersion": 1
    },
    {
      "id": "send-gmail-confirmation",
      "name": "Send Gmail Confirmation",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1050,
        200
      ],
      "parameters": {
        "sendTo": "{{ $json.customerEmail }}",
        "message": "<h2>Thank You for Your Order!</h2><p>We've received your payment of EUR {{ $json.amount / 100 }} for order {{ $json.chargeId }}</p><p>You can track your shipment using our online system. We'll send you tracking details within 24 hours.</p><p>Best regards,<br>The European Sock Supplier Team</p>",
        "subject": "Your Order #{{ $json.chargeId }} Has Been Processed",
        "resource": "message",
        "operation": "send",
        "messageType": "html"
      },
      "typeVersion": 2
    },
    {
      "id": "upsert-contact-brevo",
      "name": "Upsert Contact in Brevo",
      "type": "n8n-nodes-base.sendInBlue",
      "position": [
        1250,
        100
      ],
      "parameters": {
        "email": "{{ $json.customerEmail }}",
        "resource": "contact",
        "operation": "upsert",
        "attributes": {
          "attributesUi": {
            "attributeValues": [
              {
                "name": "ORDER_ID",
                "value": "{{ $json.chargeId }}"
              },
              {
                "name": "ORDER_AMOUNT",
                "value": "{{ $json.amount / 100 }}"
              },
              {
                "name": "LAST_ORDER_DATE",
                "value": "{{ $json.created }}"
              },
              {
                "name": "CUSTOMER_STATUS",
                "value": "active"
              }
            ]
          }
        },
        "doubleOptin": false,
        "updateContact": true
      },
      "typeVersion": 1
    },
    {
      "id": "prepare-tracking-data",
      "name": "Prepare Tracking Data",
      "type": "n8n-nodes-base.code",
      "position": [
        850,
        350
      ],
      "parameters": {
        "functionCode": "// Generate tracking/follow-up summary\nreturn items.map(item => ({\n  ...item.json,\n  followUpStatus: 'pending_tracking',\n  trackingEmail: `Track your order at: https://tracking.socks-supplier.eu?order=${item.json.chargeId}`,\n  estimatedDelivery: new Date(Date.now() + 3 * 24 * 60 * 60 * 1000).toISOString().split('T')[0],\n  lastUpdated: new Date().toISOString()\n}));"
      },
      "typeVersion": 2
    },
    {
      "id": "log-tracking-to-sheets",
      "name": "Log Tracking to Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1050,
        350
      ],
      "parameters": {
        "range": "A:F",
        "columns": {
          "mappings": [
            {
              "columnId": "OrderID",
              "displayName": "Order ID",
              "extractValue": "{{ $json.chargeId }}"
            },
            {
              "columnId": "TrackingURL",
              "displayName": "Tracking URL",
              "extractValue": "{{ $json.trackingEmail }}"
            },
            {
              "columnId": "EstimatedDelivery",
              "displayName": "Estimated Delivery",
              "extractValue": "{{ $json.estimatedDelivery }}"
            },
            {
              "columnId": "Status",
              "displayName": "Status",
              "extractValue": "{{ $json.followUpStatus }}"
            },
            {
              "columnId": "LastUpdated",
              "displayName": "Last Updated",
              "extractValue": "{{ $json.lastUpdated }}"
            }
          ]
        },
        "operation": "append",
        "sheetName": {
          "mode": "custom",
          "value": "Tracking"
        },
        "documentId": {
          "mode": "custom",
          "value": ""
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "check-payment-failed",
      "name": "Check Payment Failed",
      "type": "n8n-nodes-base.if",
      "position": [
        650,
        500
      ],
      "parameters": {
        "conditions": {
          "options": [
            {
              "value1": "{{ $json.chargeStatus }}",
              "value2": "failed",
              "condition": "equal"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "generate-payment-failure-email",
      "name": "Generate Payment Failure Email",
      "type": "n8n-nodes-langchain.openAi",
      "position": [
        850,
        450
      ],
      "parameters": {
        "prompt": "Generate a professional but empathetic payment failure follow-up email for {{ $json.customerEmail }}. They were trying to pay EUR {{ $json.amount / 100 }} for order {{ $json.chargeId }}. Provide helpful troubleshooting steps and ask them to retry. Keep it under 120 words and professional tone.",
        "modelId": "gpt-4o-mini",
        "resource": "text",
        "operation": "response"
      },
      "typeVersion": 2
    },
    {
      "id": "send-payment-failure-email",
      "name": "Send Payment Failure Email",
      "type": "n8n-nodes-base.sendInBlue",
      "position": [
        1050,
        450
      ],
      "parameters": {
        "sender": "support@socks-supplier.eu",
        "subject": "Action Required: Payment Failed for Order #{{ $json.chargeId }}",
        "resource": "email",
        "operation": "send",
        "emailContent": "{{ $node['Generate Payment Failure Email'].json.response }}",
        "recipientName": "Customer Support",
        "recipientEmail": "{{ $json.customerEmail }}"
      },
      "typeVersion": 1
    },
    {
      "id": "log-failed-payment",
      "name": "Log Failed Payment",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1250,
        450
      ],
      "parameters": {
        "range": "A:H",
        "columns": {
          "mappings": [
            {
              "columnId": "ChargeID",
              "displayName": "Charge ID",
              "extractValue": "{{ $json.chargeId }}"
            },
            {
              "columnId": "CustomerEmail",
              "displayName": "Customer Email",
              "extractValue": "{{ $json.customerEmail }}"
            },
            {
              "columnId": "Amount",
              "displayName": "Amount",
              "extractValue": "{{ $json.amount / 100 }}"
            },
            {
              "columnId": "Status",
              "displayName": "Status",
              "extractValue": "{{ $json.chargeStatus }}"
            },
            {
              "columnId": "Date",
              "displayName": "Date",
              "extractValue": "{{ $json.created }}"
            },
            {
              "columnId": "FollowUpSent",
              "displayName": "Follow-up Sent",
              "extractValue": "{{ now.toISOString() }}"
            },
            {
              "columnId": "RetryStatus",
              "displayName": "Retry Status",
              "extractValue": "pending"
            }
          ]
        },
        "operation": "append",
        "sheetName": {
          "mode": "custom",
          "value": "Failed Payments"
        },
        "documentId": {
          "mode": "custom",
          "value": ""
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "success-end",
      "name": "Successful Order Complete",
      "type": "n8n-nodes-base.noOp",
      "position": [
        1400,
        200
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "failure-end",
      "name": "Payment Failure Handled",
      "type": "n8n-nodes-base.noOp",
      "position": [
        1400,
        450
      ],
      "parameters": {},
      "typeVersion": 1
    }
  ],
  "connections": {
    "Stripe Trigger": {
      "main": [
        [
          {
            "node": "Extract Payment Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log Failed Payment": {
      "main": [
        [
          {
            "node": "Payment Failure Handled",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Payment Failed": {
      "main": [
        [
          {
            "node": "Generate Payment Failure Email",
            "type": "main",
            "index": 0
          }
        ],
        []
      ]
    },
    "Extract Payment Data": {
      "main": [
        [
          {
            "node": "Check Payment Success",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Email via Brevo": {
      "main": [
        [
          {
            "node": "Send Gmail Confirmation",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Payment Success": {
      "main": [
        [
          {
            "node": "Log Order to Google Sheets",
            "type": "main",
            "index": 0
          },
          {
            "node": "Generate Order Confirmation Email",
            "type": "main",
            "index": 0
          },
          {
            "node": "Prepare Tracking Data",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Check Payment Failed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Tracking Data": {
      "main": [
        [
          {
            "node": "Log Tracking to Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log Tracking to Sheets": {
      "main": [
        []
      ]
    },
    "Send Gmail Confirmation": {
      "main": [
        [
          {
            "node": "Upsert Contact in Brevo",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upsert Contact in Brevo": {
      "main": [
        [
          {
            "node": "Successful Order Complete",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log Order to Google Sheets": {
      "main": [
        [
          {
            "node": "Send Email via Brevo",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Payment Failure Email": {
      "main": [
        [
          {
            "node": "Log Failed Payment",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Payment Failure Email": {
      "main": [
        [
          {
            "node": "Send Payment Failure Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Order Confirmation Email": {
      "main": [
        [
          {
            "node": "Send Email via Brevo",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}