AutomationFlowsData & Sheets › Automated 30-Min SMS Reminders

Automated 30-Min SMS Reminders

Original n8n title: Cron 30min SMS Reminder

cron-30min-sms-reminder. Uses postgres, twilio. Scheduled trigger; 7 nodes.

Cron / scheduled trigger★★★★☆ complexity7 nodesPostgresTwilio
Data & Sheets Trigger: Cron / scheduled Nodes: 7 Complexity: ★★★★☆ Added:

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": "cron-30min-sms-reminder",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "minutes",
              "minutesInterval": 10
            }
          ]
        }
      },
      "id": "cron-10min",
      "name": "Cron: Every 10 Minutes",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        100,
        300
      ],
      "notes": "Runs every 10 minutes. Catches appointments 25-35 minutes out."
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT a.id, a.customer_id, a.service_type, a.start_time, a.end_time, a.notes, c.name AS customer_name, c.phone AS customer_phone FROM appointments a JOIN customers c ON a.customer_id = c.id WHERE a.start_time >= NOW() + INTERVAL '25 minutes' AND a.start_time <= NOW() + INTERVAL '35 minutes' AND a.status = 'confirmed' AND a.id NOT IN ( SELECT (metadata->>'appointment_id')::uuid FROM analytics_events WHERE event_type = 'reminder_30min_sms_sent' AND created_at > NOW() - INTERVAL '1 hour' )",
        "options": {}
      },
      "id": "query-30min-appts",
      "name": "Supabase: Get 30min-Away Appointments",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [
        320,
        300
      ],
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "conditions": [
            {
              "leftValue": "={{ $json.length }}",
              "rightValue": 0,
              "operator": {
                "type": "number",
                "operation": "gt"
              }
            }
          ],
          "combinator": "and"
        }
      },
      "id": "if-has-30min",
      "name": "IF: Has Appointments?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        540,
        300
      ]
    },
    {
      "parameters": {
        "options": {}
      },
      "id": "split-30min",
      "name": "Split Into Batches",
      "type": "n8n-nodes-base.splitInBatches",
      "typeVersion": 3,
      "position": [
        760,
        260
      ]
    },
    {
      "parameters": {
        "jsCode": "const appt = $input.first().json;\nconst name = appt.customer_name?.split(' ')[0] || 'love';\nconst startDate = new Date(appt.start_time);\nconst timeStr = startDate.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit', hour12: true });\n\nconst smsBody = `\u23f0 ${name}, your appointment at Sweet Hand Braids is in about 30 minutes! (${timeStr})\\n\\nWe're getting everything ready for you! \ud83d\udc95\\n\\nRunning late? Just text us and we'll adjust.\\n\u2014 Sweet Hand Braids`;\n\nreturn [{ json: { smsBody, customer_phone: appt.customer_phone, appointment_id: appt.id, customer_id: appt.customer_id } }];"
      },
      "id": "build-30min-sms",
      "name": "Code: Build 30min SMS",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        980,
        260
      ]
    },
    {
      "parameters": {
        "resource": "message",
        "operation": "send",
        "from": "={{ $vars.TWILIO_PHONE_NUMBER }}",
        "to": "={{ $json.customer_phone }}",
        "body": "={{ $json.smsBody }}"
      },
      "id": "sms-30min",
      "name": "Twilio: Send 30min SMS",
      "type": "n8n-nodes-base.twilio",
      "typeVersion": 1,
      "position": [
        1200,
        260
      ],
      "credentials": {
        "twilioApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "INSERT INTO analytics_events (event_type, customer_id, channel, metadata) VALUES ('reminder_30min_sms_sent', '{{ $('Code: Build 30min SMS').first().json.customer_id }}', 'automated', '{{ JSON.stringify({ appointment_id: $('Code: Build 30min SMS').first().json.appointment_id }) }}')",
        "options": {}
      },
      "id": "log-30min",
      "name": "Supabase: Log 30min Sent",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [
        1420,
        260
      ],
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    }
  ],
  "connections": {
    "Cron: Every 10 Minutes": {
      "main": [
        [
          {
            "node": "Supabase: Get 30min-Away Appointments",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Supabase: Get 30min-Away Appointments": {
      "main": [
        [
          {
            "node": "IF: Has Appointments?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF: Has Appointments?": {
      "main": [
        [
          {
            "node": "Split Into Batches",
            "type": "main",
            "index": 0
          }
        ],
        []
      ]
    },
    "Split Into Batches": {
      "main": [
        [
          {
            "node": "Code: Build 30min SMS",
            "type": "main",
            "index": 0
          }
        ],
        []
      ]
    },
    "Code: Build 30min SMS": {
      "main": [
        [
          {
            "node": "Twilio: Send 30min SMS",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Twilio: Send 30min SMS": {
      "main": [
        [
          {
            "node": "Supabase: Log 30min Sent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Supabase: Log 30min Sent": {
      "main": [
        [
          {
            "node": "Split Into Batches",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1",
    "errorWorkflow": "sub-error-handler"
  },
  "tags": [
    {
      "name": "sweethandbraids"
    },
    {
      "name": "cron"
    },
    {
      "name": "reminders"
    }
  ]
}

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

cron-30min-sms-reminder. Uses postgres, twilio. Scheduled trigger; 7 nodes.

Source: https://github.com/rdmahpcengineer-gpu/sweethandbraidsMainProject/blob/9c327e7b2190848ae227fe277b0662173be78f38/n8n/cron-30min-sms.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

Send Sms Alerts Based On Database Queries Twilio And Postgres. Uses postgres, twilio. Scheduled trigger; 5 nodes.

Postgres, Twilio
Data & Sheets

Monitoring and alerting. Uses postgres, twilio. Scheduled trigger; 5 nodes.

Postgres, Twilio
Data & Sheets

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

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

공유회_알림톡_크론. Uses postgres, httpRequest, n8n-nodes-solapi. Scheduled trigger; 39 nodes.

Postgres, HTTP Request, N8N Nodes Solapi
Data & Sheets

QuepasaAutomatic. Uses postgres, postgresTrigger, httpRequest. Scheduled trigger; 39 nodes.

Postgres, Postgres Trigger, HTTP Request