Free n8n workflow templates

10 free n8n workflow templates with full JSON examples.

Copy practical, ready-to-import n8n JSON examples for popular automations: Stripe onboarding, AI form summaries, RSS publishing, Calendly handoffs, Shopify fulfillment, finance approvals, and more.

Full workflow JSONPlain-English stepsn8n import shape

New one-time launch offer

Automation Starter Pack: 10 JSON templates + AI prompt cheat-sheet

Get the ready-to-import files bundled with a 1-page prompt guide. One-time purchase, no subscription.

$9 — Get the Starter Pack

Copy-paste library

Free n8n JSON examples for common automations

Each workflow uses n8n's importable workflow shape and keeps secrets as placeholders so you can safely adapt it.

#01Revenue ops

New Stripe customer → Google Sheet + welcome email

Problem

Paid customers should land in one shared tracker and get a fast welcome email, but Stripe events often sit disconnected from onboarding.

Workflow steps

  1. 1Receive the Stripe customer.created or checkout.session.completed event in an n8n Webhook.
  2. 2Normalize customer email, name, company, Stripe customer ID, plan, and event time.
  3. 3Stop the happy path if Stripe did not send an email address.
  4. 4Append the customer record to a Google Sheet called Stripe Customers.
  5. 5Send a Gmail welcome email and post a Slack note for the team.

Setup notes

  • Paste the production webhook URL into Stripe after importing the workflow.
  • Replace REPLACE_WITH_GOOGLE_SHEET_ID with your sheet ID.
  • Connect Google Sheets, Gmail, and Slack credentials in n8n.
Want a custom version? Generate any workflow from plain English with FlowForge AI.

Full importable n8n JSON

Copy everything in this block into n8n.

