GitHub n8n
Você quer receber um evento via API (Webhook), enviar uma mensagem no WhatsApp via Notifish e registrar o resultado (sucesso/erro) em log.
Esse fluxo é útil para:
POST https://meu-dominio.notifish.com/api/v2/{INSTANCE_UUID}/whatsapp/message/groupsAuthorization: Bearer ...Aqui vou usar a opção A (mais “produção”).
Você vai expor um endpoint no n8n, por exemplo:
POST https://SEU_N8N/webhook/notify
Payload recomendado (simples e suficiente):
{
"title": "API 5xx alto",
"message": "Erros 5xx acima do normal em /api/orders",
"url": "https://seu-dashboard",
"identifier": "prod:api:5xx",
"delayMessage": 0
}
Repare que já mandamos identifier. Isso permite deduplicar e evitar spam.
Se você tiver Redis (muito comum), dá para usar um passo “check” antes do envio.
dedupe:{identifier}Se você não tiver Redis, dá para deduplicar com “Data Store” do n8n ou com um endpoint seu.
Vou te passar o fluxo com Data Store do n8n (não depende de infra extra).
O Notifish recebe:
{
"message": "...",
"identifier": "...",
"link": true,
"typing": "composing",
"delayMessage": 1200
}
A gente vai montar isso no n8n.
Depois do envio (sucesso ou falha), registramos em um endpoint de log. Exemplo:
POST https://seu-sistema.com/api/logs/notifish
Log recomendado:
{
"identifier": "prod:api:5xx",
"status": "success",
"http_status": 200,
"provider": "notifish",
"payload": { ... },
"response": { ... },
"created_at": "2026-01-22T00:00:00-03:00"
}
Cria um formato consistente e monta a mensagem final do WhatsApp:
Busca identifier na datastore (dedupe).
Se já existe registro recente, responde 200 “ignored” e não envia.
POST no endpoint do Notifish com Bearer Token.
Salva identifier com TTL (ex.: 300s) para dedupe.
Envia log para seu endpoint.
Se Notifish falhar, manda log com status error.
Abaixo um workflow base. Você só precisa trocar:
NOTIFISH_INSTANCE_UUIDNOTIFISH_TOKENLOG_ENDPOINT_URLImport: n8n → Workflows → Import from file/clipboard
{
"name": "API → Notifish WhatsApp → Log (com dedupe)",
"nodes": [
{
"parameters": {
"path": "notify",
"httpMethod": "POST",
"responseMode": "lastNode",
"options": {}
},
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [260, 300]
},
{
"parameters": {
"functionCode": "const body = $json;\n\nconst title = body.title || 'Notificação';\nconst msg = body.message || '';\nconst url = body.url || '';\n\nconst identifier = body.identifier || `generic:${Date.now()}`;\nconst delayMessage = body.delayMessage ?? 0;\n\nconst whatsappMessage = `*${title}*\\n\\n${msg}${url ? `\\n\\n${url}` : ''}`;\n\nreturn [{\n identifier,\n delayMessage,\n notifishPayload: {\n message: whatsappMessage,\n identifier,\n link: true,\n typing: 'composing',\n delayMessage\n },\n original: body\n}];"
},
"name": "Normalize",
"type": "n8n-nodes-base.function",
"typeVersion": 2,
"position": [520, 300]
},
{
"parameters": {
"operation": "get",
"key": "={{$json.identifier}}"
},
"name": "Dedupe Get",
"type": "n8n-nodes-base.dataStore",
"typeVersion": 1,
"position": [760, 300]
},
{
"parameters": {
"conditions": {
"boolean": [
{
"value1": "={{$json.value !== undefined && $json.value !== null}}",
"value2": true
}
]
}
},
"name": "Já enviou?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [980, 300]
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={\"status\":\"ignored\",\"reason\":\"dedupe\",\"identifier\":\"{{$json.identifier}}\"}",
"options": {}
},
"name": "Return Ignored",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1,
"position": [1210, 200]
},
{
"parameters": {
"url": "https://meu-dominio.notifish.com/api/v2/NOTIFISH_INSTANCE_UUID/whatsapp/message/groups",
"method": "POST",
"authentication": "none",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "Bearer NOTIFISH_TOKEN"
},
{
"name": "Content-Type",
"value": "application/json"
},
{
"name": "Accept",
"value": "application/json"
}
]
},
"sendBody": true,
"contentType": "json",
"jsonBody": "={{$json.notifishPayload}}",
"options": {
"timeout": 8000
}
},
"name": "Send Notifish",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [1210, 380]
},
{
"parameters": {
"operation": "set",
"key": "={{$json.identifier}}",
"value": "={{JSON.stringify({sentAt: new Date().toISOString()})}}"
},
"name": "Dedupe Set",
"type": "n8n-nodes-base.dataStore",
"typeVersion": 1,
"position": [1450, 380]
},
{
"parameters": {
"url": "LOG_ENDPOINT_URL",
"method": "POST",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"contentType": "json",
"jsonBody": "={{ {\n identifier: $json.identifier,\n status: 'success',\n provider: 'notifish',\n response: $json,\n created_at: new Date().toISOString()\n} }}"
},
"name": "Log Success",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [1690, 380]
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={\"status\":\"sent\",\"identifier\":\"{{$json.identifier}}\"}",
"options": {}
},
"name": "Return OK",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1,
"position": [1910, 380]
}
],
"connections": {
"Webhook": {
"main": [
[
{
"node": "Normalize",
"type": "main",
"index": 0
}
]
]
},
"Normalize": {
"main": [
[
{
"node": "Dedupe Get",
"type": "main",
"index": 0
}
]
]
},
"Dedupe Get": {
"main": [
[
{
"node": "Já enviou?",
"type": "main",
"index": 0
}
]
]
},
"Já enviou?": {
"main": [
[
{
"node": "Return Ignored",
"type": "main",
"index": 0
}
],
[
{
"node": "Send Notifish",
"type": "main",
"index": 0
}
]
]
},
"Send Notifish": {
"main": [
[
{
"node": "Dedupe Set",
"type": "main",
"index": 0
}
]
]
},
"Dedupe Set": {
"main": [
[
{
"node": "Log Success",
"type": "main",
"index": 0
}
]
]
},
"Log Success": {
"main": [
[
{
"node": "Return OK",
"type": "main",
"index": 0
}
]
]
}
},
"active": false
}
Ele salva “para sempre” se você não limpar. Em produção, o ideal é:
Se você quiser, eu te mando a versão com Redis (TTL real).
Se você não tiver endpoint pronto, você pode logar em:
ou até em um arquivo via API sua
PostgreSQL/MySQL via node de banco
Google Sheets (rápido)
A maioria dos desenvolvedores PHP sabe fazer CRUD.Isso não te torna pleno. Muito menos sênior.…
Você não precisa ser especialista nem passar horas auditando código para saber se um projeto…
WordPress não é lento, frágil ou amador. Ele só ficou mal-falado porque virou refém de…
De assistentes que escrevem códigos a geradores de vídeos e músicas em segundos, essas inteligências…
WhatsApp é um canal excelente para alerta porque ele tem uma característica que e-mail e…
Durante alguns anos, o AMP foi tratado como solução quase obrigatória para quem queria desempenho…