This workflow corresponds to n8n.io template #17751 — we link there as the canonical source.
This workflow follows the Gmail → Google Sheets recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"id": "XluCFlXNGV59hKB3",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Demo Order Processing \u2014 Stripe + Lovable + Gmail + Slack",
"tags": [
{
"id": "OvFYhjJXlS56B9rk",
"name": "stripe",
"createdAt": "2026-08-02T18:27:36.692Z",
"updatedAt": "2026-08-02T18:27:36.692Z"
},
{
"id": "rCd1tGwxINxFwo6G",
"name": "production",
"createdAt": "2026-08-02T18:27:36.649Z",
"updatedAt": "2026-08-02T18:27:36.649Z"
}
],
"nodes": [
{
"id": "aab90100-9273-4fb4-aa48-2853e89f3226",
"name": "01 | Webhook Trigger",
"type": "n8n-nodes-base.webhook",
"position": [
-3360,
720
],
"parameters": {
"path": "process-order",
"options": {},
"httpMethod": "POST",
"responseMode": "responseNode"
},
"typeVersion": 2
},
{
"id": "da7ec619-6f97-47ef-85c5-ec1cc7ff0147",
"name": "02 | Validate Payload",
"type": "n8n-nodes-base.code",
"position": [
-3104,
720
],
"parameters": {
"jsCode": "// \u2705 Extract the actual Lovable payload\nconst body = $input.first()?.json?.body || {};\nconst errors = [];\n\n// --------------------\n// Required fields\n// --------------------\nif (!body.order_id) errors.push('Missing field: order_id');\nif (!body.email) errors.push('Missing field: email');\n\n// --------------------\n// Email validation\n// --------------------\nif (\n body.email &&\n !/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(String(body.email))\n) {\n errors.push('Invalid email format');\n}\n\n// --------------------\n// Amount validation\n// --------------------\nconst amount = Number(body.amount);\nif (!Number.isFinite(amount) || amount <= 0) {\n errors.push('Amount must be a positive number');\n}\n\n// --------------------\n// Payment failure simulation\n// --------------------\nconst simulateFailure =\n body.force_fail === true ||\n body.force_fail === 'true';\n\n// --------------------\n// Normalized output\n// --------------------\nreturn [\n {\n json: {\n order_id: String(body.order_id || ''),\n email: String(body.email || ''),\n amount: Number.isFinite(amount) ? amount : 0,\n currency: body.currency || 'USD',\n\n customer_name: body.customer_name || 'Valued Customer',\n product_name: body.product_name || 'Order',\n status: body.status || 'pending',\n\n // \ud83d\udd34 Used by IF node for demo failure\n simulate_payment_failure: simulateFailure,\n\n validation_passed: errors.length === 0,\n validation_errors: errors,\n received_at: new Date().toISOString(),\n },\n },\n];"
},
"typeVersion": 2
},
{
"id": "8208a26f-23dc-4c38-a1cc-8eef0f112478",
"name": "03 | Is Valid?",
"type": "n8n-nodes-base.if",
"position": [
-2832,
720
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "c1",
"operator": {
"type": "boolean",
"operation": "equals"
},
"leftValue": "={{ $json.validation_passed }}",
"rightValue": true
}
]
}
},
"typeVersion": 2
},
{
"id": "1986eb17-e91c-44a5-ab13-3b99ed78c9e3",
"name": "03a | Respond \u2014 400 Bad Request",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
-2640,
848
],
"parameters": {
"options": {
"responseCode": 400
},
"respondWith": "json",
"responseBody": "={{\n {\n success: false,\n error: \"Validation failed\",\n details: $json.validation_errors\n }\n}}"
},
"typeVersion": 1
},
{
"id": "3df25d46-2271-4b4f-824b-b4092b70eb39",
"name": "04 | Set Idempotency Key",
"type": "n8n-nodes-base.set",
"position": [
-2368,
592
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "304ecbb3-7652-4de8-9701-5d719226f804",
"name": "idempotency_key",
"type": "string",
"value": "={{($json.email || '').trim() + '|' + ($json.product_name || '').trim() + '|' + String($json.amount || '')}}"
}
]
},
"includeOtherFields": true
},
"typeVersion": 3.4
},
{
"id": "6ec0fb60-2130-4f34-a704-05c50456a6cf",
"name": "05 | Idempotency Lookup",
"type": "n8n-nodes-base.googleSheets",
"position": [
-2144,
592
],
"parameters": {
"options": {},
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1OQRWbM-1s9_dOBiZH7th3AEJca2roxw1Hkjdgl5ZvW0/edit#gid=0",
"cachedResultName": "orders"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1OQRWbM-1s9_dOBiZH7th3AEJca2roxw1Hkjdgl5ZvW0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1OQRWbM-1s9_dOBiZH7th3AEJca2roxw1Hkjdgl5ZvW0/edit?usp=drivesdk",
"cachedResultName": "Swiftpay-Database"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4,
"alwaysOutputData": true
},
{
"id": "8210777f-fe48-4048-b0dd-3adaaf6564b0",
"name": "06 | Is Duplicate?",
"type": "n8n-nodes-base.if",
"position": [
-1920,
592
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "c2",
"operator": {
"type": "string",
"operation": "notEmpty",
"singleValue": true
},
"leftValue": "={{ $json.order_id }}",
"rightValue": 0
}
]
}
},
"typeVersion": 2
},
{
"id": "0bb241f8-12c5-413c-a6d4-28d1a9b959e5",
"name": "06a | Respond \u2014 409 Conflict",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
-1568,
432
],
"parameters": {
"options": {
"responseCode": 409
},
"respondWith": "json",
"responseBody": "={\n \"success\": false,\n \"code\": \"DUPLICATE_ORDER\",\n \"message\": \"This order has already been processed.\",\n \"details\": {\n \"reason\": \"Duplicate submission detected\",\n \"order_reference\": \"{{ $('02 | Validate Payload').item.json.order_id }}\"\n }\n}"
},
"typeVersion": 1
},
{
"id": "7cfe6b81-c4b6-4853-af30-fbdb1501cebc",
"name": "07 | Store Order (processing)",
"type": "n8n-nodes-base.googleSheets",
"position": [
-1712,
608
],
"parameters": {
"columns": {
"value": {
"email": "={{ $('04 | Set Idempotency Key').item.json.email }}",
"amount": "={{ $('04 | Set Idempotency Key').item.json.amount }}",
"status": "processing",
"order_id": "={{ $('04 | Set Idempotency Key').item.json.order_id }}",
"created_at": "={{ new Date().toISOString() }}",
"updated_at": "={{ new Date().toISOString() }}",
"idempotency_key": "={{ $json.idempotency_key }}"
},
"schema": [
{
"id": "order_id",
"type": "string",
"display": true,
"required": false,
"displayName": "order_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "email",
"type": "string",
"display": true,
"required": false,
"displayName": "email",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "amount",
"type": "string",
"display": true,
"required": false,
"displayName": "amount",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "status",
"type": "string",
"display": true,
"required": false,
"displayName": "status",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "created_at",
"type": "string",
"display": true,
"required": false,
"displayName": "created_at",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "updated_at",
"type": "string",
"display": true,
"required": false,
"displayName": "updated_at",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "idempotency_key",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "idempotency_key",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {
"cellFormat": "RAW"
},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "name",
"value": "orders"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1OQRWbM-1s9_dOBiZH7th3AEJca2roxw1Hkjdgl5ZvW0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1OQRWbM-1s9_dOBiZH7th3AEJca2roxw1Hkjdgl5ZvW0/edit?usp=drivesdk",
"cachedResultName": "Database"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4
},
{
"id": "f26048f1-4dac-43a1-96ef-d98dc48b7878",
"name": "08 | Log \u2014 Order Received",
"type": "n8n-nodes-base.googleSheets",
"position": [
-1440,
608
],
"parameters": {
"columns": {
"value": {
"step": "order_received",
"status": "processing",
"mesaage": "Order validated and stored with status=processing",
"order_id": "={{ $('04 | Set Idempotency Key').item.json.order_id }}",
"timestamp": "={{ new Date().toISOString() }}"
},
"schema": [
{
"id": "order_id",
"type": "string",
"display": true,
"required": false,
"displayName": "order_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "step",
"type": "string",
"display": true,
"required": false,
"displayName": "step",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "status",
"type": "string",
"display": true,
"required": false,
"displayName": "status",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "mesaage",
"type": "string",
"display": true,
"required": false,
"displayName": "mesaage",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "timestamp",
"type": "string",
"display": true,
"required": false,
"displayName": "timestamp",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "name",
"value": "logs"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1OQRWbM-1s9_dOBiZH7th3AEJca2roxw1Hkjdgl5ZvW0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1OQRWbM-1s9_dOBiZH7th3AEJca2roxw1Hkjdgl5ZvW0/edit?usp=drivesdk",
"cachedResultName": "Database"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4
},
{
"id": "546ef063-15d6-4c21-942a-0f9c3053f836",
"name": "09 | Prepare Payment Data",
"type": "n8n-nodes-base.set",
"position": [
-1248,
384
],
"parameters": {
"fields": {
"values": [
{
"name": "=retry_count",
"type": "numberValue",
"numberValue": "0"
},
{
"name": "order_id",
"stringValue": "={{$json.order_id}}"
},
{
"name": "email",
"stringValue": "={{ $('04 | Set Idempotency Key').item.json.email }}"
},
{
"name": "amount",
"stringValue": "={{ $('04 | Set Idempotency Key').item.json.amount }}"
},
{
"name": "product_name",
"stringValue": "={{ $('04 | Set Idempotency Key').item.json.product_name }}"
},
{
"name": "customer_name",
"stringValue": "={{ $('04 | Set Idempotency Key').item.json.customer_name }}"
},
{
"name": "step",
"stringValue": "order_received"
},
{
"name": "status",
"stringValue": "processing"
},
{
"name": "timestamp",
"stringValue": "={{$now}}"
},
{
"name": "=simulate_payment_failure",
"type": "booleanValue",
"booleanValue": "={{$json.simulate_payment_failure}}"
},
{
"name": "currency",
"stringValue": "={{ $('04 | Set Idempotency Key').item.json.currency }}"
},
{
"name": "idempotency_key",
"stringValue": "={{ $('04 | Set Idempotency Key').item.json.idempotency_key }}"
}
]
},
"options": {}
},
"typeVersion": 3
},
{
"id": "f0009cd6-68ef-4679-9297-26c100e64c30",
"name": "10 | Create Payment Intent (Demo)",
"type": "n8n-nodes-base.httpRequest",
"onError": "continueErrorOutput",
"position": [
-1040,
448
],
"parameters": {
"url": "=https://httpbin.org/anything",
"method": "POST",
"options": {
"timeout": 10000,
"response": {
"response": {
"fullResponse": true,
"responseFormat": "json"
}
}
},
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "order_id",
"value": "={{$json.order_id}}"
},
{
"name": "email",
"value": "={{$json.email}}"
},
{
"name": "amount",
"value": "={{$json.amount}}"
},
{
"name": "currency",
"value": "={{$json.currency}}"
},
{
"name": "simulate_payment_failure",
"value": "={{ $('02 | Validate Payload').item.json.simulate_payment_failure }}"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "bd2ba3c4-d139-4e84-b4e6-6e484e243b8b",
"name": "10a | Log Payment Gateway Error",
"type": "n8n-nodes-base.googleSheets",
"position": [
-784,
528
],
"parameters": {
"columns": {
"value": {
"timestamp": "={{ $now.toISO() }}",
"error node": "10 | Create Payment Intent (Demo)",
"error message": "={{ $json.error.message }}"
},
"schema": [
{
"id": "error node",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "error node",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "error message",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "error message",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "timestamp",
"type": "string",
"display": true,
"required": false,
"displayName": "timestamp",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "name",
"value": "errors"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1OQRWbM-1s9_dOBiZH7th3AEJca2roxw1Hkjdgl5ZvW0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1OQRWbM-1s9_dOBiZH7th3AEJca2roxw1Hkjdgl5ZvW0/edit?usp=drivesdk",
"cachedResultName": "Database"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4
},
{
"id": "48cf79ea-4af5-4e4d-a689-e579fb65bf48",
"name": "11 | Evaluate Payment Response",
"type": "n8n-nodes-base.code",
"position": [
-848,
272
],
"parameters": {
"jsCode": "// 11 | Evaluate Payment Response\n\nconst resp = $input.first();\n\n// \u2705 Order context (authoritative business intent)\nconst orderState = $('09 | Prepare Payment Data').item.json;\n\n// \u2705 HTTP status\nconst statusCode = resp.json?.statusCode ?? 200;\n\n// \u2705 CORRECT location of echoed request payload (HTTP v2 node)\nconst httpBody = resp.json?.body ?? {};\nconst stripeEcho = httpBody.json ?? {};\n\n// \u2705 Determine simulation flag (robust + defensive)\nconst simulationEnabled =\n orderState.simulate_payment_failure === true ||\n orderState.simulate_payment_failure === 'true' ||\n stripeEcho.simulate_payment_failure === true ||\n stripeEcho.simulate_payment_failure === 'true';\n\n// \u2705 Simulation ALWAYS forces failure\nconst paymentSuccess = simulationEnabled\n ? false\n : statusCode >= 200 && statusCode < 300;\n\nreturn [\n {\n json: {\n ...orderState,\n\n // keep gateway echo for debugging / audit\n stripe_response: stripeEcho,\n\n // \u2705 authoritative routing flags\n simulated: simulationEnabled,\n payment_success: paymentSuccess,\n\n stripe_status: paymentSuccess ? 'succeeded' : 'failed',\n\n stripe_intent_id: paymentSuccess\n ? `demo_pi_${Date.now()}`\n : null,\n\n stripe_error: paymentSuccess\n ? null\n : simulationEnabled\n ? 'Simulated failure \u2014 demo mode'\n : 'Payment declined',\n\n evaluated_at: new Date().toISOString()\n }\n }\n];"
},
"typeVersion": 2
},
{
"id": "5d94a2a0-8dc3-434e-a81a-110508a349ec",
"name": "12 | Payment Successful?",
"type": "n8n-nodes-base.if",
"position": [
-656,
272
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "c3",
"operator": {
"type": "boolean",
"operation": "equals"
},
"leftValue": "={{ $json.payment_success }}",
"rightValue": true
}
]
}
},
"typeVersion": 2
},
{
"id": "809383da-b7b6-4a6c-bc1e-ea6fdf377911",
"name": "13 | Update Order (completed)",
"type": "n8n-nodes-base.googleSheets",
"position": [
-400,
64
],
"parameters": {
"columns": {
"value": {
"email": "={{ $json.email }}",
"amount": "={{ $json.amount }}",
"status": "completed",
"order_id": "={{ $json.order_id }}",
"created_at": "={{ $json.evaluated_at }}",
"updated_at": "={{ $now.toISO() }}",
"idempotency_key": "={{ $json.idempotency_key }}"
},
"schema": [
{
"id": "order_id",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "order_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "email",
"type": "string",
"display": true,
"required": false,
"displayName": "email",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "amount",
"type": "string",
"display": true,
"required": false,
"displayName": "amount",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "status",
"type": "string",
"display": true,
"required": false,
"displayName": "status",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "created_at",
"type": "string",
"display": true,
"required": false,
"displayName": "created_at",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "updated_at",
"type": "string",
"display": true,
"required": false,
"displayName": "updated_at",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "idempotency_key",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "idempotency_key",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "row_number",
"type": "number",
"display": true,
"removed": true,
"readOnly": true,
"required": false,
"displayName": "row_number",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"order_id"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "update",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1OQRWbM-1s9_dOBiZH7th3AEJca2roxw1Hkjdgl5ZvW0/edit#gid=0",
"cachedResultName": "orders"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1OQRWbM-1s9_dOBiZH7th3AEJca2roxw1Hkjdgl5ZvW0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1OQRWbM-1s9_dOBiZH7th3AEJca2roxw1Hkjdgl5ZvW0/edit?usp=drivesdk",
"cachedResultName": "Database"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4
},
{
"id": "6c574477-7d56-4990-8ff9-c3582a9c0975",
"name": "14 | Log \u2014 Payment Success",
"type": "n8n-nodes-base.googleSheets",
"position": [
-176,
64
],
"parameters": {
"columns": {
"value": {
"step": "payment_completed",
"status": "success",
"mesaage": "={{ 'Stripe Payment Intent created: ' + $('11 | Evaluate Payment Response').item.json.stripe_intent_id }}",
"order_id": "={{ $('11 | Evaluate Payment Response').item.json.order_id }}",
"timestamp": "={{ new Date().toISOString() }}"
},
"schema": [
{
"id": "order_id",
"type": "string",
"display": true,
"required": false,
"displayName": "order_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "step",
"type": "string",
"display": true,
"required": false,
"displayName": "step",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "status",
"type": "string",
"display": true,
"required": false,
"displayName": "status",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "mesaage",
"type": "string",
"display": true,
"required": false,
"displayName": "mesaage",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "timestamp",
"type": "string",
"display": true,
"required": false,
"displayName": "timestamp",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "name",
"value": "logs"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1OQRWbM-1s9_dOBiZH7th3AEJca2roxw1Hkjdgl5ZvW0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1OQRWbM-1s9_dOBiZH7th3AEJca2roxw1Hkjdgl5ZvW0/edit?usp=drivesdk",
"cachedResultName": "Database"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4
},
{
"id": "c55395d2-00aa-4dbc-b694-90b6f495de34",
"name": "15 | Send Success Receipt (Gmail)",
"type": "n8n-nodes-base.gmail",
"onError": "continueErrorOutput",
"position": [
48,
64
],
"parameters": {
"sendTo": "={{ $('09 | Prepare Payment Data').item.json.email }}",
"message": "=<div style=\"font-family: Arial, sans-serif; background-color: #f7f7f7; padding: 20px;\">\n <div style=\"max-width: 600px; margin: auto; background: #ffffff; padding: 24px; border-radius: 8px;\">\n \n <h2 style=\"color: #2e7d32; margin-top: 0;\">\n \u2705 Payment Confirmed\n </h2>\n\n <p>\n Hello\n <strong>{{ $('09 | Prepare Payment Data').item.json.customer_name }}</strong>,\n </p>\n\n <p>\n Thank you for your purchase. Your payment has been successfully processed.\n </p>\n\n <hr style=\"border: none; border-top: 1px solid #e0e0e0; margin: 20px 0;\" />\n\n <h3 style=\"margin-bottom: 8px;\">Order Details</h3>\n\n <p>\n <strong>Order ID:</strong>\n {{ $('09 | Prepare Payment Data').item.json.order_id }}\n </p>\n\n <p>\n <strong>Product:</strong>\n {{ $('09 | Prepare Payment Data').item.json.product_name }}\n </p>\n\n <p>\n <strong>Amount:</strong>\n ${{ $('09 | Prepare Payment Data').item.json.amount }}\n {{ $('09 | Prepare Payment Data').item.json.currency || 'USD' }}\n </p>\n\n <p>\n <strong>Status:</strong> Paid\n </p>\n\n <hr style=\"border: none; border-top: 1px solid #e0e0e0; margin: 20px 0;\" />\n\n <p>\n If you have any questions or need support, feel free to reply to this email.\n </p>\n\n <p style=\"margin-top: 24px;\">\n Best regards,<br />\n <strong>SwiftPay Team</strong>\n </p>\n\n </div>\n</div>",
"options": {},
"subject": "=Payment Confirmed \u2013 Order {{$json.order_id}}"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
},
{
"id": "476bc36c-d9da-4c3e-8d4c-56c37dca76eb",
"name": "15a | Log Email Error",
"type": "n8n-nodes-base.googleSheets",
"position": [
304,
112
],
"parameters": {
"columns": {
"value": {
"timestamp": "={{ $now.toISO() }}",
"error node": "15 | Send Success Receipt (Gmail)",
"error message": "={{ $json.error.message }}"
},
"schema": [
{
"id": "error node",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "error node",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "error message",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "error message",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "timestamp",
"type": "string",
"display": true,
"required": false,
"displayName": "timestamp",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "name",
"value": "errors"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1OQRWbM-1s9_dOBiZH7th3AEJca2roxw1Hkjdgl5ZvW0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1OQRWbM-1s9_dOBiZH7th3AEJca2roxw1Hkjdgl5ZvW0/edit?usp=drivesdk",
"cachedResultName": "Database"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4
},
{
"id": "ee57d234-7a14-48b5-8595-dee4afdfe3c8",
"name": "16 | Respond \u2014 200 Success",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
288,
-96
],
"parameters": {
"options": {
"responseCode": 200
},
"respondWith": "json",
"responseBody": "={{ JSON.stringify({\n success: true,\n code: \"PAYMENT_COMPLETED\",\n order_id: $('11 | Evaluate Payment Response').item.json.order_id,\n stripe_intent_id: $('11 | Evaluate Payment Response').item.json.stripe_intent_id,\n status: \"completed\",\n message: \"Payment processed successfully.\",\n processed_at: new Date().toISOString()\n}) }}"
},
"typeVersion": 1
},
{
"id": "26832bb8-32b0-4822-a11b-704684a3bab4",
"name": "17 | Is Failure Simulation?",
"type": "n8n-nodes-base.if",
"position": [
-416,
416
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "04225816-2e78-41cf-afd3-463da739ffcd",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ $json.simulated }}\n",
"rightValue": "true"
}
]
},
"looseTypeValidation": true
},
"typeVersion": 2.3
},
{
"id": "74283ed4-58fd-404f-96ae-91b07eabeb14",
"name": "18 | Update Order (failed)",
"type": "n8n-nodes-base.googleSheets",
"position": [
-112,
528
],
"parameters": {
"columns": {
"value": {
"email": "={{ $json.email }}",
"amount": "={{ $json.amount }}",
"status": "failed",
"order_id": "={{ $json.order_id }}",
"created_at": "={{ $('02 | Validate Payload').item.json.received_at }}",
"updated_at": "={{ $now.toISO() }}",
"idempotency_key": "={{ $json.idempotency_key }}"
},
"schema": [
{
"id": "order_id",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "order_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "email",
"type": "string",
"display": true,
"required": false,
"displayName": "email",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "amount",
"type": "string",
"display": true,
"required": false,
"displayName": "amount",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "status",
"type": "string",
"display": true,
"required": false,
"displayName": "status",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "created_at",
"type": "string",
"display": true,
"required": false,
"displayName": "created_at",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "updated_at",
"type": "string",
"display": true,
"required": false,
"displayName": "updated_at",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "idempotency_key",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "idempotency_key",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "row_number",
"type": "number",
"display": true,
"removed": true,
"readOnly": true,
"required": false,
"displayName": "row_number",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"order_id"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "update",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1OQRWbM-1s9_dOBiZH7th3AEJca2roxw1Hkjdgl5ZvW0/edit#gid=0",
"cachedResultName": "orders"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1OQRWbM-1s9_dOBiZH7th3AEJca2roxw1Hkjdgl5ZvW0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1OQRWbM-1s9_dOBiZH7th3AEJca2roxw1Hkjdgl5ZvW0/edit?usp=drivesdk",
"cachedResultName": "Database"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4
},
{
"id": "aa4e168d-ef80-40df-a4a1-66e152aad438",
"name": "19 | Log \u2014 Payment Failed",
"type": "n8n-nodes-base.googleSheets",
"position": [
128,
528
],
"parameters": {
"columns": {
"value": {
"step": "payment_failed",
"status": "failed",
"mesaage": "={{ 'Payment failed after ' + $json.retry_count + ' retries. Stripe error: ' + ($json.stripe_error || 'unknown') }}",
"order_id": "={{ $json.order_id }}",
"timestamp": "={{ new Date().toISOString() }}"
},
"schema": [
{
"id": "order_id",
"type": "string",
"display": true,
"required": false,
"displayName": "order_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "step",
"type": "string",
"display": true,
"required": false,
"displayName": "step",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "status",
"type": "string",
"display": true,
"required": false,
"displayName": "status",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "mesaage",
"type": "string",
"display": true,
"required": false,
"displayName": "mesaage",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "timestamp",
"type": "string",
"display": true,
"required": false,
"displayName": "timestamp",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "name",
"value": "logs"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1OQRWbM-1s9_dOBiZH7th3AEJca2roxw1Hkjdgl5ZvW0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1OQRWbM-1s9_dOBiZH7th3AEJca2roxw1Hkjdgl5ZvW0/edit?usp=drivesdk",
"cachedResultName": "Database"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4
},
{
"id": "e8dc70d5-337c-48ef-9188-5e5a67bf487c",
"name": "20 | Send Failure Alert (Slack)",
"type": "n8n-nodes-base.slack",
"onError": "continueErrorOutput",
"position": [
320,
720
],
"parameters": {
"text": "=:warning: *Payment Failed*\n\n*Order ID:* {{ $('09 | Prepare Payment Data').item.json.order_id }}\n*Customer:* {{ $('09 | Prepare Payment Data').item.json.customer_name }}\n*Email:* {{ $('09 | Prepare Payment Data').item.json.email }}\n\n*Product:* {{ $('09 | Prepare Payment Data').item.json.product_name }}\n*Amount:* ${{ $('09 | Prepare Payment Data').item.json.amount }} {{ $('09 | Prepare Payment Data').item.json.currency || 'USD' }}\n\n*Status:* Payment Failed\n*Retry Count:* {{ $('09 | Prepare Payment Data').item.json.retry_count }}\n*Timestamp:* {{ $('09 | Prepare Payment Data').item.json.timestamp }}\n\nManual review may be required.",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "list",
"value": "C0ATF16GUQ7",
"cachedResultName": "error-logs"
},
"otherOptions": {},
"authentication": "oAuth2"
},
"credentials": {
"slackOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 2.2
},
{
"id": "a8c16737-4a11-4050-98ce-f218095299b1",
"name": "20a | Log Slack Error",
"type": "n8n-nodes-base.googleSheets",
"position": [
560,
912
],
"parameters": {
"columns": {
"value": {
"timestamp": "={{ $now.toISO() }}",
"error node": "20 | Send Failure Alert (Slack)",
"error message": "={{ $json.error.message }}"
},
"schema": [
{
"id": "error node",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "error node",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "error message",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "error message",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "timestamp",
"type": "string",
"display": true,
"required": false,
"displayName": "timestamp",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "name",
"value": "errors"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1OQRWbM-1s9_dOBiZH7th3AEJca2roxw1Hkjdgl5ZvW0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1OQRWbM-1s9_dOBiZH7th3AEJca2roxw1Hkjdgl5ZvW0/edit?usp=drivesdk",
"cachedResultName": "Database"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4
},
{
"id": "d6e61114-086f-4fed-945f-526d1f53496e",
"name": "21 | Respond \u2014 502 Failed",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
560,
576
],
"parameters": {
"options": {
"responseCode": 502
},
"respondWith": "json",
"responseBody": "={\n \"success\": false,\n \"code\": \"PAYMENT_SIMULATED_FAILURE\",\n \"message\": \"Payment was not successful. This failure was intentionally simulated and no charges were made.\",\n \"order_id\": \"{{ $json.order_id }}\",\n \"details\": {\n \"status\": \"failed\",\n \"simulated\": true,\n \"retryable\": false,\n \"support_message\": \"This failure was triggered in demo mode for testing purposes.\"\n }\n}"
},
"typeVersion": 1
},
{
"id": "sticky-overview-0001",
"name": "Sticky Note \u2014 Overview",
"type": "n8n-nodes-base.stickyNote",
"position": [
-3408,
-496
],
"parameters": {
"width": 972,
"height": 864,
"content": "\ud83d\udcb3 Order Processing \u2014 Payment Demo Overview\nThis workflow demonstrates a complete payment-to-fulfilment pipeline for teams handling online orders. It validates incoming requests, prevents duplicates, simulates payments, and ensures customers are notified while failures trigger alerts. Every step is logged to Google Sheets for full transparency and auditability.\n\nHow it works\nReceive order via webhook\n\nValidate payload and reject invalid requests (400)\n\nBlock duplicates using idempotency key (409)\n\nStore order and create a demo payment intent\n\nBranch on payment outcome:\n\nSuccess \u2192 send receipt email + return 200\n\nFailure \u2192 send Slack alert + return 502\n\nWrite all events to Google Sheets (orders, logs, errors)\n\nSetup\nGoogle Sheets: connect to a file with orders, logs, and errors tabs\n\nGmail: used to send customer receipts\n\nSlack: used for failure alerts\n\nEndpoint: POST /webhook/process-order\n\nCustomization\nSwap the demo payment node (httpbin.org) for a real Stripe Create Payment Intent call in production. Use \"force_fail\": true in the request body to test the failure path."
},
"typeVersion": 1
},
{
"id": "sticky-section-1",
"name": "Sticky Note \u2014 Section 1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-3408,
560
],
"parameters": {
"color": 7,
"width": 972,
"height": 480,
"content": "## 1. Intake & Validation\n\nReceive the order webhook, normalise the payload, and reject invalid requests with a `400`."
},
"typeVersion": 1
},
{
"id": "sticky-section-2",
"name": "Sticky Note \u2014 Section 2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2400,
288
],
"parameters": {
"color": 7,
"width": 1118,
"height": 520,
"content": "## 2. Idempotency & Store\n\nBuild an idempotency key, look up existing orders, reject duplicates with a `409`, and persist the new order as `processing`."
},
"typeVersion": 1
},
{
"id": "sticky-section-3",
"name": "Sticky Note \u2014 Section 3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1248,
176
],
"parameters": {
"color": 7,
"width": 744,
"height": 520,
"content": "## 3. Payment Processing\n\nPrepare payment data, create the payment intent (demo), and evaluate the gateway response to decide success vs. failure."
},
"typeVersion": 1
},
{
"id": "sticky-section-4",
"name": "Sticky Note \u2014 Section 4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-464,
-208
],
"parameters": {
"color": 7,
"width": 984,
"height": 480,
"content": "## 4. Success Path\n\nMark the order `completed`, log the success, email the customer receipt, and respond `200`."
},
"typeVersion": 1
},
{
"id": "sticky-section-5",
"name": "Sticky Note \u2014 Section 5",
"type": "n8n-nodes-base.stickyNote",
"position": [
-480,
304
],
"parameters": {
"color": 7,
"width": 1230,
"height": 816,
"content": "## 5. Failure Path\n\nHandle simulated / declined payments: mark the order `failed`, log it, alert the team on Slack, and respond `502`."
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"binaryMode": "separate",
"availableInMCP": false,
"executionOrder": "v1"
},
"versionId": "e5360404-ad14-4797-bbf0-fd0f0069ea82",
"nodeGroups": [],
"connections": {
"03 | Is Valid?": {
"main": [
[
{
"node": "04 | Set Idempotency Key",
"type": "main",
"index": 0
}
],
[
{
"node": "03a | Respond \u2014 400 Bad Request",
"type": "main",
"index": 0
}
]
]
},
"06 | Is Duplicate?": {
"main": [
[
{
"node": "06a | Respond \u2014 409 Conflict",
"type": "main",
"index": 0
}
],
[
{
"node": "07 | Store Order (processing)",
"type": "main",
"index": 0
}
]
]
},
"01 | Webhook Trigger": {
"main": [
[
{
"node": "02 | Validate Payload",
"type": "main",
"index": 0
}
]
]
},
"02 | Validate Payload": {
"main": [
[
{
"node": "03 | Is Valid?",
"type": "main",
"index": 0
}
]
]
},
"05 | Idempotency Lookup": {
"main": [
[
{
"node": "06 | Is Duplicate?",
"type": "main",
"index": 0
}
]
]
},
"04 | Set Idempotency Key": {
"main": [
[
{
"node": "05 | Idempotency Lookup",
"type": "main",
"index": 0
}
]
]
},
"12 | Payment Successful?": {
"main": [
[
{
"node": "13 | Update Order (completed)",
"type": "main",
"index": 0
}
],
[
{
"node": "17 | Is Failure Simulation?",
"type": "main",
"index": 0
}
]
]
},
"09 | Prepare Payment Data": {
"main": [
[
{
"node": "10 | Create Payment Intent (Demo)",
"type": "main",
"index": 0
}
]
]
},
"18 | Update Order (failed)": {
"main": [
[
{
"node": "19 | Log \u2014 Payment Failed",
"type": "main",
"index": 0
}
]
]
},
"08 | Log \u2014 Order Received": {
"main": [
[
{
"node": "09 | Prepare Payment Data",
"type": "main",
"index": 0
}
]
]
},
"17 | Is Failure Simulation?": {
"main": [
[
{
"node": "18 | Update Order (failed)",
"type": "main",
"index": 0
}
]
]
},
"19 | Log \u2014 Payment Failed": {
"main": [
[
{
"node": "20 | Send Failure Alert (Slack)",
"type": "main",
"index": 0
}
]
]
},
"14 | Log \u2014 Payment Success": {
"main": [
[
{
"node": "15 | Send Success Receipt (Gmail)",
"type": "main",
"index": 0
}
]
]
},
"07 | Store Order (processing)": {
"main": [
[
{
"node": "08 | Log \u2014 Order Received",
"type": "main",
"index": 0
}
]
]
},
"13 | Update Order (completed)": {
"main": [
[
{
"node": "14 | Log \u2014 Payment Success",
"type": "main",
"index": 0
}
]
]
},
"11 | Evaluate Payment Response": {
"main": [
[
{
"node": "12 | Payment Successful?",
"type": "main",
"index": 0
}
]
]
},
"20 | Send Failure Alert (Slack)": {
"main": [
[
{
"node": "21 | Respond \u2014 502 Failed",
"type": "main",
"index": 0
}
],
[
{
"node": "20a | Log Slack Error",
"type": "main",
"index": 0
}
]
]
},
"10 | Create Payment Intent (Demo)": {
"main": [
[
{
"node": "11 | Evaluate Payment Response",
"type": "main",
"index": 0
}
],
[
{
"node": "10a | Log Payment Gateway Error",
"type": "main",
"index": 0
}
]
]
},
"15 | Send Success Receipt (Gmail)": {
"main": [
[
{
"node": "16 | Respond \u2014 200 Success",
"type": "main",
"index": 0
}
],
[
{
"node": "15a | Log Email Error",
"type": "main",
"index": 0
}
]
]
}
}
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
gmailOAuth2googleSheetsOAuth2ApislackOAuth2Api
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow receives order requests from a Lovable app via webhook, validates and deduplicates them in Google Sheets, simulates a Stripe payment intent, and then sends a Gmail receipt on success or posts a Slack alert on failure, while logging events and errors to Sheets.…
Source: https://n8n.io/workflows/17751/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
This n8n template demonstrates how to automate the followup when your customer completes a checkout in Stripe by emailing a receipt, logging the transaction, and sending an internal notification.
This workflow automates inventory management and predictive reordering for Shopify stores. It integrates Shopify, Google Sheets, and Slack to monitor inventory levels, calculate dynamic reorder points
This workflow provides a robust, end-to-end automated pipeline for managing e-commerce orders. It bridges the gap between your storefront and your fulfillment team by handling inventory validation, mu
E-commerce store owners and sales managers who want AI-powered insights from their Shopify data without manually crunching numbers every week.
This template automates Shopify abandoned cart recovery with a 3-email Gmail sequence, tracks recoveries in Google Sheets via Shopify “order paid” webhooks, and sends a weekly HTML performance report