Skip to main content
Glama

Uazapi WhatsApp MCP Server

by pabloweyne
workflow-chatbot-v2-memoria.json21.9 kB
{ "name": "UAZAPI WhatsApp Chatbot v2 - Com Memória", "nodes": [ { "parameters": { "httpMethod": "POST", "path": "uazapi-webhook", "responseMode": "responseNode", "options": {} }, "id": "webhook-trigger", "name": "Webhook UAZAPI", "type": "n8n-nodes-base.webhook", "typeVersion": 2, "position": [240, 300] }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict" }, "conditions": [ { "id": "phone-check", "leftValue": "={{ $json.body.phone }}", "rightValue": "SEU_NUMERO_AQUI", "operator": { "type": "string", "operation": "equals" } } ], "combinator": "and" }, "options": {} }, "id": "filter-authorized", "name": "Verificar Numero Autorizado", "type": "n8n-nodes-base.if", "typeVersion": 2, "position": [460, 300] }, { "parameters": { "assignments": { "assignments": [ { "id": "user-message", "name": "userMessage", "value": "={{ $json.body.message.conversation || $json.body.message.extendedTextMessage?.text || '' }}", "type": "string" }, { "id": "phone", "name": "phone", "value": "={{ $json.body.phone }}", "type": "string" }, { "id": "message-id", "name": "messageId", "value": "={{ $json.body.key.id }}", "type": "string" }, { "id": "timestamp", "name": "timestamp", "value": "={{ Date.now() }}", "type": "number" }, { "id": "redis-key", "name": "redisKey", "value": "=uazapi:chat:{{ $json.body.phone }}", "type": "string" } ] }, "options": {} }, "id": "extract-data", "name": "Extrair Dados da Mensagem", "type": "n8n-nodes-base.set", "typeVersion": 3.4, "position": [680, 240] }, { "parameters": { "operation": "get", "key": "={{ $json.redisKey }}" }, "id": "redis-get-context", "name": "Redis Buscar Contexto", "type": "n8n-nodes-base.redis", "typeVersion": 1, "position": [900, 240], "credentials": { "redis": { "id": "REDIS_CREDENTIAL_ID", "name": "Redis" } } }, { "parameters": { "jsCode": "// Preparar contexto para o GPT\nconst currentMessage = $('Extrair Dados da Mensagem').first().json;\nlet context = {\n historico: [],\n grupos_frequentes: [],\n contatos_frequentes: [],\n ultima_acao: null,\n preferencias: {}\n};\n\n// Tentar carregar contexto existente do Redis\ntry {\n const redisData = $input.first().json;\n if (redisData && typeof redisData === 'string') {\n context = JSON.parse(redisData);\n } else if (redisData && typeof redisData === 'object' && redisData.value) {\n context = JSON.parse(redisData.value);\n }\n} catch (e) {\n // Contexto vazio, usar default\n}\n\n// Limitar histórico a últimas 10 mensagens\nconst historico = context.historico || [];\nif (historico.length > 10) {\n context.historico = historico.slice(-10);\n}\n\n// Formatar histórico para o prompt\nlet historicoTexto = '';\nif (context.historico && context.historico.length > 0) {\n historicoTexto = '\\n\\n## HISTÓRICO RECENTE\\n';\n context.historico.forEach((msg, i) => {\n historicoTexto += `${msg.role === 'user' ? 'Usuário' : 'Assistente'}: ${msg.content}\\n`;\n });\n}\n\n// Formatar grupos frequentes\nlet gruposTexto = '';\nif (context.grupos_frequentes && context.grupos_frequentes.length > 0) {\n gruposTexto = '\\n\\n## GRUPOS DO USUÁRIO\\n';\n context.grupos_frequentes.forEach(g => {\n gruposTexto += `- ${g.nome} (ID: ${g.id})\\n`;\n });\n}\n\n// Formatar contatos frequentes\nlet contatosTexto = '';\nif (context.contatos_frequentes && context.contatos_frequentes.length > 0) {\n contatosTexto = '\\n\\n## CONTATOS FREQUENTES\\n';\n context.contatos_frequentes.forEach(c => {\n contatosTexto += `- ${c.nome}: ${c.numero}\\n`;\n });\n}\n\n// Última ação\nlet ultimaAcaoTexto = '';\nif (context.ultima_acao) {\n ultimaAcaoTexto = `\\n\\n## ÚLTIMA AÇÃO\\n${context.ultima_acao.tipo}: ${context.ultima_acao.descricao}`;\n}\n\nreturn {\n json: {\n userMessage: currentMessage.userMessage,\n phone: currentMessage.phone,\n redisKey: currentMessage.redisKey,\n timestamp: currentMessage.timestamp,\n context: context,\n contextPrompt: historicoTexto + gruposTexto + contatosTexto + ultimaAcaoTexto\n }\n};" }, "id": "prepare-context", "name": "Preparar Contexto", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [1120, 240] }, { "parameters": { "model": "gpt-4o", "messages": { "values": [ { "role": "system", "content": "=Você é um assistente de gerenciamento do WhatsApp via UAZAPI. Você tem MEMÓRIA e lembra das conversas anteriores.\n\n## AÇÕES DISPONÍVEIS\n\n### Mensagens\n- enviar_texto: Enviar mensagem de texto para um número\n- enviar_imagem: Enviar imagem com URL\n- enviar_documento: Enviar documento/arquivo\n- enviar_audio: Enviar áudio\n- enviar_video: Enviar vídeo\n\n### Grupos\n- criar_grupo: Criar novo grupo com participantes\n- adicionar_participante: Adicionar pessoa a um grupo\n- remover_participante: Remover pessoa de um grupo\n- listar_grupos: Listar todos os grupos\n- info_grupo: Obter informações de um grupo\n\n### Contatos\n- listar_contatos: Listar contatos salvos\n- verificar_numero: Verificar se número tem WhatsApp\n- salvar_contato: Salvar um contato com apelido (para memória)\n\n### Links\n- enviar_link: Enviar link com preview\n- link_grupo: Obter link de convite do grupo\n\n### Memória\n- lembrar: Guardar uma informação para uso futuro\n- esquecer: Remover uma informação da memória\n\n{{ $json.contextPrompt }}\n\n## FORMATO DE RESPOSTA\n\nSempre responda em JSON:\n{\n \"acao\": \"nome_da_acao\",\n \"parametros\": { ... },\n \"mensagem_usuario\": \"Resposta amigável\",\n \"memoria\": {\n \"salvar_grupo\": { \"nome\": \"...\", \"id\": \"...\" },\n \"salvar_contato\": { \"nome\": \"...\", \"numero\": \"...\" },\n \"lembrete\": \"informação a lembrar\"\n }\n}\n\nO campo \"memoria\" é opcional - use apenas quando fizer sentido salvar algo.\n\n## REGRAS\n- Use o histórico para entender contexto (ex: \"ele\" = última pessoa mencionada)\n- Se o usuário mencionar um nome, tente encontrar nos contatos frequentes\n- Se mencionar um grupo por nome, use os grupos conhecidos\n- Seja proativo em lembrar informações úteis\n- Números devem incluir código do país (ex: 5511999999999)" }, { "role": "user", "content": "={{ $json.userMessage }}" } ] }, "options": { "temperature": 0.3, "maxTokens": 1500 } }, "id": "openai-process", "name": "OpenAI com Contexto", "type": "@n8n/n8n-nodes-langchain.openAi", "typeVersion": 1.6, "position": [1340, 240], "credentials": { "openAiApi": { "id": "OPENAI_CREDENTIAL_ID", "name": "OpenAI API" } } }, { "parameters": { "jsCode": "// Parse da resposta do GPT e preparar para salvar no Redis\nconst gptResponse = $input.first().json.message.content;\nconst previousData = $('Preparar Contexto').first().json;\nlet parsed;\n\ntry {\n const jsonMatch = gptResponse.match(/\\{[\\s\\S]*\\}/);\n if (jsonMatch) {\n parsed = JSON.parse(jsonMatch[0]);\n } else {\n parsed = {\n acao: 'responder',\n parametros: {},\n mensagem_usuario: gptResponse\n };\n }\n} catch (e) {\n parsed = {\n acao: 'responder',\n parametros: {},\n mensagem_usuario: gptResponse\n };\n}\n\n// Atualizar contexto\nlet context = previousData.context || {\n historico: [],\n grupos_frequentes: [],\n contatos_frequentes: [],\n ultima_acao: null,\n preferencias: {}\n};\n\n// Adicionar ao histórico\ncontext.historico.push({\n role: 'user',\n content: previousData.userMessage,\n timestamp: previousData.timestamp\n});\n\ncontext.historico.push({\n role: 'assistant',\n content: parsed.mensagem_usuario,\n timestamp: Date.now()\n});\n\n// Limitar histórico\nif (context.historico.length > 20) {\n context.historico = context.historico.slice(-20);\n}\n\n// Salvar última ação\nif (parsed.acao && parsed.acao !== 'responder' && parsed.acao !== 'perguntar') {\n context.ultima_acao = {\n tipo: parsed.acao,\n descricao: JSON.stringify(parsed.parametros),\n timestamp: Date.now()\n };\n}\n\n// Processar memória do GPT\nif (parsed.memoria) {\n if (parsed.memoria.salvar_grupo) {\n const grupo = parsed.memoria.salvar_grupo;\n const existe = context.grupos_frequentes.find(g => g.id === grupo.id);\n if (!existe) {\n context.grupos_frequentes.push(grupo);\n if (context.grupos_frequentes.length > 10) {\n context.grupos_frequentes = context.grupos_frequentes.slice(-10);\n }\n }\n }\n \n if (parsed.memoria.salvar_contato) {\n const contato = parsed.memoria.salvar_contato;\n const existe = context.contatos_frequentes.find(c => c.numero === contato.numero);\n if (!existe) {\n context.contatos_frequentes.push(contato);\n if (context.contatos_frequentes.length > 20) {\n context.contatos_frequentes = context.contatos_frequentes.slice(-20);\n }\n }\n }\n}\n\nreturn {\n json: {\n ...parsed,\n phone: previousData.phone,\n redisKey: previousData.redisKey,\n contextToSave: JSON.stringify(context)\n }\n};" }, "id": "parse-and-update-context", "name": "Parse e Atualizar Contexto", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [1560, 240] }, { "parameters": { "operation": "set", "key": "={{ $json.redisKey }}", "value": "={{ $json.contextToSave }}", "expire": true, "ttl": 604800 }, "id": "redis-save-context", "name": "Redis Salvar Contexto", "type": "n8n-nodes-base.redis", "typeVersion": 1, "position": [1780, 240], "credentials": { "redis": { "id": "REDIS_CREDENTIAL_ID", "name": "Redis" } } }, { "parameters": { "rules": { "values": [ { "conditions": { "options": { "caseSensitive": false }, "conditions": [{ "leftValue": "={{ $json.acao }}", "rightValue": "enviar_texto", "operator": { "type": "string", "operation": "equals" } }] }, "renameOutput": true, "outputLabel": "Enviar Texto" }, { "conditions": { "options": { "caseSensitive": false }, "conditions": [{ "leftValue": "={{ $json.acao }}", "rightValue": "enviar_imagem", "operator": { "type": "string", "operation": "equals" } }] }, "renameOutput": true, "outputLabel": "Enviar Imagem" }, { "conditions": { "options": { "caseSensitive": false }, "conditions": [{ "leftValue": "={{ $json.acao }}", "rightValue": "criar_grupo", "operator": { "type": "string", "operation": "equals" } }] }, "renameOutput": true, "outputLabel": "Criar Grupo" }, { "conditions": { "options": { "caseSensitive": false }, "conditions": [{ "leftValue": "={{ $json.acao }}", "rightValue": "adicionar_participante", "operator": { "type": "string", "operation": "equals" } }] }, "renameOutput": true, "outputLabel": "Add Participante" }, { "conditions": { "options": { "caseSensitive": false }, "conditions": [{ "leftValue": "={{ $json.acao }}", "rightValue": "remover_participante", "operator": { "type": "string", "operation": "equals" } }] }, "renameOutput": true, "outputLabel": "Remove Participante" }, { "conditions": { "options": { "caseSensitive": false }, "conditions": [{ "leftValue": "={{ $json.acao }}", "rightValue": "listar_grupos", "operator": { "type": "string", "operation": "equals" } }] }, "renameOutput": true, "outputLabel": "Listar Grupos" }, { "conditions": { "options": { "caseSensitive": false }, "conditions": [{ "leftValue": "={{ $json.acao }}", "rightValue": "listar_contatos", "operator": { "type": "string", "operation": "equals" } }] }, "renameOutput": true, "outputLabel": "Listar Contatos" } ], "fallbackOutput": { "renameOutput": true, "outputLabel": "Resposta Simples" } }, "options": {} }, "id": "router-action", "name": "Router de Ações", "type": "n8n-nodes-base.switch", "typeVersion": 3.2, "position": [2000, 240] }, { "parameters": { "method": "POST", "url": "=https://api.uazapi.com/instances/{{ $env.UAZAPI_INSTANCE_ID }}/messages/send/text", "authentication": "genericCredentialType", "genericAuthType": "httpHeaderAuth", "sendBody": true, "specifyBody": "json", "jsonBody": "={\n \"phone\": \"{{ $json.parametros.numero }}\",\n \"message\": \"{{ $json.parametros.mensagem }}\"\n}", "options": {} }, "id": "uazapi-send-text", "name": "UAZAPI Enviar Texto", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [2260, -60], "credentials": { "httpHeaderAuth": { "id": "UAZAPI_CREDENTIAL_ID", "name": "UAZAPI Auth" } } }, { "parameters": { "method": "POST", "url": "=https://api.uazapi.com/instances/{{ $env.UAZAPI_INSTANCE_ID }}/messages/send/image", "authentication": "genericCredentialType", "genericAuthType": "httpHeaderAuth", "sendBody": true, "specifyBody": "json", "jsonBody": "={\n \"phone\": \"{{ $json.parametros.numero }}\",\n \"mediaUrl\": \"{{ $json.parametros.url }}\",\n \"caption\": \"{{ $json.parametros.legenda || '' }}\"\n}", "options": {} }, "id": "uazapi-send-image", "name": "UAZAPI Enviar Imagem", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [2260, 60], "credentials": { "httpHeaderAuth": { "id": "UAZAPI_CREDENTIAL_ID", "name": "UAZAPI Auth" } } }, { "parameters": { "method": "POST", "url": "=https://api.uazapi.com/instances/{{ $env.UAZAPI_INSTANCE_ID }}/groups/create", "authentication": "genericCredentialType", "genericAuthType": "httpHeaderAuth", "sendBody": true, "specifyBody": "json", "jsonBody": "={\n \"name\": \"{{ $json.parametros.nome }}\",\n \"participants\": {{ JSON.stringify($json.parametros.participantes || []) }}\n}", "options": {} }, "id": "uazapi-create-group", "name": "UAZAPI Criar Grupo", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [2260, 180], "credentials": { "httpHeaderAuth": { "id": "UAZAPI_CREDENTIAL_ID", "name": "UAZAPI Auth" } } }, { "parameters": { "method": "POST", "url": "=https://api.uazapi.com/instances/{{ $env.UAZAPI_INSTANCE_ID }}/groups/{{ $json.parametros.grupo_id }}/participants/add", "authentication": "genericCredentialType", "genericAuthType": "httpHeaderAuth", "sendBody": true, "specifyBody": "json", "jsonBody": "={\n \"participants\": {{ JSON.stringify($json.parametros.numeros || [$json.parametros.numero]) }}\n}", "options": {} }, "id": "uazapi-add-participant", "name": "UAZAPI Add Participante", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [2260, 300], "credentials": { "httpHeaderAuth": { "id": "UAZAPI_CREDENTIAL_ID", "name": "UAZAPI Auth" } } }, { "parameters": { "method": "DELETE", "url": "=https://api.uazapi.com/instances/{{ $env.UAZAPI_INSTANCE_ID }}/groups/{{ $json.parametros.grupo_id }}/participants/remove", "authentication": "genericCredentialType", "genericAuthType": "httpHeaderAuth", "sendBody": true, "specifyBody": "json", "jsonBody": "={\n \"participants\": {{ JSON.stringify($json.parametros.numeros || [$json.parametros.numero]) }}\n}", "options": {} }, "id": "uazapi-remove-participant", "name": "UAZAPI Remove Participante", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [2260, 420], "credentials": { "httpHeaderAuth": { "id": "UAZAPI_CREDENTIAL_ID", "name": "UAZAPI Auth" } } }, { "parameters": { "method": "GET", "url": "=https://api.uazapi.com/instances/{{ $env.UAZAPI_INSTANCE_ID }}/groups", "authentication": "genericCredentialType", "genericAuthType": "httpHeaderAuth", "options": {} }, "id": "uazapi-list-groups", "name": "UAZAPI Listar Grupos", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [2260, 540], "credentials": { "httpHeaderAuth": { "id": "UAZAPI_CREDENTIAL_ID", "name": "UAZAPI Auth" } } }, { "parameters": { "method": "GET", "url": "=https://api.uazapi.com/instances/{{ $env.UAZAPI_INSTANCE_ID }}/contacts", "authentication": "genericCredentialType", "genericAuthType": "httpHeaderAuth", "options": {} }, "id": "uazapi-list-contacts", "name": "UAZAPI Listar Contatos", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [2260, 660], "credentials": { "httpHeaderAuth": { "id": "UAZAPI_CREDENTIAL_ID", "name": "UAZAPI Auth" } } }, { "parameters": { "method": "POST", "url": "=https://api.uazapi.com/instances/{{ $env.UAZAPI_INSTANCE_ID }}/messages/send/text", "authentication": "genericCredentialType", "genericAuthType": "httpHeaderAuth", "sendBody": true, "specifyBody": "json", "jsonBody": "={\n \"phone\": \"{{ $('Preparar Contexto').first().json.phone }}\",\n \"message\": \"{{ $json.mensagem_usuario }}\"\n}", "options": {} }, "id": "send-response-to-user", "name": "Enviar Resposta ao Usuario", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [2520, 340], "credentials": { "httpHeaderAuth": { "id": "UAZAPI_CREDENTIAL_ID", "name": "UAZAPI Auth" } } }, { "parameters": { "respondWith": "json", "responseBody": "={\"status\": \"ok\"}", "options": {} }, "id": "respond-webhook", "name": "Responder Webhook", "type": "n8n-nodes-base.respondToWebhook", "typeVersion": 1.1, "position": [2740, 340] }, { "parameters": { "respondWith": "json", "responseBody": "={\"status\": \"unauthorized\"}", "options": { "responseCode": 403 } }, "id": "respond-unauthorized", "name": "Responder Nao Autorizado", "type": "n8n-nodes-base.respondToWebhook", "typeVersion": 1.1, "position": [680, 400] } ], "connections": { "Webhook UAZAPI": { "main": [[{ "node": "Verificar Numero Autorizado", "type": "main", "index": 0 }]] }, "Verificar Numero Autorizado": { "main": [ [{ "node": "Extrair Dados da Mensagem", "type": "main", "index": 0 }], [{ "node": "Responder Nao Autorizado", "type": "main", "index": 0 }] ] }, "Extrair Dados da Mensagem": { "main": [[{ "node": "Redis Buscar Contexto", "type": "main", "index": 0 }]] }, "Redis Buscar Contexto": { "main": [[{ "node": "Preparar Contexto", "type": "main", "index": 0 }]] }, "Preparar Contexto": { "main": [[{ "node": "OpenAI com Contexto", "type": "main", "index": 0 }]] }, "OpenAI com Contexto": { "main": [[{ "node": "Parse e Atualizar Contexto", "type": "main", "index": 0 }]] }, "Parse e Atualizar Contexto": { "main": [[{ "node": "Redis Salvar Contexto", "type": "main", "index": 0 }]] }, "Redis Salvar Contexto": { "main": [[{ "node": "Router de Ações", "type": "main", "index": 0 }]] }, "Router de Ações": { "main": [ [{ "node": "UAZAPI Enviar Texto", "type": "main", "index": 0 }], [{ "node": "UAZAPI Enviar Imagem", "type": "main", "index": 0 }], [{ "node": "UAZAPI Criar Grupo", "type": "main", "index": 0 }], [{ "node": "UAZAPI Add Participante", "type": "main", "index": 0 }], [{ "node": "UAZAPI Remove Participante", "type": "main", "index": 0 }], [{ "node": "UAZAPI Listar Grupos", "type": "main", "index": 0 }], [{ "node": "UAZAPI Listar Contatos", "type": "main", "index": 0 }], [{ "node": "Enviar Resposta ao Usuario", "type": "main", "index": 0 }] ] }, "UAZAPI Enviar Texto": { "main": [[{ "node": "Enviar Resposta ao Usuario", "type": "main", "index": 0 }]] }, "UAZAPI Enviar Imagem": { "main": [[{ "node": "Enviar Resposta ao Usuario", "type": "main", "index": 0 }]] }, "UAZAPI Criar Grupo": { "main": [[{ "node": "Enviar Resposta ao Usuario", "type": "main", "index": 0 }]] }, "UAZAPI Add Participante": { "main": [[{ "node": "Enviar Resposta ao Usuario", "type": "main", "index": 0 }]] }, "UAZAPI Remove Participante": { "main": [[{ "node": "Enviar Resposta ao Usuario", "type": "main", "index": 0 }]] }, "UAZAPI Listar Grupos": { "main": [[{ "node": "Enviar Resposta ao Usuario", "type": "main", "index": 0 }]] }, "UAZAPI Listar Contatos": { "main": [[{ "node": "Enviar Resposta ao Usuario", "type": "main", "index": 0 }]] }, "Enviar Resposta ao Usuario": { "main": [[{ "node": "Responder Webhook", "type": "main", "index": 0 }]] } }, "settings": { "executionOrder": "v1" } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/pabloweyne/uazapi-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server