AutomationFlowsMarketing & Ads › CRM Outreach Engine V2 (api-based)

CRM Outreach Engine V2 (api-based)

CRM Outreach Engine v2 (API-Based). Uses httpRequest, errorTrigger. Scheduled trigger; 18 nodes.

Cron / scheduled trigger★★★★☆ complexity18 nodesHTTP RequestError Trigger
Marketing & Ads Trigger: Cron / scheduled Nodes: 18 Complexity: ★★★★☆ Added:

This workflow follows the Error Trigger → HTTP Request recipe pattern — see all workflows that pair these two integrations.

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": "CRM Outreach Engine v2 (API-Based)",
  "nodes": [
    {
      "parameters": {
        "content": "## CRM Outreach Engine v2\n\n**Substitui o workflow MySQL legado por chamadas \u00e0 API do CRM.**\n\n### M\u00f3dulos:\n- **M\u00f3dulo 1 - Importa\u00e7\u00e3o**: Schedule 8h + Manual \u2192 Apify \u2192 POST /customers/import\n- **M\u00f3dulo 2 - Segmenta\u00e7\u00e3o**: Schedule a cada 2h \u2192 POST /outreach/segment\n- **M\u00f3dulo 3 - Envio**: Schedule 9h, 14h, 18h \u2192 POST /outreach/send\n- **Error Handler**: Captura erros globais\n\n### Autentica\u00e7\u00e3o (API Key est\u00e1tica \u2014 N\u00c3O usa JWT):\nCrie uma credencial **Header Auth** no n8n com nome exato `CRM API Key`:\n- **Header Name**: `X-Api-Key`\n- **Header Value**: (ver secret DIAX_SERVICE_API_KEY no GitHub / AWS SM)\n\n> \u26a0\ufe0f N\u00c3O use `Authorization: Bearer <jwt>`. JWTs expiram em 60min e quebram o agendamento.\n> A API aceita `X-Api-Key` com uma chave est\u00e1tica para automa\u00e7\u00f5es M2M.\n\n**API Base:** `https://api.alexandrequeiroz.com.br/api/v1`",
        "height": 320,
        "width": 460,
        "color": 5
      },
      "id": "sticky-readme",
      "name": "Leia-me",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -480,
        -120
      ]
    },
    {
      "parameters": {
        "content": "### M\u00f3dulo 1: Importa\u00e7\u00e3o\nTrigger: Di\u00e1rio \u00e0s 8h + Manual\n1. Busca config (URL do Apify dataset)\n2. Baixa dados do Apify\n3. Normaliza para BulkImportRequest\n4. POST /customers/import",
        "height": 180,
        "width": 280,
        "color": 6
      },
      "id": "sticky-mod1",
      "name": "Nota - M\u00f3dulo 1",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -480,
        240
      ]
    },
    {
      "parameters": {
        "content": "### M\u00f3dulo 2: Segmenta\u00e7\u00e3o\nTrigger: A cada 2 horas\nSegmenta leads HOT/WARM/COLD via\nPOST /outreach/segment",
        "height": 140,
        "width": 280,
        "color": 4
      },
      "id": "sticky-mod2",
      "name": "Nota - M\u00f3dulo 2",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -480,
        460
      ]
    },
    {
      "parameters": {
        "content": "### M\u00f3dulo 3: Envio de Campanha\nTrigger: 9h, 14h e 18h\nCria e enfileira campanha via\nPOST /outreach/send",
        "height": 140,
        "width": 280,
        "color": 3
      },
      "id": "sticky-mod3",
      "name": "Nota - M\u00f3dulo 3",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -480,
        640
      ]
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 8 * * *"
            }
          ]
        }
      },
      "id": "trigger-import-schedule",
      "name": "Schedule - Importa\u00e7\u00e3o (8h)",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.1,
      "position": [
        60,
        280
      ]
    },
    {
      "parameters": {},
      "id": "trigger-import-manual",
      "name": "Manual - Importa\u00e7\u00e3o",
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        60,
        420
      ]
    },
    {
      "parameters": {
        "method": "GET",
        "url": "https://api.alexandrequeiroz.com.br/api/v1/outreach/config",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "options": {}
      },
      "id": "http-get-config",
      "name": "GET /outreach/config",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        320,
        350
      ],
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "method": "GET",
        "url": "={{ $json.apifyDatasetUrl }}",
        "options": {
          "response": {
            "response": {
              "responseFormat": "json"
            }
          }
        }
      },
      "id": "http-get-apify",
      "name": "GET Apify Dataset",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        580,
        350
      ]
    },
    {
      "parameters": {
        "jsCode": "// Normaliza os itens do Apify para o formato BulkImportRequest do CRM\nconst apifyItems = $input.all();\n\nfunction extractWhatsApp(phone) {\n  if (!phone) return null;\n  // Tenta extrair de URLs wa.me/5511...\n  const waMatch = phone.match(/wa\\.me\\/(\\d+)/);\n  if (waMatch) return '+' + waMatch[1];\n  // Limpa o n\u00famero e assume que \u00e9 WhatsApp se tiver DDD v\u00e1lido\n  const cleaned = phone.replace(/[^0-9+]/g, '');\n  if (cleaned.length >= 10) return cleaned.startsWith('+') ? cleaned : '+55' + cleaned.replace(/^0/, '');\n  return null;\n}\n\nfunction cleanPhone(phone) {\n  if (!phone) return null;\n  const cleaned = phone.replace(/[^0-9+]/g, '');\n  if (cleaned.length < 8) return null;\n  return cleaned.startsWith('+') ? cleaned : '+55' + cleaned.replace(/^0/, '');\n}\n\nconst customers = apifyItems.map(item => {\n  const d = item.json;\n  const email = Array.isArray(d.emails) && d.emails.length > 0 ? d.emails[0] : null;\n  const phone = cleanPhone(d.phone);\n  const whatsApp = extractWhatsApp(d.phone) || phone;\n\n  // Monta tags: cidade + categoria\n  const tagParts = [];\n  if (d.city) tagParts.push(d.city.toLowerCase().replace(/\\s+/g, '-'));\n  if (d.categoryName) tagParts.push(d.categoryName.toLowerCase().replace(/\\s+/g, '-'));\n  if (d.website) tagParts.push('tem-site');\n  else tagParts.push('sem-site');\n  tagParts.push('google-maps');\n\n  // Monta notes com contexto do lead\n  const notesParts = [];\n  if (d.address) notesParts.push(`Endere\u00e7o: ${d.address}`);\n  if (d.totalScore) notesParts.push(`Avalia\u00e7\u00e3o Google: ${d.totalScore}`);\n  if (d.reviewsCount) notesParts.push(`Reviews: ${d.reviewsCount}`);\n  if (d.website) notesParts.push(`Site: ${d.website}`);\n\n  return {\n    name: d.title || d.name || 'Sem nome',\n    email: email,\n    phone: phone,\n    whatsApp: whatsApp,\n    companyName: d.title || d.name || null,\n    website: d.website || null,\n    tags: tagParts.join(','),\n    notes: notesParts.join(' | ') || null\n  };\n}).filter(c => c.name && c.name !== 'Sem nome' && (c.phone || c.email));\n\nif (customers.length === 0) {\n  return [{ json: { skipped: true, reason: 'Nenhum lead v\u00e1lido encontrado no dataset Apify' } }];\n}\n\nreturn [{\n  json: {\n    customers: customers,\n    source: 11\n  }\n}];"
      },
      "id": "code-normalize-apify",
      "name": "Normalizar Dados Apify",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        840,
        350
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.alexandrequeiroz.com.br/api/v1/customers/import",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "contentType": "json",
        "body": "={{ JSON.stringify($json) }}",
        "options": {}
      },
      "id": "http-post-import",
      "name": "POST /customers/import",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1100,
        350
      ],
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours",
              "hoursInterval": 2
            }
          ]
        }
      },
      "id": "trigger-segmentation",
      "name": "Schedule - Segmenta\u00e7\u00e3o (2h)",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.1,
      "position": [
        60,
        560
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.alexandrequeiroz.com.br/api/v1/outreach/segment",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "options": {}
      },
      "id": "http-post-segment",
      "name": "POST /outreach/segment",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        320,
        560
      ],
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const result = $input.first().json;\nconsole.log(`[Segmenta\u00e7\u00e3o] Total: ${result.totalProcessed} | HOT: ${result.hotCount} | WARM: ${result.warmCount} | COLD: ${result.coldCount}`);\nreturn [{ json: { success: true, result } }];"
      },
      "id": "code-log-segmentation",
      "name": "Log Segmenta\u00e7\u00e3o",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        580,
        560
      ]
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 9,14,18 * * *"
            }
          ]
        }
      },
      "id": "trigger-send",
      "name": "Schedule - Envio (9h, 14h, 18h)",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.1,
      "position": [
        60,
        740
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.alexandrequeiroz.com.br/api/v1/outreach/send",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "options": {}
      },
      "id": "http-post-send",
      "name": "POST /outreach/send",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        320,
        740
      ],
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const result = $input.first().json;\nconst campaignId = result.campaignId || 'N/A';\nconst queued = result.queuedCount ?? 0;\nconst skipped = result.skippedCount ?? 0;\nconsole.log(`[Envio de Campanha] CampaignId: ${campaignId} | Enfileirados: ${queued} | Pulados: ${skipped}`);\nif (result.skippedReasons && result.skippedReasons.length > 0) {\n  console.log(`[Envio de Campanha] Motivos pulados: ${result.skippedReasons.join('; ')}`);\n}\nreturn [{ json: { success: true, campaignId, queued, skipped, result } }];"
      },
      "id": "code-log-send",
      "name": "Log Envio",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        580,
        740
      ]
    },
    {
      "parameters": {},
      "id": "trigger-error",
      "name": "Error Trigger",
      "type": "n8n-nodes-base.errorTrigger",
      "typeVersion": 1,
      "position": [
        60,
        940
      ]
    },
    {
      "parameters": {
        "jsCode": "const error = $input.first().json;\nconst workflow = error.workflow?.name || 'Desconhecido';\nconst node = error.execution?.lastNodeExecuted || 'Desconhecido';\nconst errorMsg = error.execution?.error?.message || JSON.stringify(error);\nconst execId = error.execution?.id || 'N/A';\n\nconsole.error(`[ERRO] Workflow: ${workflow}`);\nconsole.error(`[ERRO] N\u00f3: ${node}`);\nconsole.error(`[ERRO] Execu\u00e7\u00e3o ID: ${execId}`);\nconsole.error(`[ERRO] Mensagem: ${errorMsg}`);\n\n// Retorna resumo do erro para poss\u00edvel integra\u00e7\u00e3o futura (ex: Slack, email)\nreturn [{\n  json: {\n    alertType: 'workflow_error',\n    workflow,\n    node,\n    execId,\n    errorMsg,\n    timestamp: new Date().toISOString()\n  }\n}];"
      },
      "id": "code-error-handler",
      "name": "Tratar Erro",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        320,
        940
      ]
    }
  ],
  "connections": {
    "Schedule - Importa\u00e7\u00e3o (8h)": {
      "main": [
        [
          {
            "node": "GET /outreach/config",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Manual - Importa\u00e7\u00e3o": {
      "main": [
        [
          {
            "node": "GET /outreach/config",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "GET /outreach/config": {
      "main": [
        [
          {
            "node": "GET Apify Dataset",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "GET Apify Dataset": {
      "main": [
        [
          {
            "node": "Normalizar Dados Apify",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalizar Dados Apify": {
      "main": [
        [
          {
            "node": "POST /customers/import",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule - Segmenta\u00e7\u00e3o (2h)": {
      "main": [
        [
          {
            "node": "POST /outreach/segment",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "POST /outreach/segment": {
      "main": [
        [
          {
            "node": "Log Segmenta\u00e7\u00e3o",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule - Envio (9h, 14h, 18h)": {
      "main": [
        [
          {
            "node": "POST /outreach/send",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "POST /outreach/send": {
      "main": [
        [
          {
            "node": "Log Envio",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Error Trigger": {
      "main": [
        [
          {
            "node": "Tratar Erro",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1",
    "saveManualExecutions": true,
    "saveDataErrorExecution": "all",
    "saveDataSuccessExecution": "last",
    "callerPolicy": "workflowsFromSameOwner",
    "errorWorkflow": ""
  },
  "meta": {
    "templateCredsSetupCompleted": false,
    "notes": "ACAO NECESSARIA: Configurar credencial 'CRM API Key' no n8n com Header=X-Api-Key e Value=<DIAX_SERVICE_API_KEY>"
  }
}

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

CRM Outreach Engine v2 (API-Based). Uses httpRequest, errorTrigger. Scheduled trigger; 18 nodes.

Source: https://github.com/xandeq/diax-crm/blob/af683dd93a91539402592fd9fb178ccfbd439c7c/n8n-workflows/email-marketing-v2.json — original creator credit. Request a take-down →

More Marketing & Ads workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Marketing & Ads

Workflow A — WhatsApp Lead Intake & Qualification. Uses postgres, httpRequest, errorTrigger. Scheduled trigger; 67 nodes.

Postgres, HTTP Request, Error Trigger
Marketing & Ads

This automation creates a seamless daily pipeline that: Pulls yesterday's website visitors from Leadfeeder Enriches company data using Apollo.io's powerful database Delivers enriched leads to your Goo

HTTP Request, Google Sheets, Error Trigger +1
Marketing & Ads

Build authentic Reddit presence and generate qualified leads through AI-powered community engagement that provides genuine value without spam or promotion.

HTTP Request, Reddit
Marketing & Ads

Ghost Rider CRM Import (Lead Processor). Uses httpRequest. Scheduled trigger; 40 nodes.

HTTP Request
Marketing & Ads

This workflow runs on scheduled weekly and monthly triggers to generate unified marketing performance reports. It processes multiple websites by collecting analytics data, paid ads performance, and CR

Gmail, Google Sheets, Google Analytics +3