{
  "name": "FlowPantry - Two-step appointment reminders that cut no-shows",
  "nodes": [
    {
      "id": "a6985a24-5e9e-4ad4-91e9-7f16b250b148",
      "name": "Schedule",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        0,
        300
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours",
              "hoursInterval": 1
            }
          ]
        }
      }
    },
    {
      "id": "670a23da-0c8a-4537-894e-55fa9cbfa24f",
      "name": "Get upcoming appointments",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        240,
        300
      ],
      "parameters": {
        "url": "={{$env.APPOINTMENTS_URL}}",
        "options": {}
      }
    },
    {
      "id": "b1f4b899-d979-48ab-bf52-2884e4393405",
      "name": "Due for 24h or 2h reminder",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        480,
        300
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "language": "javaScript",
        "jsCode": "const s=$getWorkflowStaticData('global');s.sent=s.sent||{};const out=[];for(const i of $input.all()){const as=Array.isArray(i.json)?i.json:(i.json.collection||i.json.appointments||[i.json]);for(const a of as){if(!a.phone||!a.start)continue;const h=(new Date(a.start)-Date.now())/36e5;let k=null;if(h<=24&&h>23)k='24h';else if(h<=2&&h>1)k='2h';if(k&&!s.sent[a.id+k]){s.sent[a.id+k]=Date.now();const when=new Date(a.start).toLocaleString('en-US',{weekday:'short',hour:'numeric',minute:'2-digit'});out.push({json:{...a,kind:k,when,first:(a.name||'there').split(' ')[0]}});}}}return out;"
      }
    },
    {
      "id": "7004a262-d632-4a4e-87d3-1b0f139ecb96",
      "name": "Send reminder",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        720,
        300
      ],
      "parameters": {
        "method": "POST",
        "url": "=https://api.twilio.com/2010-04-01/Accounts/{{$env.TWILIO_ACCOUNT_SID}}/Messages.json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBasicAuth",
        "sendBody": true,
        "contentType": "form-urlencoded",
        "bodyParameters": {
          "parameters": [
            {
              "name": "To",
              "value": "={{$json.phone}}"
            },
            {
              "name": "From",
              "value": "={{$env.TWILIO_FROM_NUMBER}}"
            },
            {
              "name": "Body",
              "value": "={{$json.kind==='24h' ? 'Hi '+$json.first+', reminder: your appointment at '+$env.BUSINESS_NAME+' is '+$json.when+'. Reply C to confirm or call to reschedule.' : 'See you soon, '+$json.first+'! Your appointment at '+$env.BUSINESS_NAME+' starts at '+$json.when+'.'}}"
            }
          ]
        },
        "options": {}
      }
    }
  ],
  "connections": {
    "Schedule": {
      "main": [
        [
          {
            "node": "Get upcoming appointments",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get upcoming appointments": {
      "main": [
        [
          {
            "node": "Due for 24h or 2h reminder",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Due for 24h or 2h reminder": {
      "main": [
        [
          {
            "node": "Send reminder",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "pinData": {}
}