{
  "name": "Weekly Outbound Campaign Report",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks",
              "triggerAtDay": 1,
              "triggerAtHour": 9
            }
          ]
        }
      },
      "id": "cron-trigger",
      "name": "Every Monday 9 AM",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [240, 300]
    },
    {
      "parameters": {
        "method": "GET",
        "url": "https://api.instantly.ai/api/v2/campaigns",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "limit",
              "value": "100"
            },
            {
              "name": "status",
              "value": "1"
            }
          ]
        },
        "options": {}
      },
      "id": "get-campaigns",
      "name": "Get Active Campaigns",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [460, 300],
      "credentials": {
        "httpHeaderAuth": {
          "id": "YOUR_CREDENTIAL_ID",
          "name": "Instantly API Key — REPLACE THIS"
        }
      },
      "notes": "Replace credential with your Instantly API key. Header name: Authorization, Value: Bearer YOUR_API_KEY"
    },
    {
      "parameters": {
        "fieldToSplitOut": "items",
        "options": {}
      },
      "id": "split-campaigns",
      "name": "Split Campaigns",
      "type": "n8n-nodes-base.splitOut",
      "typeVersion": 1,
      "position": [680, 300]
    },
    {
      "parameters": {
        "method": "GET",
        "url": "=https://api.instantly.ai/api/v2/campaigns/{{ $json.id }}/analytics",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "options": {}
      },
      "id": "get-analytics",
      "name": "Get Campaign Analytics",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [900, 300],
      "credentials": {
        "httpHeaderAuth": {
          "id": "YOUR_CREDENTIAL_ID",
          "name": "Instantly API Key — REPLACE THIS"
        }
      },
      "notes": "[VERIFY] Check the exact analytics endpoint path in Instantly v2 docs. The campaign analytics endpoint may require different query params."
    },
    {
      "parameters": {
        "jsCode": "// Aggregate metrics across all campaigns\nconst items = $input.all();\n\nlet totalSent = 0;\nlet totalOpened = 0;\nlet totalReplied = 0;\nlet totalBounced = 0;\nlet campaignSummaries = [];\n\nfor (const item of items) {\n  const data = item.json;\n  const sent = data.emails_sent_count || 0;\n  const opened = data.emails_opened_count || 0;\n  const replied = data.emails_replied_count || 0;\n  const bounced = data.emails_bounced_count || 0;\n  \n  totalSent += sent;\n  totalOpened += opened;\n  totalReplied += replied;\n  totalBounced += bounced;\n  \n  campaignSummaries.push({\n    name: data.campaign_name || data.name || 'Unknown',\n    sent,\n    opened,\n    replied,\n    bounced,\n    openRate: sent > 0 ? ((opened / sent) * 100).toFixed(1) + '%' : '0%',\n    replyRate: sent > 0 ? ((replied / sent) * 100).toFixed(1) + '%' : '0%'\n  });\n}\n\nconst overallOpenRate = totalSent > 0 ? ((totalOpened / totalSent) * 100).toFixed(1) : '0';\nconst overallReplyRate = totalSent > 0 ? ((totalReplied / totalSent) * 100).toFixed(1) : '0';\nconst overallBounceRate = totalSent > 0 ? ((totalBounced / totalSent) * 100).toFixed(1) : '0';\n\n// Build summary text\nlet summary = `*Weekly Outbound Report*\\n`;\nsummary += `_${new Date().toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' })}_\\n\\n`;\nsummary += `*Overall Metrics*\\n`;\nsummary += `Emails Sent: ${totalSent.toLocaleString()}\\n`;\nsummary += `Opened: ${totalOpened.toLocaleString()} (${overallOpenRate}%)\\n`;\nsummary += `Replied: ${totalReplied.toLocaleString()} (${overallReplyRate}%)\\n`;\nsummary += `Bounced: ${totalBounced.toLocaleString()} (${overallBounceRate}%)\\n\\n`;\n\nif (parseFloat(overallBounceRate) > 2) {\n  summary += `⚠ Bounce rate above 2%. Check your lists.\\n\\n`;\n}\n\nsummary += `*By Campaign*\\n`;\nfor (const c of campaignSummaries) {\n  summary += `• ${c.name}: ${c.sent} sent, ${c.openRate} open, ${c.replyRate} reply\\n`;\n}\n\nreturn [{ json: { summary, totalSent, totalOpened, totalReplied, totalBounced, overallOpenRate, overallReplyRate, overallBounceRate, campaigns: campaignSummaries } }];"
      },
      "id": "format-report",
      "name": "Format Report",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [1120, 300]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "YOUR_SLACK_WEBHOOK_URL",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ text: $json.summary }) }}",
        "options": {}
      },
      "id": "send-slack",
      "name": "Send to Slack",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [1340, 200],
      "notes": "Replace YOUR_SLACK_WEBHOOK_URL with your Slack incoming webhook URL. Create one at https://api.slack.com/messaging/webhooks"
    },
    {
      "parameters": {
        "fromEmail": "your@email.com",
        "toEmail": "your@email.com",
        "subject": "=Weekly Outbound Report — {{ new Date().toLocaleDateString() }}",
        "emailType": "text",
        "message": "={{ $json.summary.replace(/\\*/g, '').replace(/_/g, '') }}"
      },
      "id": "send-email",
      "name": "Send Email (Optional)",
      "type": "n8n-nodes-base.emailSend",
      "typeVersion": 2.1,
      "position": [1340, 400],
      "notes": "Optional: sends the same report via email. Configure your SMTP credentials in n8n first."
    }
  ],
  "connections": {
    "Every Monday 9 AM": {
      "main": [
        [
          {
            "node": "Get Active Campaigns",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Active Campaigns": {
      "main": [
        [
          {
            "node": "Split Campaigns",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Campaigns": {
      "main": [
        [
          {
            "node": "Get Campaign Analytics",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Campaign Analytics": {
      "main": [
        [
          {
            "node": "Format Report",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Report": {
      "main": [
        [
          {
            "node": "Send to Slack",
            "type": "main",
            "index": 0
          },
          {
            "node": "Send Email (Optional)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "meta": {
    "templateCredsSetupCompleted": false,
    "instanceId": "say2neeraj-template"
  },
  "_comment": "SETUP INSTRUCTIONS: 1) Import this workflow into n8n. 2) Replace YOUR_CREDENTIAL_ID with your Instantly API key credential. 3) Replace YOUR_SLACK_WEBHOOK_URL with your Slack webhook. 4) Test with a manual trigger first. 5) Activate the workflow. [VERIFY] Instantly v2 analytics endpoint path — check docs.instantly.ai for the current API reference."
}
