AutomationFlowsData & Sheets › Daily Churn Retention Actions - V9

Daily Churn Retention Actions - V9

Daily Churn Retention Actions - V9. Uses postgres, httpRequest, emailSend. Scheduled trigger; 13 nodes.

Cron / scheduled trigger★★★★☆ complexity13 nodesPostgresHTTP RequestEmail Send
Data & Sheets Trigger: Cron / scheduled Nodes: 13 Complexity: ★★★★☆ Added:

This workflow follows the Emailsend → HTTP Request recipe pattern — see all workflows that pair these two integrations.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "name": "Daily Churn Retention Actions - V9",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 2 * * *"
            }
          ]
        }
      },
      "id": "c192ba3b-7071-4d41-8ace-2c09a23329e0",
      "name": "Cron Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.1,
      "position": [
        -2320,
        864
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT *\nFROM churn_predictions\nWHERE send_action_flag = TRUE\nORDER BY churn_probability DESC\nLIMIT 10;",
        "options": {}
      },
      "id": "ed3ea43b-1303-4496-aa87-15c46c035128",
      "name": "Read Predictions",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        -2096,
        848
      ],
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      },
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "url": "http://127.0.0.1:62881/explainability/latest",
        "options": {}
      },
      "id": "675c0510-626b-40ca-8c38-83b1554d356e",
      "name": "Read SHAP Explainability",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.1,
      "position": [
        -2096,
        1024
      ]
    },
    {
      "parameters": {
        "mode": "combine",
        "fieldsToMatchString": "customer_unique_id",
        "options": {}
      },
      "id": "2b7c74f4-238e-460e-b4aa-c059d3107244",
      "name": "Merge Data",
      "type": "n8n-nodes-base.merge",
      "typeVersion": 3,
      "position": [
        -1664,
        944
      ]
    },
    {
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 1
                },
                "conditions": [
                  {
                    "leftValue": "={{ String($json.risk_tier || '').toUpperCase() }}",
                    "rightValue": "HIGH",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "high_risk"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 1
                },
                "conditions": [
                  {
                    "leftValue": "={{ String($json.risk_tier || '').toUpperCase() }}",
                    "rightValue": "MEDIUM",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "medium_risk"
            }
          ]
        },
        "options": {}
      },
      "id": "88f168f3-a1f6-4377-9cbc-901891761fc5",
      "name": "Risk Switch",
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3,
      "notes": "Portfolio senior uplift 2026-05-31: this switch now routes on canonical risk_tier emitted by the scoring lineage instead of recomputing tiers from hardcoded churn_probability thresholds. This removes silent scoring-vs-orchestration drift in the demo baseline.",
      "position": [
        -1456,
        944
      ]
    },
    {
      "parameters": {},
      "id": "4f36637c-379e-4f72-8eb3-abbe0b54735a",
      "name": "Merge Risks",
      "type": "n8n-nodes-base.merge",
      "typeVersion": 3,
      "position": [
        -1216,
        944
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "http://127.0.0.1:62881/coupons/generate",
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "customer_id",
              "value": "={{ $json.customer_unique_id }}"
            },
            {
              "name": "risk_level",
              "value": "={{ $json.risk_tier }}"
            },
            {
              "name": "discount_pct",
              "value": 20
            }
          ]
        },
        "options": {}
      },
      "id": "ce1ac59e-22ba-400d-968f-ad62eab957b3",
      "name": "Generate Coupon",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.1,
      "position": [
        -992,
        944
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 1
          },
          "conditions": [
            {
              "id": "check-coupon-code",
              "leftValue": "={{ $json.coupon_code }}",
              "rightValue": "",
              "operator": {
                "type": "string",
                "operation": "notEmpty"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "27b1e9ae-51d1-4e05-8fd1-3b9fbf6e85ff",
      "name": "Validate Pre-Send",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.1,
      "position": [
        -768,
        944
      ],
      "notes": "Validates that coupon_code, email, customer_id and first_name exist before firing any channel. TRUE branch \u2192 send. FALSE branch \u2192 log skipped record."
    },
    {
      "parameters": {
        "fromEmail": "architect.openclaw@gmail.com",
        "toEmail": "={{ $json.email }}",
        "subject": "Sentimos sua falta, {{ $json.first_name }}! \ud83c\udf81",
        "html": "=<p>Ol\u00e1, {{ $json.first_name }}!</p>\n<p>Sentimos a sua falta no VivaMarket. Preparamos uma oferta exclusiva para voc\u00ea:</p>\n<p style=\"font-size:1.4em; font-weight:bold;\">\ud83c\udf81 Use o cupom <span style=\"color:#E53935;\">{{ $json.coupon_code }}</span> e ganhe {{ $json.discount_pct }}% de desconto na sua pr\u00f3xima compra.</p>\n<p>O cupom \u00e9 v\u00e1lido por 7 dias. N\u00e3o perca!</p>\n<p>At\u00e9 breve,<br>Equipe VivaMarket</p>",
        "options": {}
      },
      "id": "b86cf74d-c128-4320-abc3-09f14b076012",
      "name": "Send Email",
      "type": "n8n-nodes-base.emailSend",
      "typeVersion": 2.1,
      "position": [
        -544,
        768
      ],
      "credentials": {
        "smtp": {
          "name": "<your credential>"
        }
      },
      "disabled": true
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://onesignal.com/api/v1/notifications",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "=Basic {{ $vars.ONE_SIGNAL_API_KEY }}"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"app_id\": \"b466045e-3354-4304-b99b-ada211caaee4\",\n  \"include_external_user_ids\": [\"{{ $json.customer_unique_id }}\"],\n  \"contents\": {\n    \"pt\": \"Temos uma oferta especial para voc\u00ea! Use o cupom {{ $json.coupon_code }} e ganhe {{ $json.discount_pct }}% de desconto.\",\n    \"en\": \"We have a special offer for you! Use coupon {{ $json.coupon_code }} and get {{ $json.discount_pct }}% off.\"\n  },\n  \"headings\": {\n    \"pt\": \"\ud83c\udf81 Oferta exclusiva VivaMarket\",\n    \"en\": \"\ud83c\udf81 Exclusive VivaMarket offer\"\n  }\n}",
        "options": {}
      },
      "id": "153edce9-a905-4b44-99f1-43af1d8cd8d0",
      "name": "Send Push",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.1,
      "position": [
        -544,
        944
      ],
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "notes": "FIX v6: OneSignal credentials now read from n8n Variables (ONE_SIGNAL_API_KEY, ONE_SIGNAL_APP_ID). $credentials.x syntax is not supported in HTTP Request nodes."
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "INSERT INTO retention_actions_skipped (customer_id, reason, skipped_at, churn_probability)\nVALUES ($1, 'missing_coupon_or_email', NOW(), $2);",
        "options": {
          "queryReplacement": "={{ [$json.customer_id, $json.churn_probability] }}"
        }
      },
      "id": "39392540-3d42-48dd-8953-48fd32ab601d",
      "name": "Log Skipped",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        -544,
        1120
      ],
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      },
      "onError": "continueErrorOutput",
      "notes": "FALSE branch from Validate Pre-Send. FIX v6: Added queryReplacement binding for $1=customer_id, $2=churn_probability. Success output is terminal \u2014 NOT connected to Error Handler."
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "INSERT INTO retention_actions (customer_id, risk_level, action_type, coupon_code, executed_at, churn_probability, send_action_flag)\nVALUES ($1, $2, $3, $4, NOW(), $5, TRUE);",
        "options": {
          "queryReplacement": "={{ [$json.customer_id, $json.risk_level, $json.action_type ?? 'email_push', $json.coupon_code, $json.churn_probability] }}"
        }
      },
      "id": "041b8e46-8790-4bff-b8f4-24c934e43d4c",
      "name": "Log Actions",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        -320,
        864
      ],
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      },
      "onError": "continueErrorOutput",
      "notes": "FIX v6: Added queryReplacement binding for all 5 parameters ($1=customer_id, $2=risk_level, $3=action_type, $4=coupon_code, $5=churn_probability)."
    },
    {
      "parameters": {
        "fieldToSplitOut": "records",
        "options": {}
      },
      "type": "n8n-nodes-base.splitOut",
      "typeVersion": 1,
      "position": [
        -1888,
        1024
      ],
      "id": "6f6c54a8-0b17-4d4e-bd2d-7c7e76716daf",
      "name": "Split Out"
    }
  ],
  "connections": {
    "Cron Trigger": {
      "main": [
        [
          {
            "node": "Read Predictions",
            "type": "main",
            "index": 0
          },
          {
            "node": "Read SHAP Explainability",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read Predictions": {
      "main": [
        [
          {
            "node": "Merge Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read SHAP Explainability": {
      "main": [
        [
          {
            "node": "Split Out",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge Data": {
      "main": [
        [
          {
            "node": "Risk Switch",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Risk Switch": {
      "main": [
        [
          {
            "node": "Merge Risks",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Merge Risks",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Merge Risks": {
      "main": [
        [
          {
            "node": "Generate Coupon",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Coupon": {
      "main": [
        [
          {
            "node": "Validate Pre-Send",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate Pre-Send": {
      "main": [
        [
          {
            "node": "Send Email",
            "type": "main",
            "index": 0
          },
          {
            "node": "Send Push",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Log Skipped",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Email": {
      "main": [
        [
          {
            "node": "Log Actions",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Push": {
      "main": [
        [
          {
            "node": "Log Actions",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Out": {
      "main": [
        [
          {
            "node": "Merge Data",
            "type": "main",
            "index": 1
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1",
    "binaryMode": "separate",
    "availableInMCP": false,
    "timeSavedMode": "fixed",
    "errorWorkflow": "5W6h4T8ck3na51md",
    "callerPolicy": "workflowsFromSameOwner"
  },
  "versionId": "559d07a2-3b99-4c80-a5e8-ebc32b6818a8",
  "id": "F6MT21Rkgr4BZvCT",
  "tags": []
}

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.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

Daily Churn Retention Actions - V9. Uses postgres, httpRequest, emailSend. Scheduled trigger; 13 nodes.

Source: https://github.com/albertosvallejo/daily-customer-churn-predictor/blob/main/n8n/n8n_workflow_daily_churn_retention_workflow.json — original creator credit. Request a take-down →

More Data & Sheets workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Data & Sheets

Disparador 1.8. Uses itemLists, postgres, emailSend, httpRequest. Scheduled trigger; 85 nodes.

Item Lists, Postgres, Email Send +1
Data & Sheets

This n8n workflow runs daily to analyze active customer behavior, engineers relevant features from usage and transaction data, applies a machine learning or AI-based model to predict churn probability

HTTP Request, Postgres, Email Send
Data & Sheets

This n8n workflow automates continuous compliance monitoring across IT, OT, and cloud environments by aggregating security controls, validating policies (ISO 27001, NIST, GDPR, SOC2), detecting anomal

HTTP Request, Postgres, Email Send
Data & Sheets

Automates real-time market monitoring, technical analysis, AI-powered signal generation for cryptocurrencies (and stocks), filters high-confidence trades, and delivers actionable alerts via multiple c

HTTP Request, Postgres, Email Send
Data & Sheets

HIPAA-Compliant Healthcare Data Synchronization. Uses httpRequest, postgres, mongoDb, elasticsearch. Scheduled trigger; 19 nodes.

HTTP Request, Postgres, MongoDB +3