{
  "name": "FlowPantry - Overdue invoice reminders (Day 7 / 14 / 30)",
  "nodes": [
    {
      "id": "8ac7a834-3c8b-4662-870c-394a9aad79be",
      "name": "Schedule",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        0,
        300
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "days",
              "daysInterval": 1,
              "triggerAtHour": 9
            }
          ]
        }
      }
    },
    {
      "id": "4b5ced8c-8c49-4539-9e1f-7cbd4794a43b",
      "name": "Get open invoices",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        240,
        300
      ],
      "parameters": {
        "url": "={{$env.INVOICES_URL}}",
        "options": {}
      }
    },
    {
      "id": "5559a6f8-d873-4bf3-be6e-213e7a7aaf9b",
      "name": "Pick reminder stage",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        480,
        300
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "language": "javaScript",
        "jsCode": "const out=[];\nfor(const i of $input.all()){\n  const rows=Array.isArray(i.json)?i.json:(i.json.data||i.json.invoices||[i.json]);\n  for(const inv of rows){\n    const status=String(inv.status||'').toLowerCase();\n    if(['paid','void','cancelled','canceled','draft'].includes(status)) continue;\n    if(!inv.email||!inv.due_date) continue;\n    const due=new Date(inv.due_date); due.setHours(0,0,0,0);\n    const today=new Date(); today.setHours(0,0,0,0);\n    const days=Math.floor((today-due)/864e5);\n    const stage=Number(inv.reminder_stage||0);\n    let next=null;\n    if(days>=30 && stage<30) next=30;\n    else if(days>=14 && stage<14) next=14;\n    else if(days>=7 && stage<7) next=7;\n    if(!next) continue;\n    const name=(inv.customer_name||'there').split(' ')[0];\n    const amt=inv.amount!=null?String(inv.amount):'';\n    const pay=inv.payment_url||'';\n    const biz=$env.BUSINESS_NAME||'YOUR BUSINESS';\n    let subject,body;\n    if(next===7){\n      subject=`Friendly reminder: invoice #${inv.id} from ${biz}`;\n      body=`Hi ${name},\\n\\nJust a friendly reminder that invoice #${inv.id}${amt?' for $'+amt:''} was due on ${inv.due_date}. You can pay here: ${pay}\\n\\nReply to this email if you have a question.\\n\\n\u2014 ${biz}`;\n    }else if(next===14){\n      subject=`Invoice #${inv.id} is past due`;\n      body=`Hi ${name},\\n\\nInvoice #${inv.id}${amt?' for $'+amt:''} is now ${days} days past due. Please pay at your earliest convenience: ${pay}\\n\\nIf you've already paid, thank you \u2014 just reply so we can update our records.\\n\\n\u2014 ${biz}`;\n    }else{\n      subject=`Final notice: invoice #${inv.id}`;\n      body=`Hi ${name},\\n\\nThis is a final notice that invoice #${inv.id}${amt?' for $'+amt:''} is ${days} days overdue. Please pay here: ${pay}\\n\\nIf we don't hear from you, we'll follow up by phone.\\n\\n\u2014 ${biz}`;\n    }\n    out.push({json:{...inv,days_overdue:days,next_stage:next,subject,body,first:name}});\n  }\n}\nreturn out;"
      }
    },
    {
      "id": "9d980967-f32d-4205-8b32-811daf0e2866",
      "name": "Stage switch",
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3.2,
      "position": [
        720,
        300
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict"
                },
                "conditions": [
                  {
                    "leftValue": "={{$json.next_stage}}",
                    "rightValue": 7,
                    "operator": {
                      "type": "number",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Day 7"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict"
                },
                "conditions": [
                  {
                    "leftValue": "={{$json.next_stage}}",
                    "rightValue": 14,
                    "operator": {
                      "type": "number",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Day 14"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict"
                },
                "conditions": [
                  {
                    "leftValue": "={{$json.next_stage}}",
                    "rightValue": 30,
                    "operator": {
                      "type": "number",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Day 30"
            }
          ]
        },
        "options": {}
      }
    },
    {
      "id": "d2122621-5ba8-49b0-991e-31bf00191284",
      "name": "Email day 7",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        960,
        120
      ],
      "parameters": {
        "method": "POST",
        "url": "https://api.resend.com/emails",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{JSON.stringify({from:$env.FROM_EMAIL,to:$json.email,subject:$json.subject,text:$json.body})}}",
        "options": {}
      }
    },
    {
      "id": "c71be5eb-f29d-417b-976f-1bcbeb6ec234",
      "name": "Email day 14",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        960,
        300
      ],
      "parameters": {
        "method": "POST",
        "url": "https://api.resend.com/emails",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{JSON.stringify({from:$env.FROM_EMAIL,to:$json.email,subject:$json.subject,text:$json.body})}}",
        "options": {}
      }
    },
    {
      "id": "2f52d07f-29db-4bf9-8dd3-f516833e6c48",
      "name": "Email day 30",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        960,
        480
      ],
      "parameters": {
        "method": "POST",
        "url": "https://api.resend.com/emails",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{JSON.stringify({from:$env.FROM_EMAIL,to:$json.email,subject:$json.subject,text:$json.body})}}",
        "options": {}
      }
    },
    {
      "id": "f74c2a6f-2f6e-472d-8115-6db5e5b0394f",
      "name": "Owner SMS day 30",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1200,
        480
      ],
      "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": "={{$env.OWNER_PHONE}}"
            },
            {
              "name": "From",
              "value": "={{$env.TWILIO_FROM_NUMBER}}"
            },
            {
              "name": "Body",
              "value": "=Invoice #{{$json.id}} for {{$json.customer_name}} ({{$json.amount}}) is {{$json.days_overdue}} days overdue. Call them."
            }
          ]
        },
        "options": {}
      }
    },
    {
      "id": "756df509-062c-4c2e-8972-601ee90edb71",
      "name": "Mark stage 7",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1200,
        120
      ],
      "parameters": {
        "method": "POST",
        "url": "={{$env.INVOICE_UPDATE_URL}}",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={JSON.stringify({id:$json.id,reminder_stage:7})}",
        "options": {}
      }
    },
    {
      "id": "196d0d9c-f491-4263-82d0-b68c1433834d",
      "name": "Mark stage 14",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1200,
        300
      ],
      "parameters": {
        "method": "POST",
        "url": "={{$env.INVOICE_UPDATE_URL}}",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={JSON.stringify({id:$json.id,reminder_stage:14})}",
        "options": {}
      }
    },
    {
      "id": "77e9ae34-58ed-4fb0-bd2d-e9549273feac",
      "name": "Mark stage 30",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1440,
        480
      ],
      "parameters": {
        "method": "POST",
        "url": "={{$env.INVOICE_UPDATE_URL}}",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={JSON.stringify({id:$json.id,reminder_stage:30})}",
        "options": {}
      }
    }
  ],
  "connections": {
    "Schedule": {
      "main": [
        [
          {
            "node": "Get open invoices",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get open invoices": {
      "main": [
        [
          {
            "node": "Pick reminder stage",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Pick reminder stage": {
      "main": [
        [
          {
            "node": "Stage switch",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Stage switch": {
      "main": [
        [
          {
            "node": "Email day 7",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Email day 14",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Email day 30",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Email day 7": {
      "main": [
        [
          {
            "node": "Mark stage 7",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Email day 14": {
      "main": [
        [
          {
            "node": "Mark stage 14",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Email day 30": {
      "main": [
        [
          {
            "node": "Owner SMS day 30",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Owner SMS day 30": {
      "main": [
        [
          {
            "node": "Mark stage 30",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "pinData": {}
}