n8n-nodes-salvia 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# n8n-nodes-salvia
|
|
2
|
+
|
|
3
|
+
Nodes do **Salvia CRM** para o n8n: crie leads a partir de qualquer fluxo (formulário, planilha, anúncio, bot) com credencial própria e campos amigáveis.
|
|
4
|
+
|
|
5
|
+
## Instalação (n8n self-hosted)
|
|
6
|
+
|
|
7
|
+
No terminal do container do n8n:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
mkdir -p ~/.n8n/nodes && cd ~/.n8n/nodes
|
|
11
|
+
npm install https://github.com/Projetos-Mov/n8n-nodes-salvia/archive/refs/heads/main.tar.gz
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Depois **reinicie o n8n**. O node "Salvia" aparece na busca de nodes.
|
|
15
|
+
|
|
16
|
+
## Credencial
|
|
17
|
+
|
|
18
|
+
1. No Salvia: **Ajustes → Central de Integrações → Desenvolvedores → Nova chave** (planos Pro e Clínica).
|
|
19
|
+
2. No n8n: **Credentials → New → Salvia API**:
|
|
20
|
+
- **Base URL**: `https://salviacrm.com.br` (ou a URL do ambiente de teste)
|
|
21
|
+
- **API Key**: a chave gerada
|
|
22
|
+
3. O botão de teste chama `GET /api/v1/me` e confirma a conexão.
|
|
23
|
+
|
|
24
|
+
## Operações
|
|
25
|
+
|
|
26
|
+
### Lead → Criar
|
|
27
|
+
|
|
28
|
+
`POST /api/v1/leads` — campos: Nome (obrigatório), Telefone, Email, Origem e opcionais (funil, etapa, dono, campos personalizados, UTMs, telefone duplicado). O lead cai na etapa de entrada do funil padrão quando funil/etapa não são informados.
|
|
29
|
+
|
|
30
|
+
A saída do node é o lead criado (id, nome, etapa etc.) pronto pra usar nos próximos passos do fluxo.
|
|
31
|
+
|
|
32
|
+
## Desenvolvimento
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npm install
|
|
36
|
+
npm run build # tsc + cópia de ícones pro dist/
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
O `dist/` fica commitado pra permitir instalação direta pelo tarball do GitHub, sem build no servidor.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SalviaApi = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Credencial do Salvia CRM: chave da API (Ajustes → Central de Integrações →
|
|
6
|
+
* Desenvolvedores) enviada como Bearer token. A Base URL permite apontar pro
|
|
7
|
+
* ambiente de teste (preview) sem mexer nos fluxos.
|
|
8
|
+
*/
|
|
9
|
+
class SalviaApi {
|
|
10
|
+
constructor() {
|
|
11
|
+
this.name = "salviaApi";
|
|
12
|
+
this.displayName = "Salvia API";
|
|
13
|
+
this.documentationUrl = "https://salviacrm.com.br";
|
|
14
|
+
this.properties = [
|
|
15
|
+
{
|
|
16
|
+
displayName: "Base URL",
|
|
17
|
+
name: "baseUrl",
|
|
18
|
+
type: "string",
|
|
19
|
+
default: "https://salviacrm.com.br",
|
|
20
|
+
description: "Endereço do Salvia. Pra testar, use a URL do ambiente de teste (preview).",
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
displayName: "API Key",
|
|
24
|
+
name: "apiKey",
|
|
25
|
+
type: "string",
|
|
26
|
+
typeOptions: { password: true },
|
|
27
|
+
default: "",
|
|
28
|
+
description: "Gerada no Salvia em Ajustes → Central de Integrações → Desenvolvedores.",
|
|
29
|
+
},
|
|
30
|
+
];
|
|
31
|
+
this.authenticate = {
|
|
32
|
+
type: "generic",
|
|
33
|
+
properties: {
|
|
34
|
+
headers: {
|
|
35
|
+
Authorization: "=Bearer {{$credentials.apiKey}}",
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
this.test = {
|
|
40
|
+
request: {
|
|
41
|
+
baseURL: "={{$credentials.baseUrl}}",
|
|
42
|
+
url: "/api/v1/me",
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
exports.SalviaApi = SalviaApi;
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Salvia = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Node declarativo do Salvia CRM. Sem método execute: o roteamento REST fica
|
|
6
|
+
* todo na descrição — menos código, mesma robustez dos nodes oficiais.
|
|
7
|
+
*
|
|
8
|
+
* Operações:
|
|
9
|
+
* Lead → Criar (POST /api/v1/leads)
|
|
10
|
+
*
|
|
11
|
+
* A resposta da API vem em { data: {...} } — o postReceive desembrulha pro
|
|
12
|
+
* item de saída ser o lead direto.
|
|
13
|
+
*/
|
|
14
|
+
class Salvia {
|
|
15
|
+
constructor() {
|
|
16
|
+
this.description = {
|
|
17
|
+
displayName: "Salvia",
|
|
18
|
+
name: "salvia",
|
|
19
|
+
icon: "file:salvia.svg",
|
|
20
|
+
group: ["transform"],
|
|
21
|
+
version: 1,
|
|
22
|
+
subtitle: '={{ $parameter["operation"] + ": " + $parameter["resource"] }}',
|
|
23
|
+
description: "Interage com o Salvia CRM (leads, funil, atendimento)",
|
|
24
|
+
defaults: {
|
|
25
|
+
name: "Salvia",
|
|
26
|
+
},
|
|
27
|
+
// Literal "main" compila em qualquer versão do n8n-workflow (o enum
|
|
28
|
+
// NodeConnectionType virou type-only em versões recentes).
|
|
29
|
+
inputs: ["main"],
|
|
30
|
+
outputs: ["main"],
|
|
31
|
+
usableAsTool: true,
|
|
32
|
+
credentials: [
|
|
33
|
+
{
|
|
34
|
+
name: "salviaApi",
|
|
35
|
+
required: true,
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
requestDefaults: {
|
|
39
|
+
baseURL: "={{ $credentials.baseUrl }}",
|
|
40
|
+
headers: {
|
|
41
|
+
"Content-Type": "application/json",
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
properties: [
|
|
45
|
+
{
|
|
46
|
+
displayName: "Recurso",
|
|
47
|
+
name: "resource",
|
|
48
|
+
type: "options",
|
|
49
|
+
noDataExpression: true,
|
|
50
|
+
options: [{ name: "Lead", value: "lead" }],
|
|
51
|
+
default: "lead",
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
displayName: "Operação",
|
|
55
|
+
name: "operation",
|
|
56
|
+
type: "options",
|
|
57
|
+
noDataExpression: true,
|
|
58
|
+
displayOptions: { show: { resource: ["lead"] } },
|
|
59
|
+
options: [
|
|
60
|
+
{
|
|
61
|
+
name: "Criar",
|
|
62
|
+
value: "create",
|
|
63
|
+
action: "Criar um lead",
|
|
64
|
+
description: "Cria um lead no funil (etapa de entrada do funil padrão, salvo se você indicar outra)",
|
|
65
|
+
routing: {
|
|
66
|
+
request: {
|
|
67
|
+
method: "POST",
|
|
68
|
+
url: "/api/v1/leads",
|
|
69
|
+
},
|
|
70
|
+
output: {
|
|
71
|
+
postReceive: [
|
|
72
|
+
{
|
|
73
|
+
type: "rootProperty",
|
|
74
|
+
properties: { property: "data" },
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
default: "create",
|
|
82
|
+
},
|
|
83
|
+
// ── Campos do Criar Lead ──
|
|
84
|
+
{
|
|
85
|
+
displayName: "Nome",
|
|
86
|
+
name: "name",
|
|
87
|
+
type: "string",
|
|
88
|
+
required: true,
|
|
89
|
+
default: "",
|
|
90
|
+
placeholder: "Maria Souza",
|
|
91
|
+
displayOptions: { show: { resource: ["lead"], operation: ["create"] } },
|
|
92
|
+
routing: { send: { type: "body", property: "name" } },
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
displayName: "Telefone",
|
|
96
|
+
name: "phone",
|
|
97
|
+
type: "string",
|
|
98
|
+
default: "",
|
|
99
|
+
placeholder: "+55 71 99999-9999",
|
|
100
|
+
description: "Com DDD. Aceita formato nacional ou internacional.",
|
|
101
|
+
displayOptions: { show: { resource: ["lead"], operation: ["create"] } },
|
|
102
|
+
routing: { send: { type: "body", property: "phone" } },
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
displayName: "Email",
|
|
106
|
+
name: "email",
|
|
107
|
+
type: "string",
|
|
108
|
+
default: "",
|
|
109
|
+
placeholder: "maria@email.com",
|
|
110
|
+
displayOptions: { show: { resource: ["lead"], operation: ["create"] } },
|
|
111
|
+
routing: { send: { type: "body", property: "email" } },
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
displayName: "Origem",
|
|
115
|
+
name: "origin",
|
|
116
|
+
type: "string",
|
|
117
|
+
default: "",
|
|
118
|
+
placeholder: "instagram-ads",
|
|
119
|
+
description: "De onde o lead veio (aparece na ficha e nas métricas)",
|
|
120
|
+
displayOptions: { show: { resource: ["lead"], operation: ["create"] } },
|
|
121
|
+
routing: { send: { type: "body", property: "origin" } },
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
displayName: "Opções adicionais",
|
|
125
|
+
name: "additionalFields",
|
|
126
|
+
type: "collection",
|
|
127
|
+
placeholder: "Adicionar campo",
|
|
128
|
+
default: {},
|
|
129
|
+
displayOptions: { show: { resource: ["lead"], operation: ["create"] } },
|
|
130
|
+
options: [
|
|
131
|
+
{
|
|
132
|
+
displayName: "Funil (pipelineId)",
|
|
133
|
+
name: "pipelineId",
|
|
134
|
+
type: "string",
|
|
135
|
+
default: "",
|
|
136
|
+
description: "UUID do funil de destino (opcional)",
|
|
137
|
+
routing: { send: { type: "body", property: "pipelineId" } },
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
displayName: "Etapa (stageId)",
|
|
141
|
+
name: "stageId",
|
|
142
|
+
type: "string",
|
|
143
|
+
default: "",
|
|
144
|
+
description: "UUID da etapa de destino (opcional)",
|
|
145
|
+
routing: { send: { type: "body", property: "stageId" } },
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
displayName: "Dono (email do atendente)",
|
|
149
|
+
name: "ownerEmail",
|
|
150
|
+
type: "string",
|
|
151
|
+
default: "",
|
|
152
|
+
description: "Email de um usuário do Salvia que vira dono do lead",
|
|
153
|
+
routing: { send: { type: "body", property: "ownerEmail" } },
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
displayName: "Campos personalizados (JSON)",
|
|
157
|
+
name: "customFields",
|
|
158
|
+
type: "json",
|
|
159
|
+
default: "{}",
|
|
160
|
+
description: 'Ex.: {"convenio": "Unimed", "procedimento": "Botox"}',
|
|
161
|
+
routing: {
|
|
162
|
+
send: {
|
|
163
|
+
type: "body",
|
|
164
|
+
property: "customFields",
|
|
165
|
+
value: "={{ typeof $value === 'string' ? JSON.parse($value || '{}') : $value }}",
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
displayName: "UTM Source",
|
|
171
|
+
name: "utmSource",
|
|
172
|
+
type: "string",
|
|
173
|
+
default: "",
|
|
174
|
+
routing: { send: { type: "body", property: "utmSource" } },
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
displayName: "UTM Medium",
|
|
178
|
+
name: "utmMedium",
|
|
179
|
+
type: "string",
|
|
180
|
+
default: "",
|
|
181
|
+
routing: { send: { type: "body", property: "utmMedium" } },
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
displayName: "UTM Campaign",
|
|
185
|
+
name: "utmCampaign",
|
|
186
|
+
type: "string",
|
|
187
|
+
default: "",
|
|
188
|
+
routing: { send: { type: "body", property: "utmCampaign" } },
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
displayName: "Permitir telefone duplicado",
|
|
192
|
+
name: "forceDuplicate",
|
|
193
|
+
type: "boolean",
|
|
194
|
+
default: false,
|
|
195
|
+
description: "Se desligado (padrão), telefone já cadastrado devolve erro com o ID do lead existente",
|
|
196
|
+
routing: { send: { type: "body", property: "forceDuplicate" } },
|
|
197
|
+
},
|
|
198
|
+
],
|
|
199
|
+
},
|
|
200
|
+
],
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
exports.Salvia = Salvia;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 60 60">
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="g" x1="0" y1="0" x2="1" y2="1">
|
|
4
|
+
<stop offset="0" stop-color="#7C3AED"/>
|
|
5
|
+
<stop offset="1" stop-color="#A855F7"/>
|
|
6
|
+
</linearGradient>
|
|
7
|
+
</defs>
|
|
8
|
+
<rect width="60" height="60" rx="14" fill="#0B1220"/>
|
|
9
|
+
<path d="M30 10c8 6 12 13 12 21 0 8-5 15-12 19-7-4-12-11-12-19 0-8 4-15 12-21z" fill="url(#g)"/>
|
|
10
|
+
<path d="M30 14v32" stroke="#0B1220" stroke-width="2.4" stroke-linecap="round"/>
|
|
11
|
+
<path d="M30 24c-3-1-6-4-7-8M30 32c3-1 6-4 7-8" stroke="#0B1220" stroke-width="2.4" stroke-linecap="round" fill="none"/>
|
|
12
|
+
</svg>
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "n8n-nodes-salvia",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Nodes do Salvia CRM para n8n — crie leads e integre sua clínica aos seus fluxos.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"n8n-community-node-package",
|
|
7
|
+
"salvia",
|
|
8
|
+
"crm",
|
|
9
|
+
"whatsapp"
|
|
10
|
+
],
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"author": "MovMed <pedro@grupomovmed.com.br>",
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "https://github.com/Projetos-Mov/n8n-nodes-salvia.git"
|
|
16
|
+
},
|
|
17
|
+
"main": "index.js",
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsc && node scripts/copy-assets.js"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist"
|
|
23
|
+
],
|
|
24
|
+
"n8n": {
|
|
25
|
+
"n8nNodesApiVersion": 1,
|
|
26
|
+
"credentials": [
|
|
27
|
+
"dist/credentials/SalviaApi.credentials.js"
|
|
28
|
+
],
|
|
29
|
+
"nodes": [
|
|
30
|
+
"dist/nodes/Salvia/Salvia.node.js"
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/node": "^20.14.0",
|
|
35
|
+
"n8n-workflow": "^1.70.0",
|
|
36
|
+
"typescript": "^5.5.0"
|
|
37
|
+
},
|
|
38
|
+
"peerDependencies": {
|
|
39
|
+
"n8n-workflow": "*"
|
|
40
|
+
}
|
|
41
|
+
}
|