stripe-customer-google-sheets-welcome-email.json
n8n workflow
{
  "name": "Stripe Customer to Google Sheets and Welcome Email",
  "nodes": [
    {
      "parameters": {
        "path": "stripe-customer-created",
        "httpMethod": "POST",
        "responseMode": "onReceived",
        "responseData": "firstEntryJson"
      },
      "id": "stripe-customer-webhook",
      "name": "Stripe Customer Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        0,
        0
      ]
    },
    {
      "parameters": {
        "keepOnlySet": true,
        "values": {
          "string": [
            {
              "name": "email",
              "value": "={{$json.data?.object?.email || $json.email}}"
            },
            {
              "name": "name",
              "value": "={{$json.data?.object?.name || $json.name || 'New customer'}}"
            },
            {
              "name": "company",
              "value": "={{$json.data?.object?.metadata?.company || ''}}"
            },
            {
              "name": "stripeCustomerId",
              "value": "={{$json.data?.object?.customer || $json.data?.object?.id}}"
            },
            {
              "name": "plan",
              "value": "={{$json.data?.object?.metadata?.plan || 'unknown'}}"
            },
            {
              "name": "createdAt",
              "value": "={{$now.toISO()}}"
            }
          ]
        }
      },
      "id": "normalize-stripe-customer",
      "name": "Normalize Stripe Customer",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3,
      "position": [
        280,
        0
      ]
    },
    {
      "parameters": {
        "conditions": {
          "string": [
            {
              "value1": "={{$json.email}}",
              "operation": "isNotEmpty"
            }
          ]
        }
      },
      "id": "validate-customer-email",
      "name": "Validate Customer Email",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        560,
        0
      ]
    },
    {
      "parameters": {
        "operation": "append",
        "documentId": "REPLACE_WITH_GOOGLE_SHEET_ID",
        "sheetName": "Stripe Customers",
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "email": "={{$json.email}}",
            "name": "={{$json.name}}",
            "company": "={{$json.company}}",
            "stripeCustomerId": "={{$json.stripeCustomerId}}",
            "plan": "={{$json.plan}}",
            "createdAt": "={{$json.createdAt}}"
          }
        }
      },
      "id": "append-customer-to-google-sheets",
      "name": "Append Customer to Google Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4,
      "position": [
        840,
        -120
      ]
    },
    {
      "parameters": {
        "sendTo": "={{$json.email}}",
        "subject": "Welcome to {{$json.plan || 'our product'}}",
        "message": "Hi {{$json.name}},\n\nThanks for becoming a customer. We received your payment and will send onboarding details shortly.\n\nBest,\nThe team"
      },
      "id": "send-welcome-email",
      "name": "Send Welcome Email",
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2,
      "position": [
        1120,
        -120
      ]
    },
    {
      "parameters": {
        "channel": "#new-customers",
        "text": "New Stripe customer: {{$json.email}} on {{$json.plan}}."
      },
      "id": "notify-new-customer-in-slack",
      "name": "Notify New Customer in Slack",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2,
      "position": [
        1400,
        -120
      ]
    }
  ],
  "connections": {
    "Stripe Customer Webhook": {
      "main": [
        [
          {
            "node": "Normalize Stripe Customer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize Stripe Customer": {
      "main": [
        [
          {
            "node": "Validate Customer Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate Customer Email": {
      "main": [
        [
          {
            "node": "Append Customer to Google Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Append Customer to Google Sheets": {
      "main": [
        [
          {
            "node": "Send Welcome Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Welcome Email": {
      "main": [
        [
          {
            "node": "Notify New Customer in Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "flowforge-template-stripe-customer-v1",
  "meta": {
    "generatedBy": "FlowForge AI templates",
    "sourceGoal": "New Stripe customer to Google Sheets and welcome email"
  }
}
#02Lead intake

Form submission → AI summary → Slack

Problem

Long form submissions are hard to triage in Slack, so sales or support teams miss the actual ask until someone reads every field manually.

Workflow steps

  1. 1Receive a Typeform, Webflow, Tally, or custom form payload with an n8n Webhook.
  2. 2Normalize sender name, email, company, request type, and free-text message.
  3. 3Send the message to an AI endpoint to produce a short summary and urgency label.
  4. 4Post the enriched summary to Slack with the contact fields.
  5. 5Return a lightweight success response to the form tool.

Setup notes

  • Point your form tool to the webhook test URL first, then activate the production URL.
  • Add your AI provider URL and API key to the HTTP Request node.
  • Connect Slack credentials and update the destination channel.
Want a custom version? Generate any workflow from plain English with FlowForge AI.

Full importable n8n JSON

Copy everything in this block into n8n.

form-ai-summary-slack.json
n8n workflow
{
  "name": "Form Submission to AI Summary and Slack",
  "nodes": [
    {
      "parameters": {
        "path": "form-ai-summary",
        "httpMethod": "POST",
        "responseMode": "onReceived",
        "responseData": "firstEntryJson"
      },
      "id": "form-submission-webhook",
      "name": "Form Submission Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        0,
        0
      ]
    },
    {
      "parameters": {
        "keepOnlySet": true,
        "values": {
          "string": [
            {
              "name": "name",
              "value": "={{$json.name || $json.firstName || 'Anonymous'}}"
            },
            {
              "name": "email",
              "value": "={{$json.email || ''}}"
            },
            {
              "name": "company",
              "value": "={{$json.company || ''}}"
            },
            {
              "name": "requestType",
              "value": "={{$json.requestType || $json.type || 'General'}}"
            },
            {
              "name": "message",
              "value": "={{$json.message || $json.notes || $json.description || ''}}"
            }
          ]
        }
      },
      "id": "normalize-form-submission",
      "name": "Normalize Form Submission",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3,
      "position": [
        280,
        0
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.openai.com/v1/chat/completions",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer REPLACE_WITH_OPENAI_API_KEY"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "model",
              "value": "gpt-4o-mini"
            },
            {
              "name": "messages",
              "value": "=[{role:'system',content:'Summarize this form submission in one sentence and assign urgency low, medium, or high.'},{role:'user',content:$json.message}]"
            }
          ]
        }
      },
      "id": "summarize-with-ai",
      "name": "Summarize with AI",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        560,
        0
      ]
    },
    {
      "parameters": {
        "channel": "#new-leads",
        "text": "New {{$json.requestType}} form from {{$json.name}} <{{$json.email}}> at {{$json.company}}. Summary: {{$json.choices?.[0]?.message?.content || $json.message}}"
      },
      "id": "post-ai-summary-to-slack",
      "name": "Post AI Summary to Slack",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2,
      "position": [
        840,
        0
      ]
    }
  ],
  "connections": {
    "Form Submission Webhook": {
      "main": [
        [
          {
            "node": "Normalize Form Submission",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize Form Submission": {
      "main": [
        [
          {
            "node": "Summarize with AI",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Summarize with AI": {
      "main": [
        [
          {
            "node": "Post AI Summary to Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "flowforge-template-form-ai-slack-v1",
  "meta": {
    "generatedBy": "FlowForge AI templates",
    "sourceGoal": "Form submission to AI summary and Slack"
  }
}
#03Content ops

RSS feed → auto-post to Twitter/X

Problem

Blog posts and changelog entries get published, but social updates lag because someone has to remember to write and post them manually.

Workflow steps

  1. 1Run on a schedule every hour.
  2. 2Read the latest items from an RSS feed.
  3. 3Trim each item into a concise social post with title and link.
  4. 4Skip empty titles or links before posting.
  5. 5Send the final post text to the X API through an HTTP Request node.

Setup notes

  • Replace the RSS URL with your blog, changelog, or podcast feed.
  • Add a dedupe store if you want to prevent reposting old feed items.
  • Replace the X API placeholder bearer token before activating.
Want a custom version? Generate any workflow from plain English with FlowForge AI.

Full importable n8n JSON

Copy everything in this block into n8n.

rss-auto-post-twitter-x.json
n8n workflow
{
  "name": "RSS Feed to Twitter X Auto Post",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours",
              "hoursInterval": 1
            }
          ]
        }
      },
      "id": "hourly-schedule",
      "name": "Hourly Schedule",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        0,
        0
      ]
    },
    {
      "parameters": {
        "url": "https://example.com/feed.xml"
      },
      "id": "read-rss-feed",
      "name": "Read RSS Feed",
      "type": "n8n-nodes-base.rssFeedRead",
      "typeVersion": 1,
      "position": [
        280,
        0
      ]
    },
    {
      "parameters": {
        "jsCode": "return items.map((item) => ({ json: { title: item.json.title, link: item.json.link, postText: `${item.json.title} ${item.json.link}`.slice(0, 275) } }));"
      },
      "id": "format-social-post",
      "name": "Format Social Post",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        560,
        0
      ]
    },
    {
      "parameters": {
        "conditions": {
          "string": [
            {
              "value1": "={{$json.link}}",
              "operation": "isNotEmpty"
            }
          ]
        }
      },
      "id": "validate-post-link",
      "name": "Validate Post Link",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        840,
        0
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.twitter.com/2/tweets",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer REPLACE_WITH_X_BEARER_TOKEN"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "text",
              "value": "={{$json.postText}}"
            }
          ]
        }
      },
      "id": "publish-to-x",
      "name": "Publish to X",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1120,
        -120
      ]
    }
  ],
  "connections": {
    "Hourly Schedule": {
      "main": [
        [
          {
            "node": "Read RSS Feed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read RSS Feed": {
      "main": [
        [
          {
            "node": "Format Social Post",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Social Post": {
      "main": [
        [
          {
            "node": "Validate Post Link",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate Post Link": {
      "main": [
        [
          {
            "node": "Publish to X",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "flowforge-template-rss-x-v1",
  "meta": {
    "generatedBy": "FlowForge AI templates",
    "sourceGoal": "RSS feed to Twitter X auto post"
  }
}
#04Sales handoff

Calendly booking → Notion prep task + Slack alert

Problem

Booked calls need context fast; without an automatic prep task, reps scramble for attendee details minutes before the meeting.

Workflow steps

  1. 1Receive a Calendly invitee.created webhook in n8n.
  2. 2Normalize attendee name, email, company, event type, and meeting time.
  3. 3Create a Notion database page for call prep.
  4. 4Post the booking details to a Slack sales channel.
  5. 5Let the team enrich the Notion page before the call.

Setup notes

  • Register the n8n webhook URL in Calendly webhook subscriptions.
  • Replace REPLACE_WITH_NOTION_DATABASE_ID with your call-prep database ID.
  • Connect Notion and Slack credentials in n8n.
Want a custom version? Generate any workflow from plain English with FlowForge AI.

Full importable n8n JSON

Copy everything in this block into n8n.

calendly-booking-notion-slack.json
n8n workflow
{
  "name": "Calendly Booking to Notion Prep and Slack",
  "nodes": [
    {
      "parameters": {
        "path": "calendly-booking",
        "httpMethod": "POST",
        "responseMode": "onReceived",
        "responseData": "firstEntryJson"
      },
      "id": "calendly-webhook",
      "name": "Calendly Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        0,
        0
      ]
    },
    {
      "parameters": {
        "keepOnlySet": true,
        "values": {
          "string": [
            {
              "name": "name",
              "value": "={{$json.payload?.name || $json.name}}"
            },
            {
              "name": "email",
              "value": "={{$json.payload?.email || $json.email}}"
            },
            {
              "name": "eventType",
              "value": "={{$json.payload?.event_type?.name || 'Booked call'}}"
            },
            {
              "name": "startTime",
              "value": "={{$json.payload?.scheduled_event?.start_time || $json.start_time}}"
            },
            {
              "name": "company",
              "value": "={{$json.payload?.questions_and_answers?.[0]?.answer || ''}}"
            }
          ]
        }
      },
      "id": "normalize-booking",
      "name": "Normalize Booking",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3,
      "position": [
        280,
        0
      ]
    },
    {
      "parameters": {
        "resource": "databasePage",
        "operation": "create",
        "databaseId": "REPLACE_WITH_NOTION_DATABASE_ID",
        "title": "={{$json.name}} — {{$json.eventType}}",
        "propertiesUi": {
          "propertyValues": [
            {
              "key": "Email",
              "textValue": "={{$json.email}}"
            },
            {
              "key": "Company",
              "textValue": "={{$json.company}}"
            },
            {
              "key": "Meeting Time",
              "textValue": "={{$json.startTime}}"
            }
          ]
        }
      },
      "id": "create-notion-prep-page",
      "name": "Create Notion Prep Page",
      "type": "n8n-nodes-base.notion",
      "typeVersion": 2,
      "position": [
        560,
        -120
      ]
    },
    {
      "parameters": {
        "channel": "#sales",
        "text": "New Calendly booking: {{$json.name}} <{{$json.email}}> for {{$json.eventType}} at {{$json.startTime}}. Prep page created in Notion."
      },
      "id": "notify-sales-in-slack",
      "name": "Notify Sales in Slack",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2,
      "position": [
        840,
        -120
      ]
    }
  ],
  "connections": {
    "Calendly Webhook": {
      "main": [
        [
          {
            "node": "Normalize Booking",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize Booking": {
      "main": [
        [
          {
            "node": "Create Notion Prep Page",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Notion Prep Page": {
      "main": [
        [
          {
            "node": "Notify Sales in Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "flowforge-template-calendly-notion-v1",
  "meta": {
    "generatedBy": "FlowForge AI templates",
    "sourceGoal": "Calendly booking to Notion prep and Slack"
  }
}
#05Ecommerce ops

Shopify order → Airtable fulfillment row + SMS

Problem

Small stores often track fulfillment in Airtable or spreadsheets, but new paid orders still require manual copying and status texts.

Workflow steps

  1. 1Receive a Shopify orders/create webhook.
  2. 2Normalize order number, customer, total, fulfillment status, and phone number.
  3. 3Create an Airtable row through the Airtable REST API.
  4. 4Send the customer an SMS confirmation through Twilio.
  5. 5Keep the fulfillment team’s Airtable queue up to date.

Setup notes

  • Register the webhook URL in Shopify for order creation events.
  • Replace Airtable base/table IDs and API token placeholders.
  • Replace Twilio placeholders before sending real SMS messages.
Want a custom version? Generate any workflow from plain English with FlowForge AI.

Full importable n8n JSON

Copy everything in this block into n8n.

shopify-order-airtable-fulfillment-sms.json
n8n workflow
{
  "name": "Shopify Order to Airtable Fulfillment and SMS",
  "nodes": [
    {
      "parameters": {
        "path": "shopify-order-created",
        "httpMethod": "POST",
        "responseMode": "onReceived",
        "responseData": "firstEntryJson"
      },
      "id": "shopify-order-webhook",
      "name": "Shopify Order Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        0,
        0
      ]
    },
    {
      "parameters": {
        "keepOnlySet": true,
        "values": {
          "string": [
            {
              "name": "orderNumber",
              "value": "={{$json.order_number || $json.name}}"
            },
            {
              "name": "customerEmail",
              "value": "={{$json.email || $json.customer?.email}}"
            },
            {
              "name": "customerPhone",
              "value": "={{$json.phone || $json.customer?.phone}}"
            },
            {
              "name": "total",
              "value": "={{$json.total_price}}"
            },
            {
              "name": "fulfillmentStatus",
              "value": "={{$json.fulfillment_status || 'unfulfilled'}}"
            }
          ]
        }
      },
      "id": "normalize-shopify-order",
      "name": "Normalize Shopify Order",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3,
      "position": [
        280,
        0
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.airtable.com/v0/REPLACE_WITH_BASE_ID/Fulfillment",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer REPLACE_WITH_AIRTABLE_TOKEN"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "fields",
              "value": "={{ { Order: $json.orderNumber, Email: $json.customerEmail, Total: $json.total, Status: $json.fulfillmentStatus } }}"
            }
          ]
        }
      },
      "id": "create-airtable-row",
      "name": "Create Airtable Row",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        560,
        -120
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.twilio.com/2010-04-01/Accounts/REPLACE_WITH_ACCOUNT_SID/Messages.json",
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "To",
              "value": "={{$json.customerPhone}}"
            },
            {
              "name": "From",
              "value": "+15555555555"
            },
            {
              "name": "Body",
              "value": "Your order {{$json.orderNumber}} was received. We'll text again when it ships."
            }
          ]
        }
      },
      "id": "send-order-sms",
      "name": "Send Order SMS",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        840,
        -120
      ]
    }
  ],
  "connections": {
    "Shopify Order Webhook": {
      "main": [
        [
          {
            "node": "Normalize Shopify Order",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize Shopify Order": {
      "main": [
        [
          {
            "node": "Create Airtable Row",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Airtable Row": {
      "main": [
        [
          {
            "node": "Send Order SMS",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "flowforge-template-shopify-airtable-v1",
  "meta": {
    "generatedBy": "FlowForge AI templates",
    "sourceGoal": "Shopify order to Airtable fulfillment and SMS"
  }
}
#06Finance ops

Invoice email → Google Drive archive + Slack approval

Problem

Vendor invoices arrive by email, then disappear into inboxes until finance manually saves attachments and asks for approval.

Workflow steps

  1. 1Receive an inbound invoice email payload through an email parser webhook.
  2. 2Normalize sender, subject, invoice amount, due date, and attachment URL.
  3. 3Validate that an attachment URL exists.
  4. 4Create a Google Drive archive handoff through HTTP.
  5. 5Ask the finance channel in Slack to approve or reject the invoice.

Setup notes

  • Use Mailparser, Postmark inbound, or another email parser to call the webhook.
  • Replace the Drive upload endpoint or switch the HTTP Request node to a Google Drive node.
  • Update the Slack channel and approval text for your finance process.
Want a custom version? Generate any workflow from plain English with FlowForge AI.

Full importable n8n JSON

Copy everything in this block into n8n.

invoice-email-drive-slack.json
n8n workflow
{
  "name": "Invoice Email to Drive Archive and Slack Approval",
  "nodes": [
    {
      "parameters": {
        "path": "invoice-email",
        "httpMethod": "POST",
        "responseMode": "onReceived",
        "responseData": "firstEntryJson"
      },
      "id": "invoice-email-webhook",
      "name": "Invoice Email Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        0,
        0
      ]
    },
    {
      "parameters": {
        "keepOnlySet": true,
        "values": {
          "string": [
            {
              "name": "vendor",
              "value": "={{$json.from || $json.vendor || 'Unknown vendor'}}"
            },
            {
              "name": "subject",
              "value": "={{$json.subject || 'Invoice received'}}"
            },
            {
              "name": "amount",
              "value": "={{$json.amount || $json.invoiceAmount || ''}}"
            },
            {
              "name": "dueDate",
              "value": "={{$json.dueDate || ''}}"
            },
            {
              "name": "attachmentUrl",
              "value": "={{$json.attachmentUrl || $json.attachments?.[0]?.url || ''}}"
            }
          ]
        }
      },
      "id": "normalize-invoice-email",
      "name": "Normalize Invoice Email",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3,
      "position": [
        280,
        0
      ]
    },
    {
      "parameters": {
        "conditions": {
          "string": [
            {
              "value1": "={{$json.attachmentUrl}}",
              "operation": "isNotEmpty"
            }
          ]
        }
      },
      "id": "validate-invoice-attachment",
      "name": "Validate Invoice Attachment",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        560,
        0
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer REPLACE_WITH_GOOGLE_ACCESS_TOKEN"
            }
          ]
        },
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "name",
              "value": "={{$json.vendor}} - {{$json.subject}}"
            },
            {
              "name": "sourceUrl",
              "value": "={{$json.attachmentUrl}}"
            }
          ]
        }
      },
      "id": "archive-in-google-drive",
      "name": "Archive in Google Drive",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        840,
        -120
      ]
    },
    {
      "parameters": {
        "channel": "#finance",
        "text": "Invoice approval needed: {{$json.vendor}} {{$json.amount}} due {{$json.dueDate}}. Attachment: {{$json.attachmentUrl}}"
      },
      "id": "request-slack-approval",
      "name": "Request Slack Approval",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2,
      "position": [
        1120,
        -120
      ]
    }
  ],
  "connections": {
    "Invoice Email Webhook": {
      "main": [
        [
          {
            "node": "Normalize Invoice Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize Invoice Email": {
      "main": [
        [
          {
            "node": "Validate Invoice Attachment",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate Invoice Attachment": {
      "main": [
        [
          {
            "node": "Archive in Google Drive",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Archive in Google Drive": {
      "main": [
        [
          {
            "node": "Request Slack Approval",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "flowforge-template-invoice-approval-v1",
  "meta": {
    "generatedBy": "FlowForge AI templates",
    "sourceGoal": "Invoice email to Google Drive archive and Slack approval"
  }
}
#07Product ops

GitHub issue → Linear task + Slack triage

Problem

Bug reports land in GitHub, but product and support teams need a triage-ready task plus a quick Slack heads-up.

Workflow steps

  1. 1Receive a GitHub issues webhook when an issue opens.
  2. 2Normalize issue title, URL, author, labels, and body.
  3. 3Create a Linear issue through the Linear GraphQL API.
  4. 4Post the triage summary in Slack.
  5. 5Let the team decide owner and priority inside Linear.

Setup notes

  • Add the n8n webhook URL to your GitHub repository webhooks for Issues events.
  • Replace Linear API token, team ID, and Slack channel placeholders.
  • Optionally add a label filter before creating Linear issues.
Want a custom version? Generate any workflow from plain English with FlowForge AI.

Full importable n8n JSON

Copy everything in this block into n8n.

github-issue-linear-slack.json
n8n workflow
{
  "name": "GitHub Issue to Linear and Slack Triage",
  "nodes": [
    {
      "parameters": {
        "path": "github-issue-opened",
        "httpMethod": "POST",
        "responseMode": "onReceived",
        "responseData": "firstEntryJson"
      },
      "id": "github-issue-webhook",
      "name": "GitHub Issue Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        0,
        0
      ]
    },
    {
      "parameters": {
        "keepOnlySet": true,
        "values": {
          "string": [
            {
              "name": "title",
              "value": "={{$json.issue?.title}}"
            },
            {
              "name": "url",
              "value": "={{$json.issue?.html_url}}"
            },
            {
              "name": "author",
              "value": "={{$json.issue?.user?.login}}"
            },
            {
              "name": "labels",
              "value": "={{($json.issue?.labels || []).map(label => label.name).join(', ')}}"
            },
            {
              "name": "body",
              "value": "={{$json.issue?.body || ''}}"
            }
          ]
        }
      },
      "id": "normalize-github-issue",
      "name": "Normalize GitHub Issue",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3,
      "position": [
        280,
        0
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.linear.app/graphql",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer REPLACE_WITH_LINEAR_API_KEY"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "query",
              "value": "mutation IssueCreate($input: IssueCreateInput!) { issueCreate(input: $input) { success issue { id url } } }"
            },
            {
              "name": "variables",
              "value": "={{ { input: { teamId: 'REPLACE_WITH_LINEAR_TEAM_ID', title: $json.title, description: `${$json.body}\\n\\nGitHub: ${$json.url}` } } }}"
            }
          ]
        }
      },
      "id": "create-linear-task",
      "name": "Create Linear Task",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        560,
        -120
      ]
    },
    {
      "parameters": {
        "channel": "#product-triage",
        "text": "New GitHub issue from {{$json.author}}: {{$json.title}} ({{$json.labels}}) {{$json.url}}"
      },
      "id": "post-triage-to-slack",
      "name": "Post Triage to Slack",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2,
      "position": [
        840,
        -120
      ]
    }
  ],
  "connections": {
    "GitHub Issue Webhook": {
      "main": [
        [
          {
            "node": "Normalize GitHub Issue",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize GitHub Issue": {
      "main": [
        [
          {
            "node": "Create Linear Task",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Linear Task": {
      "main": [
        [
          {
            "node": "Post Triage to Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "flowforge-template-github-linear-v1",
  "meta": {
    "generatedBy": "FlowForge AI templates",
    "sourceGoal": "GitHub issue to Linear task and Slack triage"
  }
}
#08Retention

Failed payment → CRM update + follow-up email

Problem

Payment failures quietly become churn unless finance, CRM, and customer messaging all update immediately.

Workflow steps

  1. 1Receive a payment_failed webhook from Stripe or your billing tool.
  2. 2Normalize customer email, plan, amount, failure reason, and invoice URL.
  3. 3Validate that the customer email is present.
  4. 4Update the CRM contact with failed-payment status through an HTTP API call.
  5. 5Send a friendly Gmail follow-up with a billing link.

Setup notes

  • Wire Stripe invoice.payment_failed or checkout failure events to the webhook.
  • Replace CRM endpoint/token placeholders or swap in your CRM node.
  • Edit the Gmail copy so it matches your billing tone.
Want a custom version? Generate any workflow from plain English with FlowForge AI.

Full importable n8n JSON

Copy everything in this block into n8n.

failed-payment-crm-followup-email.json
n8n workflow
{
  "name": "Failed Payment to CRM Update and Follow Up Email",
  "nodes": [
    {
      "parameters": {
        "path": "payment-failed",
        "httpMethod": "POST",
        "responseMode": "onReceived",
        "responseData": "firstEntryJson"
      },
      "id": "failed-payment-webhook",
      "name": "Failed Payment Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        0,
        0
      ]
    },
    {
      "parameters": {
        "keepOnlySet": true,
        "values": {
          "string": [
            {
              "name": "email",
              "value": "={{$json.data?.object?.customer_email || $json.email}}"
            },
            {
              "name": "plan",
              "value": "={{$json.data?.object?.metadata?.plan || 'subscription'}}"
            },
            {
              "name": "amount",
              "value": "={{$json.data?.object?.amount_due || $json.amount}}"
            },
            {
              "name": "reason",
              "value": "={{$json.data?.object?.last_payment_error?.message || 'Payment failed'}}"
            },
            {
              "name": "invoiceUrl",
              "value": "={{$json.data?.object?.hosted_invoice_url || $json.invoiceUrl}}"
            }
          ]
        }
      },
      "id": "normalize-payment-failure",
      "name": "Normalize Payment Failure",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3,
      "position": [
        280,
        0
      ]
    },
    {
      "parameters": {
        "conditions": {
          "string": [
            {
              "value1": "={{$json.email}}",
              "operation": "isNotEmpty"
            }
          ]
        }
      },
      "id": "validate-billing-email",
      "name": "Validate Billing Email",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        560,
        0
      ]
    },
    {
      "parameters": {
        "method": "PATCH",
        "url": "https://api.example-crm.com/contacts/by-email/{{$json.email}}",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer REPLACE_WITH_CRM_TOKEN"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "payment_status",
              "value": "failed"
            },
            {
              "name": "failure_reason",
              "value": "={{$json.reason}}"
            }
          ]
        }
      },
      "id": "update-crm-payment-status",
      "name": "Update CRM Payment Status",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        840,
        -120
      ]
    },
    {
      "parameters": {
        "sendTo": "={{$json.email}}",
        "subject": "Quick billing update for your {{$json.plan}} plan",
        "message": "Hi,\n\nWe could not process your latest payment. You can update billing here: {{$json.invoiceUrl}}\n\nIf you already fixed this, no action is needed.\n\nBest,\nBilling team"
      },
      "id": "send-payment-followup-email",
      "name": "Send Payment Follow-up Email",
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2,
      "position": [
        1120,
        -120
      ]
    }
  ],
  "connections": {
    "Failed Payment Webhook": {
      "main": [
        [
          {
            "node": "Normalize Payment Failure",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize Payment Failure": {
      "main": [
        [
          {
            "node": "Validate Billing Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate Billing Email": {
      "main": [
        [
          {
            "node": "Update CRM Payment Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update CRM Payment Status": {
      "main": [
        [
          {
            "node": "Send Payment Follow-up Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "flowforge-template-failed-payment-v1",
  "meta": {
    "generatedBy": "FlowForge AI templates",
    "sourceGoal": "Failed payment to CRM update and follow-up email"
  }
}
#09Reporting

Daily KPI digest → Google Sheets read + Slack summary

Problem

Teams want a daily numbers snapshot, but someone still opens spreadsheets and rewrites the same Slack update each morning.

Workflow steps

  1. 1Run every weekday morning.
  2. 2Read the latest KPI rows from Google Sheets.
  3. 3Format the rows into a concise daily digest.
  4. 4Post the digest in Slack.
  5. 5Optionally extend with an AI summary if metrics need interpretation.

Setup notes

  • Replace REPLACE_WITH_GOOGLE_SHEET_ID and KPI sheet/tab names.
  • Connect Google Sheets and Slack credentials in n8n.
  • Adjust the schedule to match your team's timezone.
Want a custom version? Generate any workflow from plain English with FlowForge AI.

Full importable n8n JSON

Copy everything in this block into n8n.

daily-kpi-digest-sheets-slack.json
n8n workflow
{
  "name": "Daily KPI Digest from Google Sheets to Slack",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 9 * * 1-5"
            }
          ]
        }
      },
      "id": "weekday-morning-schedule",
      "name": "Weekday Morning Schedule",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        0,
        0
      ]
    },
    {
      "parameters": {
        "operation": "read",
        "documentId": "REPLACE_WITH_GOOGLE_SHEET_ID",
        "sheetName": "KPIs",
        "range": "A1:F20"
      },
      "id": "read-kpi-sheet",
      "name": "Read KPI Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4,
      "position": [
        280,
        0
      ]
    },
    {
      "parameters": {
        "jsCode": "const lines = items.map((item) => `• ${item.json.metric || item.json.Metric}: ${item.json.value || item.json.Value}`).join('\\n'); return [{ json: { digest: `Daily KPI digest:\\n${lines}` } }];"
      },
      "id": "format-kpi-digest",
      "name": "Format KPI Digest",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        560,
        0
      ]
    },
    {
      "parameters": {
        "channel": "#daily-metrics",
        "text": "={{$json.digest}}"
      },
      "id": "post-digest-to-slack",
      "name": "Post Digest to Slack",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2,
      "position": [
        840,
        0
      ]
    }
  ],
  "connections": {
    "Weekday Morning Schedule": {
      "main": [
        [
          {
            "node": "Read KPI Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read KPI Sheet": {
      "main": [
        [
          {
            "node": "Format KPI Digest",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format KPI Digest": {
      "main": [
        [
          {
            "node": "Post Digest to Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "flowforge-template-kpi-digest-v1",
  "meta": {
    "generatedBy": "FlowForge AI templates",
    "sourceGoal": "Daily KPI digest from Google Sheets to Slack"
  }
}
#10Support ops

Support ticket → AI classify → Trello card + Slack

Problem

Support tickets need routing and priority, but early-stage teams often classify tickets manually after customers are already waiting.

Workflow steps

  1. 1Receive a Zendesk, Help Scout, Intercom, or custom ticket webhook.
  2. 2Normalize requester, subject, message, ticket URL, and source.
  3. 3Ask an AI endpoint for category, priority, and one-sentence summary.
  4. 4Create a Trello card through the Trello REST API.
  5. 5Post the classification result to the support Slack channel.

Setup notes

  • Point your support tool webhook at the n8n URL.
  • Replace AI and Trello API placeholders.
  • Add a real escalation branch if high-priority tickets need paging.
Want a custom version? Generate any workflow from plain English with FlowForge AI.

Full importable n8n JSON

Copy everything in this block into n8n.

support-ticket-ai-classify-trello-slack.json
n8n workflow
{
  "name": "Support Ticket to AI Classification Trello and Slack",
  "nodes": [
    {
      "parameters": {
        "path": "support-ticket-created",
        "httpMethod": "POST",
        "responseMode": "onReceived",
        "responseData": "firstEntryJson"
      },
      "id": "support-ticket-webhook",
      "name": "Support Ticket Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        0,
        0
      ]
    },
    {
      "parameters": {
        "keepOnlySet": true,
        "values": {
          "string": [
            {
              "name": "requester",
              "value": "={{$json.requester?.email || $json.email}}"
            },
            {
              "name": "subject",
              "value": "={{$json.subject || $json.title}}"
            },
            {
              "name": "message",
              "value": "={{$json.message || $json.description || $json.body}}"
            },
            {
              "name": "ticketUrl",
              "value": "={{$json.url || $json.ticketUrl}}"
            },
            {
              "name": "source",
              "value": "={{$json.source || 'support'}}"
            }
          ]
        }
      },
      "id": "normalize-support-ticket",
      "name": "Normalize Support Ticket",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3,
      "position": [
        280,
        0
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.openai.com/v1/chat/completions",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer REPLACE_WITH_OPENAI_API_KEY"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "model",
              "value": "gpt-4o-mini"
            },
            {
              "name": "messages",
              "value": "=[{role:'system',content:'Classify this support ticket as category, priority, and one-sentence summary.'},{role:'user',content:$json.subject + '\\n' + $json.message}]"
            }
          ]
        }
      },
      "id": "classify-ticket-with-ai",
      "name": "Classify Ticket with AI",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        560,
        0
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.trello.com/1/cards",
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "idList",
              "value": "REPLACE_WITH_TRELLO_LIST_ID"
            },
            {
              "name": "name",
              "value": "={{$json.subject}}"
            },
            {
              "name": "desc",
              "value": "Requester: {{$json.requester}}\\nTicket: {{$json.ticketUrl}}\\nAI result: {{$json.choices?.[0]?.message?.content}}"
            },
            {
              "name": "key",
              "value": "REPLACE_WITH_TRELLO_KEY"
            },
            {
              "name": "token",
              "value": "REPLACE_WITH_TRELLO_TOKEN"
            }
          ]
        }
      },
      "id": "create-trello-card",
      "name": "Create Trello Card",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        840,
        -120
      ]
    },
    {
      "parameters": {
        "channel": "#support",
        "text": "New support ticket: {{$json.subject}} from {{$json.requester}}. AI classification: {{$json.choices?.[0]?.message?.content || 'Needs review'}}"
      },
      "id": "notify-support-in-slack",
      "name": "Notify Support in Slack",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2,
      "position": [
        1120,
        -120
      ]
    }
  ],
  "connections": {
    "Support Ticket Webhook": {
      "main": [
        [
          {
            "node": "Normalize Support Ticket",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize Support Ticket": {
      "main": [
        [
          {
            "node": "Classify Ticket with AI",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Classify Ticket with AI": {
      "main": [
        [
          {
            "node": "Create Trello Card",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Trello Card": {
      "main": [
        [
          {
            "node": "Notify Support in Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "flowforge-template-support-triage-v1",
  "meta": {
    "generatedBy": "FlowForge AI templates",
    "sourceGoal": "Support ticket to AI classify, Trello card, and Slack"
  }
}

Need more than a template?

Generate custom n8n JSON from plain English.

Start with the $9 Starter Pack for import-ready files and a prompt cheat-sheet, then upgrade to Pro when you need unlimited custom workflow generation.

$9 — Get the Starter Pack

10 templates + prompt cheat-sheet

Get Pack — $9