{
  "name": "Carmentara \u2014 Shopify competitor app changes to Slack",
  "meta": {
    "templateCredsSetupCompleted": false,
    "description": "DRAFT only. Runs carmentara/shopify-app-intel (apps mode, onlyNew) daily and posts pricing/listing changes to Slack. Not published."
  },
  "settings": {
    "executionOrder": "v1"
  },
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 8 * * *"
            }
          ]
        }
      },
      "id": "sched-2",
      "name": "Schedule 08:00 daily",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        0,
        0
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.apify.com/v2/acts/carmentara~shopify-app-intel/runs",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "waitForFinish",
              "value": "180"
            },
            {
              "name": "memory",
              "value": "512"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "{\n  \"mode\": \"apps\",\n  \"appHandles\": [\n    \"klaviyo-email-marketing\",\n    \"omnisend\",\n    \"shopify-messaging\",\n    \"pushup-notification-marketing\",\n    \"carthike-recovery\"\n  ],\n  \"onlyNew\": true,\n  \"maxItems\": 20,\n  \"maxPpeChargeUSD\": 1.0\n}",
        "options": {}
      },
      "id": "apify-run-2",
      "name": "Run Shopify app intel",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        260,
        0
      ],
      "notes": "Edit appHandles to your competitors. onlyNew=true emits rows when pricingHash changed (or first seen). Auth: Bearer APIFY_TOKEN."
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "c2",
              "leftValue": "={{ $json.data.status }}",
              "rightValue": "SUCCEEDED",
              "operator": {
                "type": "string",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        }
      },
      "id": "if-ok-2",
      "name": "Run succeeded?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        520,
        0
      ]
    },
    {
      "parameters": {
        "method": "GET",
        "url": "=https://api.apify.com/v2/actor-runs/{{ $json.data.id }}/dataset/items?limit=50&clean=true",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "options": {}
      },
      "id": "fetch-ds-2",
      "name": "Fetch dataset items",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        780,
        -80
      ]
    },
    {
      "parameters": {
        "jsCode": "const items = $input.all().map(i => i.json);\nconst rows = items.length === 1 && Array.isArray(items[0]) ? items[0] : items;\nconst apps = rows.filter(r => r && (r.app || r.handle || r.mode === 'apps'));\nconst changed = apps.filter(r => {\n  const a = r.app || r;\n  return a.pricingChanged === true || r.pricingChanged === true;\n});\nconst focus = changed.length ? changed : apps;\nif (!focus.length) {\n  return [{ json: { text: ':white_check_mark: Shopify app watch: no competitor rows today.', count: 0 } }];\n}\nconst lines = focus.slice(0, 15).map((r, i) => {\n  const a = r.app || r;\n  const handle = a.handle || r.handle || '?';\n  const name = a.name || handle;\n  const url = a.url || `https://apps.shopify.com/${handle}`;\n  const plans = (a.pricingPlans || []).slice(0, 3).map(p => `${p.name}: ${p.price ?? '?'}${p.currency || ''}/${p.billingInterval || 'mo'}`).join(', ');\n  const flag = (a.pricingChanged === true) ? ' :rotating_light: pricing change' : '';\n  return `${i+1}. <${url}|${name}>${flag}\\n    ${plans || '(no plans parsed)'}`;\n});\nconst label = changed.length ? `${changed.length} pricing change(s)` : `${focus.length} snapshot(s) (first run or onlyNew off)`;\nconst text = `:shopping_trolley: *Shopify App Store \u2014 ${label}*\\n` + lines.join('\\n') + `\\n\\n_via Carmentara Shopify App Store Keyword Rank Tracker & Scraper_`;\nreturn [{ json: { text, count: focus.length } }];"
      },
      "id": "fmt-2",
      "name": "Format Slack message",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1040,
        -80
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "={{ $env.SLACK_WEBHOOK_URL }}",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ text: $json.text }) }}",
        "options": {}
      },
      "id": "slack-2",
      "name": "Post to Slack webhook",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1300,
        -80
      ]
    },
    {
      "parameters": {
        "jsCode": "const st = $json.data?.status || 'unknown';\nreturn [{ json: { text: `:warning: Shopify app-intel run did not succeed (status=${st}).` } }];"
      },
      "id": "fmt-fail-2",
      "name": "Format failure",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        780,
        120
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "={{ $env.SLACK_WEBHOOK_URL }}",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ text: $json.text }) }}",
        "options": {}
      },
      "id": "slack-fail-2",
      "name": "Slack failure alert",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1040,
        120
      ]
    }
  ],
  "connections": {
    "Schedule 08:00 daily": {
      "main": [
        [
          {
            "node": "Run Shopify app intel",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Run Shopify app intel": {
      "main": [
        [
          {
            "node": "Run succeeded?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Run succeeded?": {
      "main": [
        [
          {
            "node": "Fetch dataset items",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Format failure",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch dataset items": {
      "main": [
        [
          {
            "node": "Format Slack message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Slack message": {
      "main": [
        [
          {
            "node": "Post to Slack webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format failure": {
      "main": [
        [
          {
            "node": "Slack failure alert",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}