This workflow follows the HTTP Request → Postgres 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 →
{
"name": "ITB SDR \u2014 MVP",
"nodes": [
{
"id": "note",
"name": "Card",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
-640,
160
],
"parameters": {
"color": 4,
"width": 380,
"height": 260,
"content": "## SDR-IA IT Booster\nWebhook SimplesZap \u2192 normaliza (texto/m\u00eddia) \u2192 config \u2192 cria lead \u2192 sauda\u00e7\u00e3o (novo) / m\u00eddia (pede texto) / agente DeepSeek.\nAgente decide A\u00c7\u00c3O: conversar | agendar (notifica Inael + call_agendada) | escalar (handoff + notifica).\nTudo parametriz\u00e1vel em itbooster_sdr_config."
}
},
{
"id": "wh",
"name": "1\u00b7 Webhook inbound",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
-240,
80
],
"parameters": {
"httpMethod": "POST",
"path": "itb-sdr/inbound",
"responseMode": "responseNode",
"options": {}
}
},
{
"id": "norm",
"name": "2\u00b7 Normalizar",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-40,
80
],
"parameters": {
"jsCode": "const h=$input.first().json.headers||{};\nconst b=$input.first().json.body||{};\nconst event=(h['x-webhook-event']||'').toString();\nconst isMessage=event==='message.received';\nconst mediaEvents=['message.audio.received','message.image.received','message.video.received','message.document.received','audio.received','image.received','video.received','document.received'];\nconst isMedia=mediaEvents.includes(event);\nlet phone=(b.from??b.number??'').toString().replace(/[^0-9]/g,'');\nif(phone.length===12&&phone.startsWith('55')) phone=phone.slice(0,4)+'9'+phone.slice(4);\nconst texto=isMessage?(b.text??'').toString():'';\nconst fromMe=Boolean(b.fromMe);\nconst isGroup=/@g\\.us/.test((b.from??'').toString());\nconst processar=((isMessage&&texto.length>0)||isMedia)&&!fromMe&&!isGroup;\nreturn [{json:{event,isMessage,isMedia,processar,phone,texto,tipo:(b.type??'text').toString(),messageId:(b.messageId??'').toString(),nome:(b.fromName??b.name??'').toString(),mediaUrl:(b.mediaUrl??'').toString(),ctwa_clid:(b.referral?.ctwa_clid??b.ctwa_clid??'').toString(),fbc:(b.fbc??'').toString(),fbp:(b.fbp??'').toString()}}];"
}
},
{
"id": "cfg",
"name": "0\u00b7 Config",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.6,
"position": [
160,
80
],
"parameters": {
"operation": "executeQuery",
"query": "select * from itbooster_sdr_config where id=1;",
"options": {}
},
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"id": "proc",
"name": "3\u00b7 Process\u00e1vel?",
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
360,
80
],
"parameters": {
"conditions": {
"options": {
"version": 2,
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"leftValue": "={{ $('2\u00b7 Normalizar').first().json.processar }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
}
}
]
},
"options": {}
}
},
{
"id": "ups",
"name": "4\u00b7 UPSERT lead",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.6,
"position": [
560,
60
],
"parameters": {
"operation": "executeQuery",
"query": "with up_lead as (\n insert into itbooster_sdr_leads (phone,nome,origem,status,ctwa_clid,fbc,fbp)\n values ('{{ $('2\u00b7 Normalizar').first().json.phone }}', $${{ $('2\u00b7 Normalizar').first().json.nome }}$$,'meta-ads','novo', nullif($${{ $('2\u00b7 Normalizar').first().json.ctwa_clid }}$$,''), nullif($${{ $('2\u00b7 Normalizar').first().json.fbc }}$$,''), nullif($${{ $('2\u00b7 Normalizar').first().json.fbp }}$$,''))\n on conflict (phone) do update set nome=coalesce(itbooster_sdr_leads.nome,excluded.nome), ctwa_clid=coalesce(itbooster_sdr_leads.ctwa_clid,excluded.ctwa_clid)\n returning id,(xmax=0) as created\n), up_conv as (\n insert into itbooster_sdr_conversations (phone,lead_id,current_step) select '{{ $('2\u00b7 Normalizar').first().json.phone }}',id,'NEW_LEAD' from up_lead on conflict (phone) do update set updated_at=now() returning is_ai_managed,current_step\n)\n select l.created,c.is_ai_managed,c.current_step,'{{ $('2\u00b7 Normalizar').first().json.phone }}' as phone, $${{ $('2\u00b7 Normalizar').first().json.texto }}$$ as texto, $${{ $('2\u00b7 Normalizar').first().json.isMedia }}$$ as ismedia from up_lead l cross join up_conv c;",
"options": {}
},
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"id": "ai",
"name": "5\u00b7 IA no controle?",
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
760,
60
],
"parameters": {
"conditions": {
"options": {
"version": 2,
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"leftValue": "={{ $json.is_ai_managed }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
}
}
]
},
"options": {}
}
},
{
"id": "ismedia",
"name": "6\u00b7 \u00c9 m\u00eddia?",
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
960,
60
],
"parameters": {
"conditions": {
"options": {
"version": 2,
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"leftValue": "={{ $('2\u00b7 Normalizar').first().json.isMedia }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
}
}
]
},
"options": {}
}
},
{
"id": "mreply",
"name": "7\u00b7 Resposta m\u00eddia",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1160,
-80
],
"parameters": {
"method": "POST",
"url": "={{ $('0\u00b7 Config').first().json.simpleszap_base_url }}/message/sendText/{{ $('0\u00b7 Config').first().json.simpleszap_instance_id }}",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"number\": \"{{ $('4\u00b7 UPSERT lead').first().json.phone }}\",\n \"text\": \"Recebi seu arquivo! \ud83d\ude4c Pra te ajudar certinho, me conta por texto rapidinho o que voc\u00ea precisa?\"\n}",
"options": {}
},
"credentials": {
"httpHeaderAuth": {
"name": "<your credential>"
}
}
},
{
"id": "mlog",
"name": "8\u00b7 Log m\u00eddia",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.6,
"position": [
1360,
-80
],
"parameters": {
"operation": "executeQuery",
"query": "insert into itbooster_sdr_messages (phone,direction,msg_type,body) values ('{{ $('4\u00b7 UPSERT lead').first().json.phone }}','in','{{ $('2\u00b7 Normalizar').first().json.tipo }}','[m\u00eddia recebida]'),('{{ $('4\u00b7 UPSERT lead').first().json.phone }}','out','text','pediu texto');",
"options": {}
},
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"id": "isaudio",
"name": "6b\u00b7 \u00c9 \u00e1udio?",
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
1160,
-280
],
"parameters": {
"conditions": {
"options": {
"version": 2,
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"leftValue": "={{ $('2\u00b7 Normalizar').first().json.tipo }}",
"rightValue": "audio",
"operator": {
"type": "string",
"operation": "equals"
}
}
]
},
"options": {}
}
},
{
"id": "tr1",
"name": "tr1\u00b7 Evolution \u00e1udio",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1360,
-360
],
"parameters": {
"method": "POST",
"url": "={{ $('0\u00b7 Config').first().json.evolution_base_url }}/chat/getBase64FromMediaMessage/{{ $('0\u00b7 Config').first().json.evolution_instance }}",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "apikey",
"value": "={{ $('0\u00b7 Config').first().json.evolution_apikey }}"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"message\": { \"key\": { \"id\": \"{{ $('2\u00b7 Normalizar').first().json.messageId }}\" } },\n \"convertToMp4\": false\n}",
"options": {}
}
},
{
"id": "tr2",
"name": "tr2\u00b7 Base64 p/ arquivo",
"type": "n8n-nodes-base.convertToFile",
"typeVersion": 1.1,
"position": [
1560,
-360
],
"parameters": {
"operation": "toBinary",
"sourceProperty": "base64",
"options": {
"fileName": "audio.ogg",
"mimeType": "audio/ogg"
}
}
},
{
"id": "tr3",
"name": "tr3\u00b7 Groq Whisper",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1760,
-360
],
"parameters": {
"method": "POST",
"url": "https://api.groq.com/openai/v1/audio/transcriptions",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "=Bearer {{ $('0\u00b7 Config').first().json.groq_api_key }}"
}
]
},
"sendBody": true,
"contentType": "multipart-form-data",
"bodyParameters": {
"parameters": [
{
"parameterType": "formBinaryData",
"name": "file",
"inputDataFieldName": "data"
},
{
"parameterType": "formData",
"name": "model",
"value": "whisper-large-v3"
}
]
},
"options": {}
}
},
{
"id": "tr4",
"name": "tr4\u00b7 Reinjeta texto",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1960,
-360
],
"parameters": {
"method": "POST",
"url": "https://n8n.toolpad.cloud/webhook/itb-sdr/inbound",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "x-webhook-event",
"value": "message.received"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"instanceId\": \"{{ $('0\u00b7 Config').first().json.simpleszap_instance_id }}\",\n \"messageId\": \"{{ $('2\u00b7 Normalizar').first().json.messageId }}-tr\",\n \"from\": \"{{ $('4\u00b7 UPSERT lead').first().json.phone }}\",\n \"fromName\": \"{{ $('2\u00b7 Normalizar').first().json.nome }}\",\n \"fromMe\": false,\n \"type\": \"text\",\n \"text\": {{ JSON.stringify($json.text) }}\n}",
"options": {}
}
},
{
"id": "isimg",
"name": "6c\u00b7 \u00c9 imagem?",
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
1360,
-160
],
"parameters": {
"conditions": {
"options": {
"version": 2,
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"leftValue": "={{ $('2\u00b7 Normalizar').first().json.tipo }}",
"rightValue": "image",
"operator": {
"type": "string",
"operation": "equals"
}
}
]
},
"options": {}
}
},
{
"id": "im1",
"name": "im1\u00b7 Evolution imagem",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1560,
-160
],
"parameters": {
"method": "POST",
"url": "={{ $('0\u00b7 Config').first().json.evolution_base_url }}/chat/getBase64FromMediaMessage/{{ $('0\u00b7 Config').first().json.evolution_instance }}",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "apikey",
"value": "={{ $('0\u00b7 Config').first().json.evolution_apikey }}"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"message\": { \"key\": { \"id\": \"{{ $('2\u00b7 Normalizar').first().json.messageId }}\" } }\n}",
"options": {}
}
},
{
"id": "im2",
"name": "im2\u00b7 Groq vis\u00e3o",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1760,
-160
],
"parameters": {
"method": "POST",
"url": "https://api.groq.com/openai/v1/chat/completions",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "=Bearer {{ $('0\u00b7 Config').first().json.groq_api_key }}"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"model\": \"meta-llama/llama-4-scout-17b-16e-instruct\",\n \"max_tokens\": 150,\n \"messages\": [{ \"role\": \"user\", \"content\": [ { \"type\": \"text\", \"text\": \"Descreva esta imagem em 1-2 frases curtas, em portugues, focando no que importa pra um negocio (print de tela, foto de produto, documento, etc).\" }, { \"type\": \"image_url\", \"image_url\": { \"url\": \"data:{{ ($json.mimetype||'image/jpeg').split(';')[0] }};base64,{{ $json.base64 }}\" } } ] }]\n}",
"options": {}
}
},
{
"id": "im3",
"name": "im3\u00b7 Reinjeta imagem",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1960,
-160
],
"parameters": {
"method": "POST",
"url": "https://n8n.toolpad.cloud/webhook/itb-sdr/inbound",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "x-webhook-event",
"value": "message.received"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"instanceId\": \"{{ $('0\u00b7 Config').first().json.simpleszap_instance_id }}\",\n \"messageId\": \"{{ $('2\u00b7 Normalizar').first().json.messageId }}-img\",\n \"from\": \"{{ $('4\u00b7 UPSERT lead').first().json.phone }}\",\n \"fromName\": \"{{ $('2\u00b7 Normalizar').first().json.nome }}\",\n \"fromMe\": false,\n \"type\": \"text\",\n \"text\": {{ JSON.stringify('[imagem] ' + ($json.choices[0].message.content||'')) }}\n}",
"options": {}
}
},
{
"id": "gcal",
"name": "18b\u00b7 Cria evento GCal",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
2560,
60
],
"parameters": {
"jsCode": "const crypto=require('crypto');const cfg=$('0\u00b7 Config').first().json;const r=$('15\u00b7 Ler resposta IA').first().json;let startD=new Date(r.slot);if(!r.slot||isNaN(startD.getTime())){startD=new Date(Date.now()+86400000);startD.setHours(13,0,0,0);}const start=startD.toISOString();const end=new Date(startD.getTime()+1800000).toISOString();const b64=(s)=>Buffer.from(s).toString('base64url');const now=Math.floor(Date.now()/1000);const si=b64(JSON.stringify({alg:'RS256',typ:'JWT'}))+'.'+b64(JSON.stringify({iss:cfg.gcal_sa_email,scope:'https://www.googleapis.com/auth/calendar',aud:'https://oauth2.googleapis.com/token',iat:now,exp:now+3600}));const signer=crypto.createSign('RSA-SHA256');signer.update(si);const jwt=si+'.'+signer.sign(cfg.gcal_sa_key).toString('base64url');const tok=await this.helpers.httpRequest({method:'POST',url:'https://oauth2.googleapis.com/token',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:'grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion='+jwt});const token=(typeof tok==='string'?JSON.parse(tok):tok).access_token;const meet='https://meet.jit.si/itbooster-'+r.phone;const ev={summary:'Call de diagnostico - lead '+r.phone,description:'Lead: '+r.phone+' | Segmento: '+(r.segmento||'')+' | Dor: '+(r.dor||'')+' | Link: '+meet,start:{dateTime:start,timeZone:'America/Sao_Paulo'},end:{dateTime:end,timeZone:'America/Sao_Paulo'}};const created=await this.helpers.httpRequest({method:'POST',url:'https://www.googleapis.com/calendar/v3/calendars/'+encodeURIComponent(cfg.gcal_calendar_id)+'/events',headers:{Authorization:'Bearer '+token,'Content-Type':'application/json'},body:ev,json:true});return [{json:{event_link:created.htmlLink||'',meet,start}}];"
}
},
{
"id": "novo",
"name": "9\u00b7 Lead novo?",
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
1160,
140
],
"parameters": {
"conditions": {
"options": {
"version": 2,
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"leftValue": "={{ $json.created }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
}
}
]
},
"options": {}
}
},
{
"id": "saud",
"name": "10\u00b7 Sauda\u00e7\u00e3o",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1360,
60
],
"parameters": {
"method": "POST",
"url": "={{ $('0\u00b7 Config').first().json.simpleszap_base_url }}/message/sendText/{{ $('0\u00b7 Config').first().json.simpleszap_instance_id }}",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"number\": \"{{ $json.phone }}\",\n \"text\": {{ JSON.stringify($('0\u00b7 Config').first().json.saudacao) }}\n}",
"options": {}
},
"credentials": {
"httpHeaderAuth": {
"name": "<your credential>"
}
}
},
{
"id": "slog",
"name": "11\u00b7 Log sauda\u00e7\u00e3o",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.6,
"position": [
1560,
60
],
"parameters": {
"operation": "executeQuery",
"query": "insert into itbooster_sdr_messages (phone,direction,msg_type,body) values ('{{ $('4\u00b7 UPSERT lead').first().json.phone }}','out','text', $${{ $('0\u00b7 Config').first().json.saudacao }}$$); update itbooster_sdr_conversations set current_step='OPENED', last_outbound_at=now() where phone='{{ $('4\u00b7 UPSERT lead').first().json.phone }}';",
"options": {}
},
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"id": "buf",
"name": "12\u00b7 Buffer (debounce)",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.6,
"position": [
1360,
420
],
"parameters": {
"operation": "executeQuery",
"query": "insert into itbooster_sdr_messages (phone,direction,msg_type,body) values ('{{ $('4\u00b7 UPSERT lead').first().json.phone }}','in','text', $${{ $('4\u00b7 UPSERT lead').first().json.texto }}$$); update itbooster_sdr_conversations set debounce_token='{{ $('2\u00b7 Normalizar').first().json.messageId }}' where phone='{{ $('4\u00b7 UPSERT lead').first().json.phone }}'; select 1;",
"options": {}
},
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"id": "wait",
"name": "12b\u00b7 Aguarda 8s",
"type": "n8n-nodes-base.wait",
"typeVersion": 1.1,
"position": [
1560,
420
],
"parameters": {
"amount": 10,
"unit": "seconds"
}
},
{
"id": "chk",
"name": "12c\u00b7 Checa \u00faltima",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.6,
"position": [
1760,
420
],
"parameters": {
"operation": "executeQuery",
"query": "select (debounce_token = '{{ $('2\u00b7 Normalizar').first().json.messageId }}') as latest from itbooster_sdr_conversations where phone='{{ $('4\u00b7 UPSERT lead').first().json.phone }}';",
"options": {}
},
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"id": "islast",
"name": "12d\u00b7 \u00c9 a \u00faltima?",
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
1960,
420
],
"parameters": {
"conditions": {
"options": {
"version": 2,
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"leftValue": "={{ $json.latest }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
}
}
]
},
"options": {}
}
},
{
"id": "hist",
"name": "12e\u00b7 Hist\u00f3rico",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.6,
"position": [
2160,
360
],
"parameters": {
"operation": "executeQuery",
"query": "select (select string_agg((case when direction='in' then 'Lead: ' else 'SDR: ' end)||body, E'\\n' order by created_at) from (select * from itbooster_sdr_messages where phone='{{ $('4\u00b7 UPSERT lead').first().json.phone }}' order by created_at desc limit 20) t) as historico, (select string_agg(body, E'\\n' order by created_at) from itbooster_sdr_messages where phone='{{ $('4\u00b7 UPSERT lead').first().json.phone }}' and direction='in' and created_at > coalesce((select last_outbound_at from itbooster_sdr_conversations where phone='{{ $('4\u00b7 UPSERT lead').first().json.phone }}'), to_timestamp(0))) as novas;",
"options": {}
},
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"id": "prompt",
"name": "13\u00b7 Montar prompt",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1560,
260
],
"parameters": {
"jsCode": "const cfg=$('0\u00b7 Config').first().json;\nconst phone=$('4\u00b7 UPSERT lead').first().json.phone;\nconst texto=($json.novas||$('4\u00b7 UPSERT lead').first().json.texto);\nconst hist=$json.historico||'';\nconst base=(cfg.prompt_compilado&&String(cfg.prompt_compilado).trim())?cfg.prompt_compilado:[cfg.persona||'',`Empresa: ${cfg.empresa||''}. Site: ${cfg.site||''}.`,`Objetivo: ${cfg.objetivo||''}`,`P\u00fablico: ${cfg.publico||''}`,`Qualifica\u00e7\u00e3o (uma pergunta por vez):\\n${cfg.perguntas||''}`,`Investimento: ${cfg.faixas||''}`,`Regras:\\n${cfg.regras||''}`,`NUNCA:\\n${cfg.nao_pode||''}`].join('\\n\\n');\nconst system=base+`\\n\\nDECIDA A A\u00c7\u00c3O no campo acao: 'conversar' (continuar qualificando), 'agendar' (o lead quer/aceitou uma call de diagn\u00f3stico \u2014 proponha ou confirme um dia/hor\u00e1rio e coloque em slot), 'escalar' (lead pede falar com humano, est\u00e1 irritado, ou foge muito do escopo). \\nResponda SEMPRE em JSON puro: reply, nome (o nome do cliente, se ele informar), status (novo|qualificando|qualificado), segmento, dor, objetivo, faixa_investimento, acao (conversar|agendar|escalar), slot (se acao=agendar, a data e hora em ISO 8601 com fuso -03:00, por exemplo 2026-06-30T10:00:00-03:00, calculada a partir de hoje que e ${new Date().toISOString().slice(0,10)}; senao vazio). Use string vazia no que nao souber.`;\nreturn [{json:{phone,modelo:cfg.modelo||'deepseek-chat',messages:[{role:'system',content:system},{role:'user',content:`Hist\u00f3rico:\\n${hist}\\n\\n\u00daltima mensagem do lead: ${texto}`}]}}];"
}
},
{
"id": "llm",
"name": "14\u00b7 DeepSeek",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1760,
260
],
"parameters": {
"method": "POST",
"url": "https://api.deepseek.com/v1/chat/completions",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"model\": {{ JSON.stringify($json.modelo) }},\n \"messages\": {{ JSON.stringify($json.messages) }},\n \"temperature\": 0.5,\n \"response_format\": { \"type\": \"json_object\" }\n}",
"options": {}
},
"credentials": {
"httpHeaderAuth": {
"name": "<your credential>"
}
}
},
{
"id": "parse",
"name": "15\u00b7 Ler resposta IA",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1960,
260
],
"parameters": {
"jsCode": "const phone=$('13\u00b7 Montar prompt').first().json.phone;\nlet o={};\ntry{o=JSON.parse($json.choices[0].message.content);}catch(e){o={reply:$json.choices?.[0]?.message?.content||'Pode me contar um pouco mais?'};}\nconst acao=['conversar','agendar','escalar'].includes(o.acao)?o.acao:'conversar';\nconst status=acao==='agendar'?'call_agendada':(o.status||'qualificando');\nreturn [{json:{phone,reply:o.reply||'Entendi! Me conta mais um pouco?',nome:o.nome||'',status,segmento:o.segmento||'',dor:o.dor||'',objetivo:o.objetivo||'',faixa_investimento:o.faixa_investimento||'',acao,slot:o.slot||''}}];"
}
},
{
"id": "upd",
"name": "16\u00b7 Atualiza lead",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.6,
"position": [
2160,
260
],
"parameters": {
"operation": "executeQuery",
"query": "update itbooster_sdr_leads set status='{{ $json.status }}', nome=coalesce(nullif($${{ $json.nome }}$$,''), nome), segmento=nullif($${{ $json.segmento }}$$,''), dor=nullif($${{ $json.dor }}$$,''), objetivo=nullif($${{ $json.objetivo }}$$,''), faixa_investimento=nullif($${{ $json.faixa_investimento }}$$,''), notas=nullif($${{ $json.slot }}$$,'') where phone='{{ $json.phone }}';",
"options": {}
},
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"id": "acao",
"name": "17\u00b7 A\u00e7\u00e3o?",
"type": "n8n-nodes-base.switch",
"typeVersion": 3.2,
"position": [
2360,
260
],
"parameters": {
"rules": {
"values": [
{
"outputKey": "agendar",
"conditions": {
"options": {
"version": 2,
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"leftValue": "={{ $('15\u00b7 Ler resposta IA').first().json.acao }}",
"rightValue": "agendar",
"operator": {
"type": "string",
"operation": "equals"
}
}
]
},
"renameOutput": true
},
{
"outputKey": "escalar",
"conditions": {
"options": {
"version": 2,
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"leftValue": "={{ $('15\u00b7 Ler resposta IA').first().json.acao }}",
"rightValue": "escalar",
"operator": {
"type": "string",
"operation": "equals"
}
}
]
},
"renameOutput": true
}
]
},
"options": {
"fallbackOutput": "extra"
}
}
},
{
"id": "mcall",
"name": "18\u00b7 Marca call agendada",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.6,
"position": [
2560,
140
],
"parameters": {
"operation": "executeQuery",
"query": "update itbooster_sdr_conversations set current_step='SCHEDULED' where phone='{{ $('15\u00b7 Ler resposta IA').first().json.phone }}'; select 1;",
"options": {}
},
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"id": "mhand",
"name": "19\u00b7 Marca handoff",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.6,
"position": [
2560,
300
],
"parameters": {
"operation": "executeQuery",
"query": "update itbooster_sdr_conversations set is_ai_managed=false, current_step='HUMAN' where phone='{{ $('15\u00b7 Ler resposta IA').first().json.phone }}'; select 1;",
"options": {}
},
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"id": "notify",
"name": "20\u00b7 Notifica Inael",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
2760,
220
],
"parameters": {
"method": "POST",
"url": "={{ $('0\u00b7 Config').first().json.simpleszap_base_url }}/message/sendText/{{ $('0\u00b7 Config').first().json.simpleszap_instance_id }}",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"number\": \"{{ $('0\u00b7 Config').first().json.notify_phone }}\",\n \"text\": {{ JSON.stringify('\ud83d\udd14 SDR ['+$('15\u00b7 Ler resposta IA').first().json.acao+'] lead '+$('15\u00b7 Ler resposta IA').first().json.phone+'\\nSegmento: '+$('15\u00b7 Ler resposta IA').first().json.segmento+'\\nDor: '+$('15\u00b7 Ler resposta IA').first().json.dor+($('15\u00b7 Ler resposta IA').first().json.slot?'\\nHor\u00e1rio: '+$('15\u00b7 Ler resposta IA').first().json.slot:'')) }}\n}",
"options": {}
},
"credentials": {
"httpHeaderAuth": {
"name": "<your credential>"
}
}
},
{
"id": "reply",
"name": "21\u00b7 Enviar resposta",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
2980,
260
],
"parameters": {
"method": "POST",
"url": "={{ $('0\u00b7 Config').first().json.simpleszap_base_url }}/message/sendText/{{ $('0\u00b7 Config').first().json.simpleszap_instance_id }}",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"number\": \"{{ $('15\u00b7 Ler resposta IA').first().json.phone }}\",\n \"text\": {{ JSON.stringify($('15\u00b7 Ler resposta IA').first().json.reply) }}\n}",
"options": {}
},
"credentials": {
"httpHeaderAuth": {
"name": "<your credential>"
}
}
},
{
"id": "olog",
"name": "22\u00b7 Log resposta",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.6,
"position": [
3180,
260
],
"parameters": {
"operation": "executeQuery",
"query": "insert into itbooster_sdr_messages (phone,direction,msg_type,body) values ('{{ $('15\u00b7 Ler resposta IA').first().json.phone }}','out','text', $${{ $('15\u00b7 Ler resposta IA').first().json.reply }}$$); update itbooster_sdr_conversations set last_outbound_at=now() where phone='{{ $('15\u00b7 Ler resposta IA').first().json.phone }}';",
"options": {}
},
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"id": "resp",
"name": "Responde 200",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.1,
"position": [
3380,
160
],
"parameters": {
"respondWith": "text",
"responseBody": "ok",
"options": {}
}
}
],
"connections": {
"1\u00b7 Webhook inbound": {
"main": [
[
{
"node": "2\u00b7 Normalizar",
"type": "main",
"index": 0
}
]
]
},
"2\u00b7 Normalizar": {
"main": [
[
{
"node": "0\u00b7 Config",
"type": "main",
"index": 0
}
]
]
},
"0\u00b7 Config": {
"main": [
[
{
"node": "3\u00b7 Process\u00e1vel?",
"type": "main",
"index": 0
}
]
]
},
"3\u00b7 Process\u00e1vel?": {
"main": [
[
{
"node": "4\u00b7 UPSERT lead",
"type": "main",
"index": 0
}
],
[
{
"node": "Responde 200",
"type": "main",
"index": 0
}
]
]
},
"4\u00b7 UPSERT lead": {
"main": [
[
{
"node": "5\u00b7 IA no controle?",
"type": "main",
"index": 0
}
]
]
},
"5\u00b7 IA no controle?": {
"main": [
[
{
"node": "6\u00b7 \u00c9 m\u00eddia?",
"type": "main",
"index": 0
}
],
[
{
"node": "Responde 200",
"type": "main",
"index": 0
}
]
]
},
"6\u00b7 \u00c9 m\u00eddia?": {
"main": [
[
{
"node": "6b\u00b7 \u00c9 \u00e1udio?",
"type": "main",
"index": 0
}
],
[
{
"node": "9\u00b7 Lead novo?",
"type": "main",
"index": 0
}
]
]
},
"6b\u00b7 \u00c9 \u00e1udio?": {
"main": [
[
{
"node": "tr1\u00b7 Evolution \u00e1udio",
"type": "main",
"index": 0
}
],
[
{
"node": "6c\u00b7 \u00c9 imagem?",
"type": "main",
"index": 0
}
]
]
},
"6c\u00b7 \u00c9 imagem?": {
"main": [
[
{
"node": "im1\u00b7 Evolution imagem",
"type": "main",
"index": 0
}
],
[
{
"node": "7\u00b7 Resposta m\u00eddia",
"type": "main",
"index": 0
}
]
]
},
"im1\u00b7 Evolution imagem": {
"main": [
[
{
"node": "im2\u00b7 Groq vis\u00e3o",
"type": "main",
"index": 0
}
]
]
},
"im2\u00b7 Groq vis\u00e3o": {
"main": [
[
{
"node": "im3\u00b7 Reinjeta imagem",
"type": "main",
"index": 0
}
]
]
},
"im3\u00b7 Reinjeta imagem": {
"main": [
[
{
"node": "Responde 200",
"type": "main",
"index": 0
}
]
]
},
"tr1\u00b7 Evolution \u00e1udio": {
"main": [
[
{
"node": "tr2\u00b7 Base64 p/ arquivo",
"type": "main",
"index": 0
}
]
]
},
"tr2\u00b7 Base64 p/ arquivo": {
"main": [
[
{
"node": "tr3\u00b7 Groq Whisper",
"type": "main",
"index": 0
}
]
]
},
"tr3\u00b7 Groq Whisper": {
"main": [
[
{
"node": "tr4\u00b7 Reinjeta texto",
"type": "main",
"index": 0
}
]
]
},
"tr4\u00b7 Reinjeta texto": {
"main": [
[
{
"node": "Responde 200",
"type": "main",
"index": 0
}
]
]
},
"7\u00b7 Resposta m\u00eddia": {
"main": [
[
{
"node": "8\u00b7 Log m\u00eddia",
"type": "main",
"index": 0
}
]
]
},
"8\u00b7 Log m\u00eddia": {
"main": [
[
{
"node": "Responde 200",
"type": "main",
"index": 0
}
]
]
},
"9\u00b7 Lead novo?": {
"main": [
[
{
"node": "10\u00b7 Sauda\u00e7\u00e3o",
"type": "main",
"index": 0
}
],
[
{
"node": "12\u00b7 Buffer (debounce)",
"type": "main",
"index": 0
}
]
]
},
"12\u00b7 Buffer (debounce)": {
"main": [
[
{
"node": "12b\u00b7 Aguarda 8s",
"type": "main",
"index": 0
}
]
]
},
"12b\u00b7 Aguarda 8s": {
"main": [
[
{
"node": "12c\u00b7 Checa \u00faltima",
"type": "main",
"index": 0
}
]
]
},
"12c\u00b7 Checa \u00faltima": {
"main": [
[
{
"node": "12d\u00b7 \u00c9 a \u00faltima?",
"type": "main",
"index": 0
}
]
]
},
"12d\u00b7 \u00c9 a \u00faltima?": {
"main": [
[
{
"node": "12e\u00b7 Hist\u00f3rico",
"type": "main",
"index": 0
}
],
[
{
"node": "Responde 200",
"type": "main",
"index": 0
}
]
]
},
"10\u00b7 Sauda\u00e7\u00e3o": {
"main": [
[
{
"node": "11\u00b7 Log sauda\u00e7\u00e3o",
"type": "main",
"index": 0
}
]
]
},
"11\u00b7 Log sauda\u00e7\u00e3o": {
"main": [
[
{
"node": "Responde 200",
"type": "main",
"index": 0
}
]
]
},
"12e\u00b7 Hist\u00f3rico": {
"main": [
[
{
"node": "13\u00b7 Montar prompt",
"type": "main",
"index": 0
}
]
]
},
"13\u00b7 Montar prompt": {
"main": [
[
{
"node": "14\u00b7 DeepSeek",
"type": "main",
"index": 0
}
]
]
},
"14\u00b7 DeepSeek": {
"main": [
[
{
"node": "15\u00b7 Ler resposta IA",
"type": "main",
"index": 0
}
]
]
},
"15\u00b7 Ler resposta IA": {
"main": [
[
{
"node": "16\u00b7 Atualiza lead",
"type": "main",
"index": 0
}
]
]
},
"16\u00b7 Atualiza lead": {
"main": [
[
{
"node": "17\u00b7 A\u00e7\u00e3o?",
"type": "main",
"index": 0
}
]
]
},
"17\u00b7 A\u00e7\u00e3o?": {
"main": [
[
{
"node": "18\u00b7 Marca call agendada",
"type": "main",
"index": 0
}
],
[
{
"node": "19\u00b7 Marca handoff",
"type": "main",
"index": 0
}
],
[
{
"node": "21\u00b7 Enviar resposta",
"type": "main",
"index": 0
}
]
]
},
"18\u00b7 Marca call agendada": {
"main": [
[
{
"node": "18b\u00b7 Cria evento GCal",
"type": "main",
"index": 0
}
]
]
},
"18b\u00b7 Cria evento GCal": {
"main": [
[
{
"node": "20\u00b7 Notifica Inael",
"type": "main",
"index": 0
}
]
]
},
"19\u00b7 Marca handoff": {
"main": [
[
{
"node": "20\u00b7 Notifica Inael",
"type": "main",
"index": 0
}
]
]
},
"20\u00b7 Notifica Inael": {
"main": [
[
{
"node": "21\u00b7 Enviar resposta",
"type": "main",
"index": 0
}
]
]
},
"21\u00b7 Enviar resposta": {
"main": [
[
{
"node": "22\u00b7 Log resposta",
"type": "main",
"index": 0
}
]
]
},
"22\u00b7 Log resposta": {
"main": [
[
{
"node": "Responde 200",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
}
}
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.
httpHeaderAuthpostgres
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
ITB SDR — MVP. Uses postgres, httpRequest. Webhook trigger; 39 nodes.
Source: https://gist.github.com/inael/8f442778f360d05355dfecc392e9da31 — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
CMM. Uses httpRequest, postgres, redis. Webhook trigger; 90 nodes.
Scraping. Uses httpRequest, postgres, @apify/n8n-nodes-apify, respondToWebhook. Webhook trigger; 61 nodes.
Workflow B — AI Listing Engine. Uses httpRequest, postgres, errorTrigger. Webhook trigger; 47 nodes.
LogSentinel Workflow. Uses postgres, emailSend, httpRequest. Webhook trigger; 44 nodes.
Post-Prayer. Uses postgres, httpRequest. Webhook trigger; 44 nodes.